更新followship功能

pull/361/head
HXY 2 years ago
commit 5d133a3757

@ -47,7 +47,7 @@ jobs:
name: Test name: Test
strategy: strategy:
matrix: matrix:
go-version: [ 1.20.x ] go-version: [ 1.20.x, 1.21.x ]
platform: [ ubuntu-latest, macos-latest ] platform: [ ubuntu-latest, macos-latest ]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:
@ -66,7 +66,7 @@ jobs:
name: TestOnWindows name: TestOnWindows
strategy: strategy:
matrix: matrix:
go-version: [ 1.20.x ] go-version: [ 1.20.x, 1.21.x ]
platform: [ windows-latest ] platform: [ windows-latest ]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:

5
.gitignore vendored

@ -4,7 +4,10 @@ __debug_bin
!*.example !*.example
/config.yaml /config.yaml
*.log *.log
paopao-ce* /paopao-ce
/paopao
/.env
/.envrc
/release /release
/data /data
/custom /custom

@ -7,6 +7,9 @@
"request": "launch", "request": "launch",
"mode": "exec", "mode": "exec",
"program": "${workspaceFolder}/.vscode/__debug_bin", "program": "${workspaceFolder}/.vscode/__debug_bin",
"args":[
"serve"
],
"preLaunchTask": "go: build (debug)", "preLaunchTask": "go: build (debug)",
"cwd": "${workspaceFolder}" "cwd": "${workspaceFolder}"
} }

@ -7,10 +7,34 @@ All notable changes to paopao-ce are documented in this file.
- use compiler profile-guided optimization (PGO) to further optimize builds. [#327](https://github.com/rocboss/paopao-ce/pull/327) - use compiler profile-guided optimization (PGO) to further optimize builds. [#327](https://github.com/rocboss/paopao-ce/pull/327)
- frontend: re-add stars page embed to profile page. [#339](https://github.com/rocboss/paopao-ce/pull/339) - frontend: re-add stars page embed to profile page. [#339](https://github.com/rocboss/paopao-ce/pull/339)
- simple support for user posts filter by style(post/comment/media/star). [#345](https://github.com/rocboss/paopao-ce/pull/345) - simple support for user posts filter by style(post/comment/media/star). [#345](https://github.com/rocboss/paopao-ce/pull/345)
migration database first(sql ddl file in `scripts/migration/**/*_create_view_post_filter.up.sql`):
```sql
CREATE VIEW p_post_by_media AS SELECT post.*FROM (SELECT DISTINCT post_id FROM p_post_content WHERE (TYPE=3 OR TYPE=4 OR TYPE=7 OR TYPE=8) AND is_del=0) media JOIN p_post post ON media.post_id=post.ID WHERE post.is_del=0;
CREATE VIEW p_post_by_comment AS SELECT P.*,C.user_id comment_user_id FROM (SELECT post_id,user_id FROM p_comment WHERE is_del=0 UNION SELECT post_id,reply.user_id user_id FROM p_comment_reply reply JOIN p_comment COMMENT ON reply.comment_id=COMMENT.ID WHERE reply.is_del=0 AND COMMENT.is_del=0) C JOIN p_post P ON C.post_id=P.ID WHERE P.is_del=0;
```
- add user highlight tweet support include custom tweet set to highlight and list in user/profile page.
- add cli subcommand to start paopao-ce serve or other task. [#354](https://github.com/rocboss/paopao-ce/pull/354)
- add `Friendship` feature . [#355](https://github.com/rocboss/paopao-ce/pull/355)
migration database first(sql ddl file in `scripts/migration/**/*_user_following.up.sql`):
```sql
DROP TABLE IF EXISTS p_following;
CREATE TABLE p_following (ID BIGSERIAL PRIMARY KEY,user_id BIGINT NOT NULL,follow_id BIGINT NOT NULL,is_del SMALLINT NOT NULL DEFAULT 0,created_on BIGINT NOT NULL DEFAULT 0,modified_on BIGINT NOT NULL DEFAULT 0,deleted_on BIGINT NOT NULL DEFAULT 0);
CREATE INDEX idx_following_user_follow ON p_following USING btree (user_id,follow_id);
```
### Changed ### Changed
- change man content width to 600px and optimize tweet/comment/replay text length. [#333](https://github.com/rocboss/paopao-ce/pull/333) - change man content width to 600px and optimize tweet/comment/replay text length. [#333](https://github.com/rocboss/paopao-ce/pull/333)
- optimize embed web ui to paopao execute binary file logic. [#354](https://github.com/rocboss/paopao-ce/pull/354)
```sh
# embed web ui to execute file default
make build
# use slim model to disable embed web ui to exectute file
make build TAGS='slim embed'
```
- frontend: optimize user profile page route path to domain/#/u/?s=username. [&c857142](https://github.com/rocboss/paopao-ce/commit/c857142565f0c28294344c7abc5c2df4e363b04c
- change the `Friendship` feature and `Followship` feature as builtin feature. [#362](https://github.com/rocboss/paopao-ce/pull/362)
- deprecated/remove `Lightship` feature. [#362](https://github.com/rocboss/paopao-ce/pull/362)
## 0.3.1 ## 0.3.1
### Fixed ### Fixed
- fixed: video player assets cdn error. [&caff8c0](https://github.com/rocboss/paopao-ce/commit/caff8c052be6c8d59576011192f830fd98e17ab3 'commit caff8c0') - fixed: video player assets cdn error. [&caff8c0](https://github.com/rocboss/paopao-ce/commit/caff8c052be6c8d59576011192f830fd98e17ab3 'commit caff8c0')

@ -23,6 +23,8 @@ WORKDIR /paopao-ce
COPY . . COPY . .
COPY --from=frontend /web/dist ./web/dist COPY --from=frontend /web/dist ./web/dist
ENV GOPROXY=https://goproxy.cn ENV GOPROXY=https://goproxy.cn
RUN [ $EMBED_UI != yes ] || make build TAGS='go_json'
RUN [ $EMBED_UI = yes ] || make build TAGS='slim embed go_json'
RUN [ $EMBED_UI != no ] || make build TAGS='embed go_json' RUN [ $EMBED_UI != no ] || make build TAGS='embed go_json'
RUN [ $EMBED_UI = no ] || make build TAGS='go_json' RUN [ $EMBED_UI = no ] || make build TAGS='go_json'
@ -34,10 +36,11 @@ ARG USE_DIST=no
ENV TZ=Asia/Shanghai ENV TZ=Asia/Shanghai
WORKDIR /app/paopao-ce WORKDIR /app/paopao-ce
COPY --from=backend /paopao-ce/release/paopao-ce . COPY --from=backend /paopao-ce/release/paopao .
COPY --from=backend /paopao-ce/config.yaml.sample config.yaml COPY --from=backend /paopao-ce/config.yaml.sample config.yaml
VOLUME ["/app/paopao-ce/custom"] VOLUME ["/app/paopao-ce/custom"]
EXPOSE 8008 EXPOSE 8008
HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD ps -ef | grep paopao-ce || exit 1 HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD ps -ef | grep paopao || exit 1
ENTRYPOINT ["/app/paopao-ce/paopao-ce"] ENTRYPOINT ["/app/paopao-ce/paopao"]
CMD ["serve"]

@ -1,6 +1,7 @@
.PHONY: all build run test clean fmt pre-commit help .PHONY: all build build-web run test clean fmt pre-commit help
TARGET = paopao-ce PROJECT = paopao-ce
TARGET = paopao
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
TARGET := $(TARGET).exe TARGET := $(TARGET).exe
endif endif
@ -12,10 +13,10 @@ endif
RELEASE_ROOT = release RELEASE_ROOT = release
RELEASE_FILES = LICENSE README.md CHANGELOG.md config.yaml.sample docker-compose.yaml scripts docs RELEASE_FILES = LICENSE README.md CHANGELOG.md config.yaml.sample docker-compose.yaml scripts docs
RELEASE_LINUX_AMD64 = $(RELEASE_ROOT)/linux-amd64/$(TARGET) RELEASE_LINUX_AMD64 = $(RELEASE_ROOT)/linux-amd64/$(PROJECT)
RELEASE_DARWIN_AMD64 = $(RELEASE_ROOT)/darwin-amd64/$(TARGET) RELEASE_DARWIN_AMD64 = $(RELEASE_ROOT)/darwin-amd64/$(PROJECT)
RELEASE_DARWIN_ARM64 = $(RELEASE_ROOT)/darwin-arm64/$(TARGET) RELEASE_DARWIN_ARM64 = $(RELEASE_ROOT)/darwin-arm64/$(PROJECT)
RELEASE_WINDOWS_AMD64 = $(RELEASE_ROOT)/windows-amd64/$(TARGET) RELEASE_WINDOWS_AMD64 = $(RELEASE_ROOT)/windows-amd64/$(PROJECT)
BUILD_VERSION := $(shell git describe --tags --always | cut -f1 -f2 -d "-") BUILD_VERSION := $(shell git describe --tags --always | cut -f1 -f2 -d "-")
BUILD_DATE := $(shell date +'%Y-%m-%d %H:%M:%S') BUILD_DATE := $(shell date +'%Y-%m-%d %H:%M:%S')
@ -34,8 +35,11 @@ build:
@echo Build paopao-ce @echo Build paopao-ce
@go build -pgo=auto -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $(RELEASE_ROOT)/$(TARGET) @go build -pgo=auto -trimpath -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $(RELEASE_ROOT)/$(TARGET)
build-web:
@cd web && rm -rf dist/* && yarn build && cd -
run: run:
@go run -pgo=auto -trimpath -gcflags "all=-N -l" -tags '$(TAGS)' -ldflags '$(LDFLAGS)' . @go run -pgo=auto -trimpath -gcflags "all=-N -l" -tags '$(TAGS)' -ldflags '$(LDFLAGS)' . serve
.PHONY: release .PHONY: release
release: linux-amd64 darwin-amd64 darwin-arm64 windows-x64 release: linux-amd64 darwin-amd64 darwin-arm64 windows-x64
@ -44,10 +48,10 @@ release: linux-amd64 darwin-amd64 darwin-arm64 windows-x64
@cp -rf $(RELEASE_FILES) $(RELEASE_DARWIN_AMD64) @cp -rf $(RELEASE_FILES) $(RELEASE_DARWIN_AMD64)
@cp -rf $(RELEASE_FILES) $(RELEASE_DARWIN_ARM64) @cp -rf $(RELEASE_FILES) $(RELEASE_DARWIN_ARM64)
@cp -rf $(RELEASE_FILES) $(RELEASE_WINDOWS_AMD64) @cp -rf $(RELEASE_FILES) $(RELEASE_WINDOWS_AMD64)
@cd $(RELEASE_LINUX_AMD64)/.. && rm -f *.zip && zip -r $(TARGET)-linux_amd64.zip $(TARGET) && cd - @cd $(RELEASE_LINUX_AMD64)/.. && rm -f *.zip && zip -r $(PROJECT)-linux_amd64.zip $(PROJECT) && cd -
@cd $(RELEASE_DARWIN_AMD64)/.. && rm -f *.zip && zip -r $(TARGET)-darwin_amd64.zip $(TARGET) && cd - @cd $(RELEASE_DARWIN_AMD64)/.. && rm -f *.zip && zip -r $(PROJECT)-darwin_amd64.zip $(PROJECT) && cd -
@cd $(RELEASE_DARWIN_ARM64)/.. && rm -f *.zip && zip -r $(TARGET)-darwin_arm64.zip $(TARGET) && cd - @cd $(RELEASE_DARWIN_ARM64)/.. && rm -f *.zip && zip -r $(PROJECT)-darwin_arm64.zip $(PROJECT) && cd -
@cd $(RELEASE_WINDOWS_AMD64)/.. && rm -f *.zip && zip -r $(TARGET)-windows_amd64.zip $(TARGET) && cd - @cd $(RELEASE_WINDOWS_AMD64)/.. && rm -f *.zip && zip -r $(PROJECT)-windows_amd64.zip $(PROJECT) && cd -
.PHONY: linux-amd64 .PHONY: linux-amd64
linux-amd64: linux-amd64:

@ -97,11 +97,15 @@ PaoPao主要由以下优秀的开源项目/工具构建
``` ```
编译api服务、内嵌web前端ui: 编译api服务、内嵌web前端ui:
```sh ```sh
make build TAGS='embed' make build
```
也可以使用精简模式编译不内嵌web前端ui:
```sh
make build TAGS='slim embed'
``` ```
编译后在`release`目录可以找到对应可执行文件。 编译后在`release`目录可以找到对应可执行文件。
```sh ```sh
release/paopao-ce release/paopao
``` ```
4. 直接运行后端 4. 直接运行后端
@ -369,9 +373,9 @@ release/paopao-ce --no-default-features --features sqlite3,localoss,loggerfile,r
|`LoggerFile` | 日志 | 稳定 | 使用文件写日志 | |`LoggerFile` | 日志 | 稳定 | 使用文件写日志 |
|`LoggerZinc` | 日志 | 稳定(推荐) | 使用[Zinc](https://github.com/zinclabs/zinc)写日志 | |`LoggerZinc` | 日志 | 稳定(推荐) | 使用[Zinc](https://github.com/zinclabs/zinc)写日志 |
|`LoggerMeili` | 日志 | 内测 | 使用[Meilisearch](https://github.com/meilisearch/meilisearch)写日志 | |`LoggerMeili` | 日志 | 内测 | 使用[Meilisearch](https://github.com/meilisearch/meilisearch)写日志 |
|[`Friendship`](docs/proposal/002-关于Friendship功能项的设计.md) | 关系模式 | 内 | 弱关系好友模式,类似微信朋友圈 | |[`Friendship`](docs/proposal/22110410-关于Friendship功能项的设计.md) | 关系模式 | 内置 Builtin | 弱关系好友模式,类似微信朋友圈 |
|[`Followship`](docs/proposal/003-关于Followship功能项的设计.md) | 关系模式 | WIP | 关注者模式类似Twitter的Follow模式 | |[`Followship`](docs/proposal/22110409-关于Followship功能项的设计.md) | 关系模式 | 内置 Builtin | 关注者模式类似Twitter的Follow模式 |
|[`Lightship`](docs/proposal/011-关于Lightship功能项的设计.md) | 关系模式 | 内测(默认) | 开放模式,所有推文都公开可见 | |[`Lightship`](docs/proposal/22121409-关于Lightship功能项的设计.md) | 关系模式 | 弃用 Deprecated | 开放模式,所有推文都公开可见 |
|`Alipay` | 支付 | 稳定 | 开启基于[支付宝开放平台](https://open.alipay.com/)的钱包功能 | |`Alipay` | 支付 | 稳定 | 开启基于[支付宝开放平台](https://open.alipay.com/)的钱包功能 |
|`Sms` | 短信验证 | 稳定 | 开启短信验证码功能,用于手机绑定验证手机是否注册者的;功能如果没有开启,手机绑定时任意短信验证码都可以绑定手机 | |`Sms` | 短信验证 | 稳定 | 开启短信验证码功能,用于手机绑定验证手机是否注册者的;功能如果没有开启,手机绑定时任意短信验证码都可以绑定手机 |
|`Docs:OpenAPI` | 开发文档 | 稳定 | 开启openapi文档功能提供web api文档说明(visit http://127.0.0.1:8008/docs/openapi) | |`Docs:OpenAPI` | 开发文档 | 稳定 | 开启openapi文档功能提供web api文档说明(visit http://127.0.0.1:8008/docs/openapi) |

@ -3,18 +3,22 @@
## paopao-ce roadmap ## paopao-ce roadmap
#### dev+ #### dev+
* [ ] add `Followship` feature
* [ ] add `Auth:Bcrypt` feature * [ ] add `Auth:Bcrypt` feature
* [ ] add `Auth:MD5` feature (just for compatible) * [ ] add `Auth:MD5` feature (just for compatible)
* [x] add extend base ORM code for implement data logic base sqlx/sqlc
* [ ] optimize media tweet submit logic * [ ] optimize media tweet submit logic
* [ ] optimize search logic service * [ ] optimize search logic service
#### v0.4.0
* [x] add `Followship` feature.
* [x] add extend base ORM code for implement data logic base sqlx/sqlc.
* [x] user/profile page add comment/highlight/media/likes sub-page.
* [x] add tweet highlight feature to enable user set a tweet as highlight.
#### v0.3.0 #### v0.3.0
* [x] remove `Deprecated:OldWeb` feature * [x] remove `Deprecated:OldWeb` feature
* [x] add user topic follow feature support * [x] add user topic follow feature support
* [x] add tweet link share support * [x] add tweet link share support
* [ ] add comment thumbsUp/thumbsDown support * [x] add comment thumbsUp/thumbsDown support
* [x] add `RedisCacheIndex` feature * [x] add `RedisCacheIndex` feature
* [x] add `Sentry` feature * [x] add `Sentry` feature

@ -18,10 +18,10 @@ type Followship interface {
// Chain provide handlers chain for gin // Chain provide handlers chain for gin
Chain() gin.HandlersChain Chain() gin.HandlersChain
ListFollowers(*web.ListFollowersReq) (*web.ListFollowersResp, mir.Error)
ListFollowings(*web.ListFollowingsReq) (*web.ListFollowingsResp, mir.Error) ListFollowings(*web.ListFollowingsReq) (*web.ListFollowingsResp, mir.Error)
DeleteFollowing(*web.DeleteFollowingReq) mir.Error ListFollows(*web.ListFollowsReq) (*web.ListFollowsResp, mir.Error)
AddFollowing(*web.AddFollowingReq) mir.Error UnfollowUser(*web.UnfollowUserReq) mir.Error
FollowUser(*web.FollowUserReq) mir.Error
mustEmbedUnimplementedFollowshipServant() mustEmbedUnimplementedFollowshipServant()
} }
@ -34,59 +34,59 @@ func RegisterFollowshipServant(e *gin.Engine, s Followship) {
router.Use(middlewares...) router.Use(middlewares...)
// register routes info to router // register routes info to router
router.Handle("GET", "/follower/list", func(c *gin.Context) { router.Handle("GET", "/user/followings", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
return return
default: default:
} }
req := new(web.ListFollowersReq) req := new(web.ListFollowingsReq)
if err := s.Bind(c, req); err != nil { if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err) s.Render(c, nil, err)
return return
} }
resp, err := s.ListFollowers(req) resp, err := s.ListFollowings(req)
s.Render(c, resp, err) s.Render(c, resp, err)
}) })
router.Handle("GET", "/following/list", func(c *gin.Context) { router.Handle("GET", "/user/follows", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
return return
default: default:
} }
req := new(web.ListFollowingsReq) req := new(web.ListFollowsReq)
if err := s.Bind(c, req); err != nil { if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err) s.Render(c, nil, err)
return return
} }
resp, err := s.ListFollowings(req) resp, err := s.ListFollows(req)
s.Render(c, resp, err) s.Render(c, resp, err)
}) })
router.Handle("POST", "/following/delete", func(c *gin.Context) { router.Handle("POST", "/user/unfollow", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
return return
default: default:
} }
req := new(web.DeleteFollowingReq) req := new(web.UnfollowUserReq)
if err := s.Bind(c, req); err != nil { if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err) s.Render(c, nil, err)
return return
} }
s.Render(c, nil, s.DeleteFollowing(req)) s.Render(c, nil, s.UnfollowUser(req))
}) })
router.Handle("POST", "/following/add", func(c *gin.Context) { router.Handle("POST", "/user/follow", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
return return
default: default:
} }
req := new(web.AddFollowingReq) req := new(web.FollowUserReq)
if err := s.Bind(c, req); err != nil { if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err) s.Render(c, nil, err)
return return
} }
s.Render(c, nil, s.AddFollowing(req)) s.Render(c, nil, s.FollowUser(req))
}) })
} }
@ -97,19 +97,19 @@ func (UnimplementedFollowshipServant) Chain() gin.HandlersChain {
return nil return nil
} }
func (UnimplementedFollowshipServant) ListFollowers(req *web.ListFollowersReq) (*web.ListFollowersResp, mir.Error) { func (UnimplementedFollowshipServant) ListFollowings(req *web.ListFollowingsReq) (*web.ListFollowingsResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedFollowshipServant) ListFollowings(req *web.ListFollowingsReq) (*web.ListFollowingsResp, mir.Error) { func (UnimplementedFollowshipServant) ListFollows(req *web.ListFollowsReq) (*web.ListFollowsResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedFollowshipServant) DeleteFollowing(req *web.DeleteFollowingReq) mir.Error { func (UnimplementedFollowshipServant) UnfollowUser(req *web.UnfollowUserReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedFollowshipServant) AddFollowing(req *web.AddFollowingReq) mir.Error { func (UnimplementedFollowshipServant) FollowUser(req *web.FollowUserReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
# eg.1 : sh build-image.sh # eg.1 : sh build-image.sh
# eg.2, set tags: sh build-image.sh 'embed go_json' # eg.2, set tags: sh build-image.sh 'go_json'
TAGS='embed go_json' TAGS='go_json'
if [ -n "$1" ]; then if [ -n "$1" ]; then
TAGS="$1" TAGS="$1"

@ -0,0 +1,27 @@
// 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 migrate
import (
"fmt"
"github.com/rocboss/paopao-ce/cmd"
"github.com/spf13/cobra"
)
func init() {
migrateCmd := &cobra.Command{
Use: "migrate",
Short: "migrate database data",
Long: "miegrate database data when paopao-ce upgrade",
Run: migrateRun,
}
cmd.Register(migrateCmd)
}
func migrateRun(_cmd *cobra.Command, _args []string) {
// TODO: add some logic for migrate cmd feature
fmt.Println("sorry, this feature is not implemented yet.")
}

@ -0,0 +1,36 @@
// 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 cmd
import (
"github.com/spf13/cobra"
)
var (
rootCmd = &cobra.Command{
Use: "paopao",
Short: `an artistic "twitter like" community`,
Long: `an artistic "twitter like" community`,
}
)
// Setup set root command name,short-describe, long-describe
// return &cobra.Command to custom other options
func Setup(use, short, long string) *cobra.Command {
rootCmd.Use = use
rootCmd.Short = short
rootCmd.Long = long
return rootCmd
}
// Register add sub-command
func Register(cmd *cobra.Command) {
rootCmd.AddCommand(cmd)
}
// Execute start application
func Execute() {
rootCmd.Execute()
}

@ -0,0 +1,94 @@
// 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 serve
import (
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/alimy/cfg"
"github.com/fatih/color"
"github.com/getsentry/sentry-go"
"github.com/rocboss/paopao-ce/cmd"
"github.com/rocboss/paopao-ce/internal"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/service"
"github.com/rocboss/paopao-ce/pkg/debug"
"github.com/rocboss/paopao-ce/pkg/utils"
"github.com/rocboss/paopao-ce/pkg/version"
"github.com/sourcegraph/conc"
"github.com/spf13/cobra"
"go.uber.org/automaxprocs/maxprocs"
)
var (
noDefaultFeatures bool
features []string
)
func init() {
serveCmd := &cobra.Command{
Use: "serve",
Short: "start paopao-ce server",
Long: "start paopao-ce server",
Run: serveRun,
}
serveCmd.Flags().BoolVar(&noDefaultFeatures, "no-default-features", false, "whether not use default features")
serveCmd.Flags().StringSliceVarP(&features, "features", "f", []string{}, "use special features")
cmd.Register(serveCmd)
}
func deferFn() {
if cfg.If("Sentry") {
// Flush buffered events before the program terminates.
sentry.Flush(2 * time.Second)
}
}
func serveRun(_cmd *cobra.Command, _args []string) {
utils.PrintHelloBanner(version.VersionInfo())
// set maxprocs automatic
maxprocs.Set(maxprocs.Logger(log.Printf))
// initial configure
conf.Initial(features, noDefaultFeatures)
internal.Initial()
ss := service.MustInitService()
if len(ss) < 1 {
fmt.Fprintln(color.Output, "no service need start so just exit")
return
}
// do defer function
defer deferFn()
// start pyroscope if need
debug.StartPyroscope()
// start services
wg := conc.NewWaitGroup()
fmt.Fprintf(color.Output, "\nstarting run service...\n\n")
service.Start(wg)
// graceful stop services
wg.Go(func() {
quit := make(chan os.Signal, 1)
// kill (no param) default send syscall.SIGTERM
// kill -2 is syscall.SIGINT
// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
fmt.Fprintf(color.Output, "\nshutting down server...\n\n")
service.Stop()
})
wg.Wait()
}

@ -0,0 +1,25 @@
// 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 cmd
import (
"github.com/rocboss/paopao-ce/pkg/utils"
"github.com/rocboss/paopao-ce/pkg/version"
"github.com/spf13/cobra"
)
func init() {
versionCmd := &cobra.Command{
Use: "version",
Short: "show version information",
Long: "show version information",
Run: versionRun,
}
Register(versionCmd)
}
func versionRun(_cmd *cobra.Command, _args []string) {
utils.PrintHelloBanner(version.VersionInfo())
}

@ -12,7 +12,7 @@ Server: # 服务设置
ReadTimeout: 60 ReadTimeout: 60
WriteTimeout: 60 WriteTimeout: 60
Features: Features:
Default: ["Web", "Frontend:EmbedWeb", "Zinc", "LocalOSS", "MySQL", "BigCacheIndex", "LoggerZinc", "Friendship"] Default: ["Web", "Frontend:EmbedWeb", "Meili", "LocalOSS", "MySQL", "BigCacheIndex", "LoggerFile"]
Develop: ["Base", "MySQL", "BigCacheIndex", "Meili", "Sms", "AliOSS", "LoggerMeili", "OSS:Retention"] Develop: ["Base", "MySQL", "BigCacheIndex", "Meili", "Sms", "AliOSS", "LoggerMeili", "OSS:Retention"]
Demo: ["Base", "MySQL", "Option", "Zinc", "Sms", "MinIO", "LoggerZinc", "Migration"] Demo: ["Base", "MySQL", "Option", "Zinc", "Sms", "MinIO", "LoggerZinc", "Migration"]
Slim: ["Base", "Sqlite3", "LocalOSS", "LoggerFile", "OSS:TempDir"] Slim: ["Base", "Sqlite3", "LocalOSS", "LoggerFile", "OSS:TempDir"]

@ -41,7 +41,7 @@ services:
# - paopao-network # - paopao-network
redis: redis:
image: redis/redis-stack:7.0.6-RC8 image: redis/redis-stack:7.2.0-RC3
restart: always restart: always
ports: ports:
- 6379:6379 - 6379:6379
@ -51,33 +51,33 @@ services:
networks: networks:
- paopao-network - paopao-network
zinc: # zinc:
image: public.ecr.aws/zinclabs/zinc:latest # image: bitbus/zincsearch:latest
user: root # user: zincsearch
restart: always
ports:
- 4080:4080
volumes:
- ./custom/data/zinc/data:/data
environment:
ZINC_FIRST_ADMIN_USER: admin
ZINC_FIRST_ADMIN_PASSWORD: admin
DATA_PATH: /data
networks:
- paopao-network
# meili:
# image: getmeili/meilisearch:v1.2
# restart: always # restart: always
# ports: # ports:
# - 7700:7700 # - 4080:4080
# volumes: # volumes:
# - ./custom/data/meili/data:/meili_data # - ./custom/data/zinc/data:/data
# environment: # environment:
# - MEILI_MASTER_KEY=paopao-meilisearch # ZINC_FIRST_ADMIN_USER: admin
# ZINC_FIRST_ADMIN_PASSWORD: admin
# DATA_PATH: /data
# networks: # networks:
# - paopao-network # - paopao-network
meili:
image: getmeili/meilisearch:v1.3
restart: always
ports:
- 7700:7700
volumes:
- ./custom/data/meili/data:/meili_data
environment:
- MEILI_MASTER_KEY=paopao-meilisearch
networks:
- paopao-network
# pyroscope: # pyroscope:
# image: pyroscope/pyroscope:latest # image: pyroscope/pyroscope:latest
# restart: always # restart: always
@ -102,12 +102,12 @@ services:
- paopao-network - paopao-network
backend: backend:
image: bitbus/paopao-ce:0.3 image: bitbus/paopao-ce:0.4
restart: always restart: always
depends_on: depends_on:
- db - db
- redis - redis
- zinc - meili
# modify below to reflect your custom configure # modify below to reflect your custom configure
volumes: volumes:
- ./config.yaml.sample:/app/paopao-ce/config.yaml - ./config.yaml.sample:/app/paopao-ce/config.yaml

@ -1,28 +0,0 @@
| 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 |
| ----- | ----- | ----- | ----- | ----- | ----- |
| 010| 北野 | 2022-12-10 | 2022-12-10 | v0.0 | 提议 |
### 关于Sqlx功能项的设计
---- 这里写简要介绍 ----
### 场景
---- 这里描述在什么使用场景下会需要本提按 ----
### 需求
TODO-TL;DR...
### 方案
TODO
### 疑问
1. 如何开启这个功能?
TODO
### 更新记录
#### v0.0(2022-12-10) - 北野
* 初始文档, 先占个位置

@ -1,6 +1,6 @@
| 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 | | 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 |
| ----- | ----- | ----- | ----- | ----- | ----- | | ----- | ----- | ----- | ----- | ----- | ----- |
| 22110409| 北野 | 2022-11-04 | 2022-11-21 | v0.1 | 提议 | | 22110409| 北野 | 2022-11-04 | 2023-08-16 | v1.0 | 提议 |
### 关于Followship功能项的设计 ### 关于Followship功能项的设计
Followship是实现类似Twitter Timeline模式**关注者模型**的时间线信息流广场推文列表的生成将主要与推文时间、用户的关注者相关。Twitter的推文消息流是非常智能的用户体验也非常好这得益于其背后的智能推荐算法以及完善的关注者模型体系当然还有很多其他机制共同作用下的结果。本提按作为一个总纲为paopao-ce引入类似的机制这将是一个持续完善的缓慢过程一切都是为了用户体验用户就是上帝用户需要什么paopao-ce就努力提供什么 Followship是实现类似Twitter Timeline模式**关注者模型**的时间线信息流广场推文列表的生成将主要与推文时间、用户的关注者相关。Twitter的推文消息流是非常智能的用户体验也非常好这得益于其背后的智能推荐算法以及完善的关注者模型体系当然还有很多其他机制共同作用下的结果。本提按作为一个总纲为paopao-ce引入类似的机制这将是一个持续完善的缓慢过程一切都是为了用户体验用户就是上帝用户需要什么paopao-ce就努力提供什么
@ -35,6 +35,12 @@
#### 方案二 #### 方案二
在方案一的基础上通过引入 *图数据库* 实现可选需求。待研究、设计~ 在方案一的基础上通过引入 *图数据库* 实现可选需求。待研究、设计~
#### 设计细节
* 参考实现(PR):
[add Followship feature #355](https://github.com/rocboss/paopao-ce/pull/355)
#### 状态:
内置 Builtin
### 疑问 ### 疑问
@ -42,19 +48,17 @@
理论上这两个功能项是可以共存的如果设置成共存就需要同时提供这两个机制的UI交互同时广场推文列表的生成机制也需要做相应适配可能会比较复杂。前期开发将把这两个功能设置为互斥的即**用户关系模型**只能设置为其中之一,待两个功能项都趋于稳定后,再测试这两个功能项共存后的用户体验,如果效果还不错就引入共存机制。 理论上这两个功能项是可以共存的如果设置成共存就需要同时提供这两个机制的UI交互同时广场推文列表的生成机制也需要做相应适配可能会比较复杂。前期开发将把这两个功能设置为互斥的即**用户关系模型**只能设置为其中之一,待两个功能项都趋于稳定后,再测试这两个功能项共存后的用户体验,如果效果还不错就引入共存机制。
1. 如何开启这个功能? 1. 如何开启这个功能?
在配置文件config.yaml中的`Features`中添加`Followship`功能项开启该功能: 内置 Builtin
```yaml
...
# features中加上 Followship
Features:
Default: ["Meili", "LoggerMeili", "Base", "Sqlite3", "BigCacheIndex", "MinIO", "Followship"]
Base: ["Redis", "PhoneBind"]
...
```
### 更新记录 ### 更新记录
#### v0.0(2022-11-04) - 北野 #### v0.0(2022-11-04) - 北野
* 初始文档, 先占个位置; * 初始文档, 先占个位置;
#### v0.1(2022-11-21) - 北野 #### v0.1(2022-11-21) - 北野
* 添加初始内容; * 添加初始内容;
#### v1.0(2023-08-14) - 北野
* 添加参考实现;
#### v1.1(2023-08-16) - 北野
* 添加状态信息;

@ -1,6 +1,6 @@
| 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 | | 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 |
| ----- | ----- | ----- | ----- | ----- | ----- | | ----- | ----- | ----- | ----- | ----- | ----- |
| 22110410 | 北野 | 2022-11-04 | 2023-01-04 | v1.0 | 提议 | | 22110410 | 北野 | 2022-11-04 | 2023-08-16 | v1.1 | 提议 |
### Friendship功能项的设计概要 ### Friendship功能项的设计概要
Friendship功能提供好友间分享推文信息的机制更好的帮助用户建立自己的推文分享小圈子。Friendship本质上想优化的是泡泡广场页面推文列表的生成机制开启功能后推文列表只能获取 `公开/私密/好友` 的推文,每个用户都有属于自己的个性化推文列表。在提供个性化推文列表生成机制的同时,好友体系的建立也顺便帮助用户建立自己的个性化有限范围内的灵魂社交小圈子,只有相互间拥有个性化认同感的用户才能互为好友。 Friendship功能提供好友间分享推文信息的机制更好的帮助用户建立自己的推文分享小圈子。Friendship本质上想优化的是泡泡广场页面推文列表的生成机制开启功能后推文列表只能获取 `公开/私密/好友` 的推文,每个用户都有属于自己的个性化推文列表。在提供个性化推文列表生成机制的同时,好友体系的建立也顺便帮助用户建立自己的个性化有限范围内的灵魂社交小圈子,只有相互间拥有个性化认同感的用户才能互为好友。
@ -30,6 +30,9 @@ Friendship功能提供好友间分享推文信息的机制更好的帮助用
* 参考实现(PR): * 参考实现(PR):
[add support Friendship feature #192](https://github.com/rocboss/paopao-ce/pull/192) [add support Friendship feature #192](https://github.com/rocboss/paopao-ce/pull/192)
#### 状态:
内置 Builtin
* 预览 * 预览
| | | |
@ -46,15 +49,7 @@ Friendship功能提供好友间分享推文信息的机制更好的帮助用
2. 如何形成这种好友体系? 2. 如何形成这种好友体系?
形成好友体系分 **建立、维持、解除** 好友关系。Friendship提供 *建立/解除* 好友关系的机制,泡泡广场的推文列表依据这个好友体系为每个用户生成个性化推文列表。而好友关系的**维持**本质上就是用户推文的持久更新、思想的持续演化使得好友对你一直保持兴趣Friendship也为每一条推文的访问权限进行**标记(私密/好友可见)**,这可以传达这样一种信息: **“时刻让好友知道我非常在乎好友、对好友特殊关照,你看这条推文就是只有我的好友(也就是你)才可以看到,够意思吧”!** 顺便一说,每一条推文的访问权限标记(公开/私密/好友可见)是建立Friendship弱关系体系的隐性催化剂可以加速Friendship的形成。 形成好友体系分 **建立、维持、解除** 好友关系。Friendship提供 *建立/解除* 好友关系的机制,泡泡广场的推文列表依据这个好友体系为每个用户生成个性化推文列表。而好友关系的**维持**本质上就是用户推文的持久更新、思想的持续演化使得好友对你一直保持兴趣Friendship也为每一条推文的访问权限进行**标记(私密/好友可见)**,这可以传达这样一种信息: **“时刻让好友知道我非常在乎好友、对好友特殊关照,你看这条推文就是只有我的好友(也就是你)才可以看到,够意思吧”!** 顺便一说,每一条推文的访问权限标记(公开/私密/好友可见)是建立Friendship弱关系体系的隐性催化剂可以加速Friendship的形成。
3. 如何开启这个功能? 3. 如何开启这个功能?
在配置文件config.yaml中的`Features`中添加`Friendship`功能项开启该功能: 内置 Builtin
```yaml
...
# features中加上 Friendship
Features:
Default: ["Meili", "LoggerMeili", "Base", "Sqlite3", "BigCacheIndex", "MinIO", "Friendship"]
Base: ["Redis", "PhoneBind"]
...
```
### 更新记录 ### 更新记录
#### v0.1(2022-11-04) - 北野 #### v0.1(2022-11-04) - 北野
@ -65,3 +60,6 @@ Friendship功能提供好友间分享推文信息的机制更好的帮助用
#### v1.0(2023-01-04) - 北野 #### v1.0(2023-01-04) - 北野
* 添加参考实现PR信息 * 添加参考实现PR信息
#### v1.1(2023-08-16) - 北野
* 添加状态信息;

@ -1,9 +1,9 @@
| 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 | | 编号 | 作者 | 发表时间 | 变更时间 | 版本 | 状态 |
| ----- | ----- | ----- | ----- | ----- | ----- | | ----- | ----- | ----- | ----- | ----- | ----- |
| 22121409 | 北野 | 2022-12-14 | 2022-01-09 | v1.1 | 提议 | | 22121409 | 北野 | 2022-12-14 | 2023-08-16 | v1.2 | 提议 |
### 关于Lightship功能项的设计 ### 关于Lightship功能项的设计
Lightship(开放模式)功能提供完全公开的推文分享服务,有别于[Friendship](002-关于Friendship功能项的设计.md "关于Friendship功能项的设计")、[Followship](003-关于Followship功能项的设计.md "关于Followship功能项的设计")使用Lightship用户模式部署paopao-ce用户发布的所有推文都是公开可访问的广场推文列表展示的是全站所有公开推文的Timeline Tweets。 Lightship(开放模式)功能提供完全公开的推文分享服务,有别于[Friendship](22110410-关于Friendship功能项的设计.md "关于Friendship功能项的设计")、[Followship](22110410-关于Followship功能项的设计.md "关于Followship功能项的设计")使用Lightship用户模式部署paopao-ce用户发布的所有推文都是公开可访问的广场推文列表展示的是全站所有公开推文的Timeline Tweets。
### 场景 ### 场景
一般用于非常小的站点,或者推文更新不频繁的站点。 一般用于非常小的站点,或者推文更新不频繁的站点。
@ -24,6 +24,9 @@ Lightship(开放模式)功能提供完全公开的推文分享服务,有别于
#### 参考实现(PR): #### 参考实现(PR):
[add Lightship feature support #198](https://github.com/rocboss/paopao-ce/pull/198) [add Lightship feature support #198](https://github.com/rocboss/paopao-ce/pull/198)
#### 状态:
弃用 Deprecated
### 疑问 ### 疑问
1. 公开模式为什么命名为Lightship 1. 公开模式为什么命名为Lightship
@ -45,3 +48,6 @@ Features:
#### v1.1(2022-01-09) - 北野 #### v1.1(2022-01-09) - 北野
* 添加参考实现PR信息 * 添加参考实现PR信息
#### v1.2(2023-08-16) - 北野
* 添加状态信息

@ -145,15 +145,15 @@
* [x] 业务逻辑实现 * [x] 业务逻辑实现
#### 关系模式: #### 关系模式:
* `Friendship` 弱关系好友模式,类似微信朋友圈(目前状态: 内); * `Friendship` 弱关系好友模式,类似微信朋友圈(目前状态: 内置Builtin);
* [x] [提按文档](docs/proposal/22110410-关于Friendship功能项的设计.md) * [x] [提按文档](docs/proposal/22110410-关于Friendship功能项的设计.md)
* [x] 接口定义 * [x] 接口定义
* [x] 业务逻辑实现 * [x] 业务逻辑实现
* `Followship` 关注者模式类似Twitter的Follow模式(目前状态: WIP); * `Followship` 关注者模式类似Twitter的Follow模式(目前状态: 内置Builtin);
* [ ] [提按文档](docs/proposal/22110409-关于Followship功能项的设计.md) * [ ] [提按文档](docs/proposal/22110409-关于Followship功能项的设计.md)
* [ ] 接口定义 * [ ] 接口定义
* [ ] 业务逻辑实现 * [ ] 业务逻辑实现
* `Lightship` 开放模式,所有推文都公开可见(目前状态: 内测、默认); * `Lightship` 开放模式,所有推文都公开可见(目前状态: 弃用Deprecated);
* [x] [提按文档](docs/proposal/22121409-关于Lightship功能项的设计.md) * [x] [提按文档](docs/proposal/22121409-关于Lightship功能项的设计.md)
* [x] 接口定义 * [x] 接口定义
* [x] 业务逻辑实现 * [x] 业务逻辑实现

@ -7,10 +7,10 @@ require (
github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868
github.com/alimy/cfg v0.4.0 github.com/alimy/cfg v0.4.0
github.com/alimy/mir/v4 v4.0.0 github.com/alimy/mir/v4 v4.0.0
github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible
github.com/allegro/bigcache/v3 v3.1.0 github.com/allegro/bigcache/v3 v3.1.0
github.com/bufbuild/connect-go v1.9.0 github.com/bufbuild/connect-go v1.10.0
github.com/bytedance/sonic v1.9.2 github.com/bytedance/sonic v1.10.0
github.com/cockroachdb/errors v1.10.0 github.com/cockroachdb/errors v1.10.0
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/fatih/color v1.15.0 github.com/fatih/color v1.15.0
@ -28,31 +28,33 @@ require (
github.com/minio/minio-go/v7 v7.0.61 github.com/minio/minio-go/v7 v7.0.61
github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/ginkgo/v2 v2.11.0
github.com/onsi/gomega v1.27.10 github.com/onsi/gomega v1.27.10
github.com/pyroscope-io/client v0.7.1 github.com/pyroscope-io/client v0.7.2
github.com/redis/rueidis v1.0.14 github.com/redis/rueidis v1.0.15
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/smartwalle/alipay/v3 v3.2.14 github.com/smartwalle/alipay/v3 v3.2.15
github.com/sourcegraph/conc v0.3.0 github.com/sourcegraph/conc v0.3.0
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.16.0 github.com/spf13/viper v1.16.0
github.com/tencentyun/cos-go-sdk-v5 v0.7.42 github.com/tencentyun/cos-go-sdk-v5 v0.7.42
github.com/yinheli/mahonia v0.0.0-20131226213531-0eef680515cc github.com/yinheli/mahonia v0.0.0-20131226213531-0eef680515cc
go.uber.org/automaxprocs v1.5.3 go.uber.org/automaxprocs v1.5.3
google.golang.org/grpc v1.56.2 google.golang.org/grpc v1.57.0
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/resty.v1 v1.12.0 gopkg.in/resty.v1 v1.12.0
gorm.io/driver/mysql v1.5.1 gorm.io/driver/mysql v1.5.1
gorm.io/driver/postgres v1.5.2 gorm.io/driver/postgres v1.5.2
gorm.io/driver/sqlite v1.5.2 gorm.io/driver/sqlite v1.5.2
gorm.io/gorm v1.25.2 gorm.io/gorm v1.25.3
gorm.io/plugin/dbresolver v1.4.1 gorm.io/plugin/dbresolver v1.4.4
gorm.io/plugin/soft_delete v1.2.1 gorm.io/plugin/soft_delete v1.2.1
modernc.org/sqlite v1.25.0 modernc.org/sqlite v1.25.0
) )
require ( require (
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/clbanning/mxj v1.8.4 // indirect github.com/clbanning/mxj v1.8.4 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/redact v1.1.5 // indirect
@ -76,6 +78,7 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jackc/pgx/v5 v5.3.1 // indirect
@ -102,7 +105,7 @@ require (
github.com/mozillazg/go-httpheader v0.2.1 // indirect github.com/mozillazg/go-httpheader v0.2.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pyroscope-io/godeltaprof v0.1.0 // indirect github.com/pyroscope-io/godeltaprof v0.1.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/rs/xid v1.5.0 // indirect github.com/rs/xid v1.5.0 // indirect
@ -128,7 +131,7 @@ require (
golang.org/x/text v0.11.0 // indirect golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.3 // indirect golang.org/x/tools v0.9.3 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect

@ -127,8 +127,8 @@ github.com/alimy/cfg v0.4.0 h1:SslKPndmxRViT1ePWLmNsEq7okYP0GVeuowQlRWZPkw=
github.com/alimy/cfg v0.4.0/go.mod h1:rOxbasTH2srl6StAjNF5Vyi8bfrdkl3fLGmOYtSw81c= github.com/alimy/cfg v0.4.0/go.mod h1:rOxbasTH2srl6StAjNF5Vyi8bfrdkl3fLGmOYtSw81c=
github.com/alimy/mir/v4 v4.0.0 h1:MzGfmoLjjvR69jbZEmpKJO3tUuqB0RGRv1UWPbtukBg= github.com/alimy/mir/v4 v4.0.0 h1:MzGfmoLjjvR69jbZEmpKJO3tUuqB0RGRv1UWPbtukBg=
github.com/alimy/mir/v4 v4.0.0/go.mod h1:d58dBvw2KImcVbAUANrciEV/of0arMNsI9c/5UNCMMc= github.com/alimy/mir/v4 v4.0.0/go.mod h1:d58dBvw2KImcVbAUANrciEV/of0arMNsI9c/5UNCMMc=
github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible h1:KpbJFXwhVeuxNtBJ74MCGbIoaBok2uZvkD7QXp2+Wis= github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible h1:6JF1bjhT0WN2srEmijfOFtVWwV91KZ6dJY1/JbdtGrI=
github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk= github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I= github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
@ -186,16 +186,17 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bufbuild/connect-go v1.9.0 h1:JIgAeNuFpo+SUPfU19Yt5TcWlznsN5Bv10/gI/6Pjoc= github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg=
github.com/bufbuild/connect-go v1.9.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk=
github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -209,8 +210,11 @@ github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOo
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -363,6 +367,7 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -740,6 +745,8 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
@ -849,6 +856,7 @@ github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -1105,12 +1113,12 @@ github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/pyroscope-io/client v0.7.1 h1:yFRhj3vbgjBxehvxQmedmUWJQ4CAfCHhn+itPsuWsHw= github.com/pyroscope-io/client v0.7.2 h1:OX2qdUQsS8RSkn/3C8isD7f/P0YiZQlRbAlecAaj/R8=
github.com/pyroscope-io/client v0.7.1/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU= github.com/pyroscope-io/client v0.7.2/go.mod h1:FEocnjn+Ngzxy6EtU9ZxXWRvQ0+pffkrBxHLnPpxwi8=
github.com/pyroscope-io/godeltaprof v0.1.0 h1:UBqtjt0yZi4jTxqZmLAs34XG6ycS3vUTlhEUSq4NHLE= github.com/pyroscope-io/godeltaprof v0.1.2 h1:MdlEmYELd5w+lvIzmZvXGNMVzW2Qc9jDMuJaPOR75g4=
github.com/pyroscope-io/godeltaprof v0.1.0/go.mod h1:psMITXp90+8pFenXkKIpNhrfmI9saQnPbba27VIaiQE= github.com/pyroscope-io/godeltaprof v0.1.2/go.mod h1:psMITXp90+8pFenXkKIpNhrfmI9saQnPbba27VIaiQE=
github.com/redis/rueidis v1.0.14 h1:qdFZahk1F/2L+sZeOECx5E2N5J4Qc51b7ezSUpQXJfs= github.com/redis/rueidis v1.0.15 h1:KjTaoP4ab6lpxyCwgIEZ3/rqvKfKnbICe83tVaaItxQ=
github.com/redis/rueidis v1.0.14/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo= github.com/redis/rueidis v1.0.15/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
@ -1130,6 +1138,7 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
@ -1155,8 +1164,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartwalle/alipay/v3 v3.2.14 h1:X7IPMzweYXjxO+30G9amEjCogzpoA/K1GZpVjM1keps= github.com/smartwalle/alipay/v3 v3.2.15 h1:3fvFJnINKKAOXHR/Iv20k1Z7KJ+nOh3oK214lELPqG8=
github.com/smartwalle/alipay/v3 v3.2.14/go.mod h1:niTNB609KyUYuAx9Bex/MawEjv2yPx4XOjxSAkqmGjE= github.com/smartwalle/alipay/v3 v3.2.15/go.mod h1:niTNB609KyUYuAx9Bex/MawEjv2yPx4XOjxSAkqmGjE=
github.com/smartwalle/ncrypto v1.0.2 h1:pTAhCqtPCMhpOwFXX+EcMdR6PNzruBNoGQrN2S1GbGI= github.com/smartwalle/ncrypto v1.0.2 h1:pTAhCqtPCMhpOwFXX+EcMdR6PNzruBNoGQrN2S1GbGI=
github.com/smartwalle/ncrypto v1.0.2/go.mod h1:Dwlp6sfeNaPMnOxMNayMTacvC5JGEVln3CVdiVDgbBk= github.com/smartwalle/ncrypto v1.0.2/go.mod h1:Dwlp6sfeNaPMnOxMNayMTacvC5JGEVln3CVdiVDgbBk=
github.com/smartwalle/ngx v1.0.6 h1:JPNqNOIj+2nxxFtrSkJO+vKJfeNUSEQueck/Wworjps= github.com/smartwalle/ngx v1.0.6 h1:JPNqNOIj+2nxxFtrSkJO+vKJfeNUSEQueck/Wworjps=
@ -1185,6 +1194,8 @@ github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKv
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@ -1891,8 +1902,8 @@ google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@ -1926,8 +1937,8 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -2001,12 +2012,12 @@ gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.23.0/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.0/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/plugin/dbresolver v1.4.1 h1:Ug4LcoPhrvqq71UhxtF346f+skTYoCa/nEsdjvHwEzk= gorm.io/gorm v1.25.3 h1:zi4rHZj1anhZS2EuEODMhDisGy+Daq9jtPrNGgbQYD8=
gorm.io/plugin/dbresolver v1.4.1/go.mod h1:CTbCtMWhsjXSiJqiW2R8POvJ2cq18RVOl4WGyT5nhNc= gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/plugin/dbresolver v1.4.4 h1:Dtpr/jSVy48f+BnkPwdoHTLaxcE977wJ7QPt7fxI5Hs=
gorm.io/plugin/dbresolver v1.4.4/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0=
gorm.io/plugin/soft_delete v1.2.1 h1:qx9D/c4Xu6w5KT8LviX8DgLcB9hkKl6JC9f44Tj7cGU= gorm.io/plugin/soft_delete v1.2.1 h1:qx9D/c4Xu6w5KT8LviX8DgLcB9hkKl6JC9f44Tj7cGU=
gorm.io/plugin/soft_delete v1.2.1/go.mod h1:Zv7vQctOJTGOsJ/bWgrN1n3od0GBAZgnLjEx+cApLGk= gorm.io/plugin/soft_delete v1.2.1/go.mod h1:Zv7vQctOJTGOsJ/bWgrN1n3od0GBAZgnLjEx+cApLGk=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
@ -2113,6 +2124,7 @@ modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfp
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4= modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

@ -25,10 +25,13 @@ const (
TableComment = "comment" TableComment = "comment"
TableCommentContent = "comment_content" TableCommentContent = "comment_content"
TableCommentReply = "comment_reply" TableCommentReply = "comment_reply"
TableFollowing = "following"
TableContact = "contact" TableContact = "contact"
TableContactGroup = "contact_group" TableContactGroup = "contact_group"
TableMessage = "message" TableMessage = "message"
TablePost = "post" TablePost = "post"
TablePostByComment = "post_by_comment"
TablePostByMedia = "post_by_media"
TablePostAttachmentBill = "post_attachment_bill" TablePostAttachmentBill = "post_attachment_bill"
TablePostCollection = "post_collection" TablePostCollection = "post_collection"
TablePostContent = "post_content" TablePostContent = "post_content"

@ -305,10 +305,13 @@ func (s *databaseConf) TableNames() (res TableNameMap) {
TableComment, TableComment,
TableCommentContent, TableCommentContent,
TableCommentReply, TableCommentReply,
TableFollowing,
TableContact, TableContact,
TableContactGroup, TableContactGroup,
TableMessage, TableMessage,
TablePost, TablePost,
TablePostByComment,
TablePostByMedia,
TablePostAttachmentBill, TablePostAttachmentBill,
TablePostCollection, TablePostCollection,
TablePostContent, TablePostContent,

@ -30,6 +30,7 @@ type DataService interface {
// 用户服务 // 用户服务
UserManageService UserManageService
ContactManageService ContactManageService
FollowingManageService
// 安全服务 // 安全服务
SecurityService SecurityService

@ -4,4 +4,5 @@
// Package cs contain core data service interface type // Package cs contain core data service interface type
// model define // model define
package cs package cs

@ -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 cs
import "errors"
// internal core error variable for data logic implement.
var (
ErrNotImplemented = errors.New("not implemented")
ErrNoPermission = errors.New("no permission")
)

@ -4,9 +4,28 @@
package cs package cs
const (
RelationUnknow RelationTyp = iota
RelationSelf
RelationFriend
RelationFollower
RelationFollowing
RelationAdmin
RelationGuest
)
type ( type (
// UserInfoList 用户信息列表 // UserInfoList 用户信息列表
UserInfoList []*UserInfo UserInfoList []*UserInfo
//
RelationTyp uint8
VistUser struct {
Username string
UserId int64
RelTyp RelationTyp
}
) )
// UserInfo 用户基本信息 // UserInfo 用户基本信息
@ -18,3 +37,22 @@ type UserInfo struct {
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
IsAdmin bool `json:"is_admin"` IsAdmin bool `json:"is_admin"`
} }
func (t RelationTyp) String() string {
switch t {
case RelationSelf:
return "self"
case RelationFriend:
return "friend"
case RelationFollower:
return "follower"
case RelationFollowing:
return "following"
case RelationAdmin:
return "admin"
case RelationUnknow:
fallthrough
default:
return "unknow relation"
}
}

@ -7,10 +7,11 @@ package ms
type ( type (
ContactItem struct { ContactItem struct {
UserId int64 `json:"user_id"` UserId int64 `json:"user_id"`
UserName string `db:"username" json:"username"` Username string `db:"username" json:"username"`
Nickname string `json:"nickname"` Nickname string `json:"nickname"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
Phone string `json:"phone"` Phone string `json:"phone,omitempty"`
IsFollow bool `json:"is_follow,omitempty"`
} }
ContactList struct { ContactList struct {

@ -15,7 +15,7 @@ type TweetService interface {
GetPosts(conditions ms.ConditionsT, offset, limit int) ([]*ms.Post, error) GetPosts(conditions ms.ConditionsT, offset, limit int) ([]*ms.Post, error)
GetPostCount(conditions ms.ConditionsT) (int64, error) GetPostCount(conditions ms.ConditionsT) (int64, error)
GetUserPostStar(postID, userID int64) (*ms.PostStar, error) GetUserPostStar(postID, userID int64) (*ms.PostStar, error)
GetUserPostStars(userID int64, offset, limit int) ([]*ms.PostStar, error) GetUserPostStars(userID int64, limit int, offset int) ([]*ms.PostStar, error)
GetUserPostStarCount(userID int64) (int64, error) GetUserPostStarCount(userID int64) (int64, error)
GetUserPostCollection(postID, userID int64) (*ms.PostCollection, error) GetUserPostCollection(postID, userID int64) (*ms.PostCollection, error)
GetUserPostCollections(userID int64, offset, limit int) ([]*ms.PostCollection, error) GetUserPostCollections(userID int64, offset, limit int) ([]*ms.PostCollection, error)
@ -23,6 +23,9 @@ type TweetService interface {
GetPostAttatchmentBill(postID, userID int64) (*ms.PostAttachmentBill, error) GetPostAttatchmentBill(postID, userID int64) (*ms.PostAttachmentBill, error)
GetPostContentsByIDs(ids []int64) ([]*ms.PostContent, error) GetPostContentsByIDs(ids []int64) ([]*ms.PostContent, error)
GetPostContentByID(id int64) (*ms.PostContent, error) GetPostContentByID(id int64) (*ms.PostContent, error)
ListUserStarTweets(user *cs.VistUser, limit int, offset int) ([]*ms.PostStar, int64, error)
ListUserMediaTweets(user *cs.VistUser, limit int, offset int) ([]*ms.Post, int64, error)
ListUserCommentTweets(user *cs.VistUser, limit int, offset int) ([]*ms.Post, int64, error)
} }
// TweetManageService 推文管理服务,包括创建/删除/更新推文 // TweetManageService 推文管理服务,包括创建/删除/更新推文
@ -31,6 +34,7 @@ type TweetManageService interface {
DeletePost(post *ms.Post) ([]string, error) DeletePost(post *ms.Post) ([]string, error)
LockPost(post *ms.Post) error LockPost(post *ms.Post) error
StickPost(post *ms.Post) error StickPost(post *ms.Post) error
HighlightPost(userId, postId int64) (int, error)
VisiblePost(post *ms.Post, visibility PostVisibleT) error VisiblePost(post *ms.Post, visibility PostVisibleT) error
UpdatePost(post *ms.Post) error UpdatePost(post *ms.Post) error
CreatePostStar(postID, userID int64) (*ms.PostStar, error) CreatePostStar(postID, userID int64) (*ms.PostStar, error)

@ -26,3 +26,13 @@ type ContactManageService interface {
GetContacts(userId int64, offset int, limit int) (*ms.ContactList, error) GetContacts(userId int64, offset int, limit int) (*ms.ContactList, error)
IsFriend(userID int64, friendID int64) bool IsFriend(userID int64, friendID int64) bool
} }
// FollowingManageService 关注管理服务
type FollowingManageService interface {
FollowUser(userId int64, followId int64) error
UnfollowUser(userId int64, followId int64) error
ListFollows(userId int64, limit, offset int) (*ms.ContactList, error)
ListFollowings(userId int64, limit, offset int) (*ms.ContactList, error)
GetFollowCount(userId int64) (int64, int64, error)
IsFollow(userId int64, followId int64) bool
}

@ -14,9 +14,7 @@ var (
) )
type bigCacheTweetsCache struct { type bigCacheTweetsCache struct {
name string bc *bigcache.BigCache
version *semver.Version
bc *bigcache.BigCache
} }
func (s *bigCacheTweetsCache) getTweetsBytes(key string) ([]byte, error) { func (s *bigCacheTweetsCache) getTweetsBytes(key string) ([]byte, error) {

@ -5,6 +5,7 @@
package cache package cache
import ( import (
"context"
"time" "time"
"github.com/allegro/bigcache/v3" "github.com/allegro/bigcache/v3"
@ -28,7 +29,7 @@ func NewBigCacheIndexService(ips core.IndexPostsService, ams core.AuthorizationM
c.MaxEntrySize = 10000 c.MaxEntrySize = 10000
c.Logger = logrus.StandardLogger() c.Logger = logrus.StandardLogger()
bc, err := bigcache.NewBigCache(c) bc, err := bigcache.New(context.Background(), c)
if err != nil { if err != nil {
logrus.Fatalf("initial bigCahceIndex failure by err: %v", err) logrus.Fatalf("initial bigCahceIndex failure by err: %v", err)
} }

@ -249,7 +249,7 @@ func (s *contactManageSrv) GetContacts(userId int64, offset int, limit int) (*ms
if c.User != nil { if c.User != nil {
resp.Contacts = append(resp.Contacts, ms.ContactItem{ resp.Contacts = append(resp.Contacts, ms.ContactItem{
UserId: c.FriendId, UserId: c.FriendId,
UserName: c.User.Username, Username: c.User.Username,
Nickname: c.User.Nickname, Nickname: c.User.Nickname,
Avatar: c.User.Avatar, Avatar: c.User.Avatar,
Phone: c.User.Phone, Phone: c.User.Phone,

@ -0,0 +1,87 @@
// 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 dbr
import (
"github.com/sirupsen/logrus"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Following struct {
*Model
User *User `json:"-" gorm:"foreignKey:ID;references:FollowId"`
UserId int64 `json:"user_id"`
FollowId int64 `json:"friend_id"`
}
func (f *Following) GetFollowing(db *gorm.DB, userId, followId int64) (*Following, error) {
var following Following
err := db.Omit("User").Unscoped().Where("user_id = ? AND follow_id = ?", userId, followId).First(&following).Error
if err != nil {
logrus.Debugf("Following.GetFollowing get following error:%s", err)
return nil, err
}
return &following, nil
}
func (f *Following) DelFollowing(db *gorm.DB, userId, followId int64) error {
return db.Omit("User").Unscoped().Where("user_id = ? AND follow_id = ?", userId, followId).Delete(f).Error
}
func (f *Following) ListFollows(db *gorm.DB, userId int64, limit int, offset int) (res []*Following, total int64, err error) {
db = db.Model(f).Where("user_id=?", userId)
if err = db.Count(&total).Error; err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
db.Joins("User").Order(clause.OrderByColumn{Column: clause.Column{Table: "User", Name: "nickname"}, Desc: false})
if err = db.Find(&res).Error; err != nil {
return
}
return
}
func (f *Following) ListFollowingIds(db *gorm.DB, userId int64, limit, offset int) (ids []int64, total int64, err error) {
db = db.Model(f).Where("follow_id=?", userId)
if err = db.Count(&total).Error; err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
if err = db.Omit("User").Select("user_id").Find(&ids).Error; err != nil {
return
}
return
}
func (f *Following) FollowCount(db *gorm.DB, userId int64) (follows int64, followings int64, err error) {
if err = db.Model(f).Where("user_id=?", userId).Count(&follows).Error; err != nil {
return
}
if err = db.Model(f).Where("follow_id=?", userId).Count(&followings).Error; err != nil {
return
}
return
}
func (s *Following) IsFollow(db *gorm.DB, userId int64, followId int64) bool {
if _, err := s.GetFollowing(db, userId, followId); err == nil {
return true
}
return false
}
func (f *Following) Create(db *gorm.DB) (*Following, error) {
err := db.Omit("User").Create(f).Error
return f, err
}
func (c *Following) UpdateInUnscoped(db *gorm.DB) error {
return db.Unscoped().Omit("User").Save(c).Error
}

@ -21,6 +21,10 @@ const (
PostVisitInvalid PostVisitInvalid
) )
type PostByMedia = Post
type PostByComment = Post
type Post struct { type Post struct {
*Model *Model
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`

@ -7,6 +7,7 @@ package dbr
import ( import (
"time" "time"
"github.com/rocboss/paopao-ce/internal/core/cs"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
) )
@ -52,18 +53,14 @@ func (p *PostStar) Delete(db *gorm.DB) error {
}).Error }).Error
} }
func (p *PostStar) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*PostStar, error) { func (p *PostStar) List(db *gorm.DB, conditions *ConditionsT, typ cs.RelationTyp, limit int, offset int) (res []*PostStar, err error) {
var stars []*PostStar
var err error
tn := db.NamingStrategy.TableName("PostStar") + "." tn := db.NamingStrategy.TableName("PostStar") + "."
if offset >= 0 && limit > 0 { if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit) db = db.Offset(offset).Limit(limit)
} }
if p.UserID > 0 { if p.UserID > 0 {
db = db.Where(tn+"user_id = ?", p.UserID) db = db.Where(tn+"user_id = ?", p.UserID)
} }
for k, v := range *conditions { for k, v := range *conditions {
if k == "ORDER" { if k == "ORDER" {
db = db.Order(v) db = db.Order(v)
@ -71,18 +68,24 @@ func (p *PostStar) List(db *gorm.DB, conditions *ConditionsT, offset, limit int)
db = db.Where(tn+k, v) db = db.Where(tn+k, v)
} }
} }
db = db.Joins("Post")
db = db.Joins("Post").Where("visibility <> ? OR (visibility = ? AND ? = ?)", PostVisitPrivate, PostVisitPrivate, clause.Column{Table: "Post", Name: "user_id"}, p.UserID).Order(clause.OrderByColumn{Column: clause.Column{Table: "Post", Name: "id"}, Desc: true}) switch typ {
if err = db.Find(&stars).Error; err != nil { case cs.RelationAdmin:
return nil, err // admin have all permition to visit all type tweets
case cs.RelationFriend:
db = db.Where("visibility = ? OR visibility = ?", PostVisitPublic, PostVisitFriend)
case cs.RelationSelf:
db = db.Where("visibility <> ? OR (visibility = ? AND ? = ?)", PostVisitPrivate, PostVisitPrivate, clause.Column{Table: "Post", Name: "user_id"}, p.UserID)
default:
db = db.Where("visibility=?", PostVisitPublic)
} }
return stars, nil db = db.Order(clause.OrderByColumn{Column: clause.Column{Table: "Post", Name: "id"}, Desc: true})
err = db.Find(&res).Error
return
} }
func (p *PostStar) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) { func (p *PostStar) Count(db *gorm.DB, typ cs.RelationTyp, conditions *ConditionsT) (res int64, err error) {
var count int64
tn := db.NamingStrategy.TableName("PostStar") + "." tn := db.NamingStrategy.TableName("PostStar") + "."
if p.PostID > 0 { if p.PostID > 0 {
db = db.Where(tn+"post_id = ?", p.PostID) db = db.Where(tn+"post_id = ?", p.PostID)
} }
@ -94,10 +97,17 @@ func (p *PostStar) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) {
db = db.Where(tn+k, v) db = db.Where(tn+k, v)
} }
} }
db = db.Joins("Post")
db = db.Joins("Post").Where("visibility <> ? OR (visibility = ? AND ? = ?)", PostVisitPrivate, PostVisitPrivate, clause.Column{Table: "Post", Name: "user_id"}, p.UserID) switch typ {
if err := db.Model(p).Count(&count).Error; err != nil { case cs.RelationAdmin:
return 0, err // admin have all permition to visit all type tweets
case cs.RelationFriend:
db = db.Where("visibility = ? OR visibility = ?", PostVisitPublic, PostVisitFriend)
case cs.RelationSelf:
db = db.Where("visibility <> ? OR (visibility = ? AND ? = ?)", PostVisitPrivate, PostVisitPrivate, clause.Column{Table: "Post", Name: "user_id"}, p.UserID)
default:
db = db.Where("visibility=?", PostVisitPublic)
} }
return count, nil err = db.Model(p).Count(&res).Error
return
} }

@ -0,0 +1,104 @@
// 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 jinzhu
import (
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
var (
_ core.FollowingManageService = (*followingManageSrv)(nil)
)
type followingManageSrv struct {
db *gorm.DB
f *dbr.Following
u *dbr.User
}
func newFollowingManageService(db *gorm.DB) core.FollowingManageService {
return &followingManageSrv{
db: db,
f: &dbr.Following{},
u: &dbr.User{},
}
}
func (s *followingManageSrv) FollowUser(userId int64, followId int64) error {
if _, err := s.f.GetFollowing(s.db, userId, followId); err != nil {
following := &dbr.Following{
UserId: userId,
FollowId: followId,
}
if _, err = following.Create(s.db); err != nil {
logrus.Errorf("contactManageSrv.fetchOrNewContact create new contact err:%s", err)
return err
}
}
return nil
}
func (s *followingManageSrv) UnfollowUser(userId int64, followId int64) error {
return s.f.DelFollowing(s.db, userId, followId)
}
func (s *followingManageSrv) ListFollows(userId int64, limit, offset int) (*ms.ContactList, error) {
follows, totoal, err := s.f.ListFollows(s.db, userId, limit, offset)
if err != nil {
return nil, err
}
res := &ms.ContactList{
Total: totoal,
}
for _, f := range follows {
res.Contacts = append(res.Contacts, ms.ContactItem{
UserId: f.User.ID,
Username: f.User.Username,
Nickname: f.User.Nickname,
Avatar: f.User.Avatar,
IsFollow: true,
})
}
return res, nil
}
func (s *followingManageSrv) ListFollowings(userId int64, limit, offset int) (*ms.ContactList, error) {
followingIds, totoal, err := s.f.ListFollowingIds(s.db, userId, limit, offset)
if err != nil {
return nil, err
}
followings, err := s.u.ListUserInfoById(s.db, followingIds)
if err != nil {
return nil, err
}
res := &ms.ContactList{
Total: totoal,
}
for _, user := range followings {
res.Contacts = append(res.Contacts, ms.ContactItem{
UserId: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Avatar: user.Avatar,
IsFollow: s.IsFollow(userId, user.ID),
})
}
return res, nil
}
func (s *followingManageSrv) GetFollowCount(userId int64) (int64, int64, error) {
return s.f.FollowCount(s.db, userId)
}
func (s *followingManageSrv) IsFollow(userId int64, followId int64) bool {
if _, err := s.f.GetFollowing(s.db, userId, followId); err == nil {
return true
}
return false
}

@ -17,10 +17,13 @@ var (
_comment_ string _comment_ string
_commentContent_ string _commentContent_ string
_commentReply_ string _commentReply_ string
_following_ string
_contact_ string _contact_ string
_contactGroup_ string _contactGroup_ string
_message_ string _message_ string
_post_ string _post_ string
_post_by_comment_ string
_post_by_media_ string
_postAttachmentBill_ string _postAttachmentBill_ string
_postCollection_ string _postCollection_ string
_postContent_ string _postContent_ string
@ -40,10 +43,13 @@ func initTableName() {
_comment_ = m[conf.TableComment] _comment_ = m[conf.TableComment]
_commentContent_ = m[conf.TableCommentContent] _commentContent_ = m[conf.TableCommentContent]
_commentReply_ = m[conf.TableCommentReply] _commentReply_ = m[conf.TableCommentReply]
_following_ = m[conf.TableFollowing]
_contact_ = m[conf.TableContact] _contact_ = m[conf.TableContact]
_contactGroup_ = m[conf.TableContactGroup] _contactGroup_ = m[conf.TableContactGroup]
_message_ = m[conf.TableMessage] _message_ = m[conf.TableMessage]
_post_ = m[conf.TablePost] _post_ = m[conf.TablePost]
_post_by_comment_ = m[conf.TablePostByComment]
_post_by_media_ = m[conf.TablePostByMedia]
_postAttachmentBill_ = m[conf.TablePostAttachmentBill] _postAttachmentBill_ = m[conf.TablePostAttachmentBill]
_postCollection_ = m[conf.TablePostCollection] _postCollection_ = m[conf.TablePostCollection]
_postContent_ = m[conf.TablePostContent] _postContent_ = m[conf.TablePostContent]

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Core service implement base gorm+mysql/postgresql/sqlite3. // package jinzhu Core service implement base gorm+mysql/postgresql/sqlite3.
// Jinzhu is the primary developer of gorm so use his name as // Jinzhu is the primary developer of gorm so use his name as
// package name as a saluter. // package name as a saluter.
@ -42,6 +42,7 @@ type dataSrv struct {
core.CommentManageService core.CommentManageService
core.UserManageService core.UserManageService
core.ContactManageService core.ContactManageService
core.FollowingManageService
core.SecurityService core.SecurityService
core.AttachmentCheckService core.AttachmentCheckService
core.ShareKeyService core.ShareKeyService
@ -61,24 +62,12 @@ func NewDataService() (core.DataService, core.VersionInfo) {
var ( var (
v core.VersionInfo v core.VersionInfo
cis core.CacheIndexService cis core.CacheIndexService
ips core.IndexPostsService
) )
db := conf.MustGormDB() db := conf.MustGormDB()
pvs := security.NewPhoneVerifyService() pvs := security.NewPhoneVerifyService()
ams := NewAuthorizationManageService() ams := NewAuthorizationManageService()
ths := newTweetHelpService(db) ths := newTweetHelpService(db)
ips := newShipIndexService(db, ams, ths)
// 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 // initialize core.CacheIndexService
cfg.On(cfg.Actions{ cfg.On(cfg.Actions{
@ -88,7 +77,6 @@ func NewDataService() (core.DataService, core.VersionInfo) {
cis, v = cache.NewSimpleCacheIndexService(ips) cis, v = cache.NewSimpleCacheIndexService(ips)
}, },
"BigCacheIndex": func() { "BigCacheIndex": func() {
// TODO: make cache index post in different scence like friendship/followship/lightship
cis, v = cache.NewBigCacheIndexService(ips, ams) cis, v = cache.NewBigCacheIndexService(ips, ams)
}, },
"RedisCacheIndex": func() { "RedisCacheIndex": func() {
@ -112,6 +100,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
CommentManageService: newCommentManageService(db), CommentManageService: newCommentManageService(db),
UserManageService: newUserManageService(db), UserManageService: newUserManageService(db),
ContactManageService: newContactManageService(db), ContactManageService: newContactManageService(db),
FollowingManageService: newFollowingManageService(db),
SecurityService: newSecurityService(db, pvs), SecurityService: newSecurityService(db, pvs),
AttachmentCheckService: security.NewAttachmentCheckService(), AttachmentCheckService: security.NewAttachmentCheckService(),
ShareKeyService: NewShareKeyService(db), ShareKeyService: NewShareKeyService(db),

@ -15,35 +15,23 @@ import (
) )
var ( var (
_ core.IndexPostsService = (*friendIndexSrv)(nil) _ core.IndexPostsService = (*shipIndexSrv)(nil)
_ core.IndexPostsService = (*followIndexSrv)(nil)
_ core.IndexPostsService = (*lightIndexSrv)(nil)
_ core.IndexPostsService = (*simpleIndexPostsSrv)(nil) _ core.IndexPostsService = (*simpleIndexPostsSrv)(nil)
) )
type friendIndexSrv struct { type shipIndexSrv struct {
ams core.AuthorizationManageService ams core.AuthorizationManageService
ths core.TweetHelpService ths core.TweetHelpService
db *gorm.DB db *gorm.DB
} }
type followIndexSrv struct {
ths core.TweetHelpService
db *gorm.DB
}
type lightIndexSrv struct {
ths core.TweetHelpService
db *gorm.DB
}
type simpleIndexPostsSrv struct { type simpleIndexPostsSrv struct {
ths core.TweetHelpService ths core.TweetHelpService
db *gorm.DB db *gorm.DB
} }
// IndexPosts 根据userId查询广场推文列表简单做到不同用户的主页都是不同的 // IndexPosts 根据userId查询广场推文列表简单做到不同用户的主页都是不同的
func (s *friendIndexSrv) IndexPosts(user *ms.User, offset int, limit int) (*ms.IndexTweetList, error) { func (s *shipIndexSrv) IndexPosts(user *ms.User, offset int, limit int) (*ms.IndexTweetList, error) {
predicates := dbr.Predicates{ predicates := dbr.Predicates{
"ORDER": []any{"is_top DESC, latest_replied_on DESC"}, "ORDER": []any{"is_top DESC, latest_replied_on DESC"},
} }
@ -77,60 +65,6 @@ func (s *friendIndexSrv) IndexPosts(user *ms.User, offset int, limit int) (*ms.I
}, nil }, nil
} }
func (s *friendIndexSrv) TweetTimeline(userId int64, offset int, limit int) (*cs.TweetBox, error) {
// TODO
return nil, debug.ErrNotImplemented
}
// IndexPosts 根据userId查询广场推文列表
func (s *followIndexSrv) IndexPosts(user *ms.User, offset int, limit int) (*ms.IndexTweetList, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *followIndexSrv) TweetTimeline(userId int64, offset int, limit int) (*cs.TweetBox, error) {
// TODO
return nil, debug.ErrNotImplemented
}
// IndexPosts 根据userId查询广场推文列表获取公开可见Tweet或者所属用户的私有Tweet
func (s *lightIndexSrv) IndexPosts(user *ms.User, offset int, limit int) (*ms.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("gormIndexPostsSrv.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 &ms.IndexTweetList{
Tweets: formatPosts,
Total: total,
}, nil
}
func (s *lightIndexSrv) TweetTimeline(userId int64, offset int, limit int) (*cs.TweetBox, error) {
// TODO
return nil, debug.ErrNotImplemented
}
// simpleCacheIndexGetPosts simpleCacheIndex 专属获取广场推文列表函数 // simpleCacheIndexGetPosts simpleCacheIndex 专属获取广场推文列表函数
func (s *simpleIndexPostsSrv) IndexPosts(_user *ms.User, offset int, limit int) (*ms.IndexTweetList, error) { func (s *simpleIndexPostsSrv) IndexPosts(_user *ms.User, offset int, limit int) (*ms.IndexTweetList, error) {
predicates := dbr.Predicates{ predicates := dbr.Predicates{
@ -165,28 +99,14 @@ func (s *simpleIndexPostsSrv) TweetTimeline(userId int64, offset int, limit int)
return nil, debug.ErrNotImplemented return nil, debug.ErrNotImplemented
} }
func newFriendIndexService(db *gorm.DB, ams core.AuthorizationManageService, ths core.TweetHelpService) core.IndexPostsService { func newShipIndexService(db *gorm.DB, ams core.AuthorizationManageService, ths core.TweetHelpService) core.IndexPostsService {
return &friendIndexSrv{ return &shipIndexSrv{
ams: ams, ams: ams,
ths: ths, ths: ths,
db: db, db: db,
} }
} }
func newFollowIndexService(db *gorm.DB, ths core.TweetHelpService) core.IndexPostsService {
return &followIndexSrv{
ths: ths,
db: db,
}
}
func newLightIndexService(db *gorm.DB, ths core.TweetHelpService) core.IndexPostsService {
return &lightIndexSrv{
ths: ths,
db: db,
}
}
func newSimpleIndexPostsService(db *gorm.DB, ths core.TweetHelpService) core.IndexPostsService { func newSimpleIndexPostsService(db *gorm.DB, ths core.TweetHelpService) core.IndexPostsService {
return &simpleIndexPostsSrv{ return &simpleIndexPostsSrv{
ths: ths, ths: ths,

@ -143,7 +143,7 @@ func (s *topicSrv) GetFollowTags(userId int64, limit int, offset int) (cs.TagLis
} }
// 置顶排序后处理 // 置顶排序后处理
// TODO: 垃圾办法最好是topic_user join tag 一次查询但是gorm的join真他喵的别扭F*K // TODO: 垃圾办法最好是topic_user join tag 一次查询但是gorm的join真他喵的别扭F*K
res := make(cs.TagList, len(topicIds), len(topicIds)) res := make(cs.TagList, len(topicIds))
for _, tag := range formtedTags { for _, tag := range formtedTags {
res[topicIdsMap[tag.ID]] = tag res[topicIdsMap[tag.ID]] = tag
} }
@ -217,10 +217,8 @@ func (s *topicSrv) tagsFormatA(userId int64, tags cs.TagList) (cs.TagList, error
func (s *topicSrv) tagsFormatB(userTopicsMap map[int64]*topicInfo, tags cs.TagInfoList) (cs.TagList, error) { func (s *topicSrv) tagsFormatB(userTopicsMap map[int64]*topicInfo, tags cs.TagInfoList) (cs.TagList, error) {
// 获取创建者User IDs // 获取创建者User IDs
userIds := []int64{} userIds := []int64{}
tagIds := []int64{}
for _, tag := range tags { for _, tag := range tags {
userIds = append(userIds, tag.UserID) userIds = append(userIds, tag.UserID)
tagIds = append(tagIds, tag.ID)
} }
users, err := (&dbr.User{}).ListUserInfoById(s.db, userIds) users, err := (&dbr.User{}).ListUserInfoById(s.db, userIds)
if err != nil { if err != nil {

@ -307,7 +307,26 @@ func (s *tweetManageSrv) StickPost(post *ms.Post) error {
return nil return nil
} }
func (s *tweetManageSrv) VisiblePost(post *ms.Post, visibility core.PostVisibleT) error { func (s *tweetManageSrv) HighlightPost(userId int64, postId int64) (res int, err error) {
var post dbr.Post
tx := s.db.Begin()
defer tx.Rollback()
post.Get(tx)
if err = tx.Where("id = ? AND is_del = 0", postId).First(&post).Error; err != nil {
return
}
if post.UserID != userId {
return 0, cs.ErrNoPermission
}
post.IsEssence = 1 - post.IsEssence
if err = post.Update(tx); err != nil {
return
}
tx.Commit()
return post.IsEssence, nil
}
func (s *tweetManageSrv) VisiblePost(post *ms.Post, visibility core.PostVisibleT) (err error) {
oldVisibility := post.Visibility oldVisibility := post.Visibility
post.Visibility = visibility post.Visibility = visibility
// TODO: 这个判断是否可以不要呢 // TODO: 这个判断是否可以不要呢
@ -320,33 +339,32 @@ func (s *tweetManageSrv) VisiblePost(post *ms.Post, visibility core.PostVisibleT
// TODO: 置顶推文用户是否有权设置成私密? 后续完善 // TODO: 置顶推文用户是否有权设置成私密? 后续完善
post.IsTop = 0 post.IsTop = 0
} }
db := s.db.Begin() tx := s.db.Begin()
err := post.Update(db) defer tx.Rollback()
if err != nil { if err = post.Update(tx); err != nil {
db.Rollback() return
return err
} }
// tag处理 // tag处理
tags := strings.Split(post.Tags, ",") tags := strings.Split(post.Tags, ",")
// TODO: 暂时宽松不处理错误,这里或许可以有优化,后续完善 // TODO: 暂时宽松不处理错误,这里或许可以有优化,后续完善
if oldVisibility == dbr.PostVisitPrivate { if oldVisibility == dbr.PostVisitPrivate {
// 从私密转为非私密才需要重新创建tag // 从私密转为非私密才需要重新创建tag
createTags(db, post.UserID, tags) createTags(tx, post.UserID, tags)
} else if visibility == dbr.PostVisitPrivate { } else if visibility == dbr.PostVisitPrivate {
// 从非私密转为私密才需要删除tag // 从非私密转为私密才需要删除tag
deleteTags(db, tags) deleteTags(tx, tags)
} }
db.Commit() tx.Commit()
s.cacheIndex.SendAction(core.IdxActVisiblePost, post) s.cacheIndex.SendAction(core.IdxActVisiblePost, post)
return nil return
} }
func (s *tweetManageSrv) UpdatePost(post *ms.Post) error { func (s *tweetManageSrv) UpdatePost(post *ms.Post) (err error) {
if err := post.Update(s.db); err != nil { if err = post.Update(s.db); err != nil {
return err return
} }
s.cacheIndex.SendAction(core.IdxActUpdatePost, post) s.cacheIndex.SendAction(core.IdxActUpdatePost, post)
return nil return
} }
func (s *tweetManageSrv) CreatePostStar(postID, userID int64) (*ms.PostStar, error) { func (s *tweetManageSrv) CreatePostStar(postID, userID int64) (*ms.PostStar, error) {
@ -386,21 +404,67 @@ func (s *tweetSrv) GetUserPostStar(postID, userID int64) (*ms.PostStar, error) {
return star.Get(s.db) return star.Get(s.db)
} }
func (s *tweetSrv) GetUserPostStars(userID int64, offset, limit int) ([]*ms.PostStar, error) { func (s *tweetSrv) GetUserPostStars(userID int64, limit int, offset int) ([]*ms.PostStar, error) {
star := &dbr.PostStar{ star := &dbr.PostStar{
UserID: userID, UserID: userID,
} }
return star.List(s.db, &dbr.ConditionsT{ return star.List(s.db, &dbr.ConditionsT{
"ORDER": s.db.NamingStrategy.TableName("PostStar") + ".id DESC", "ORDER": s.db.NamingStrategy.TableName("PostStar") + ".id DESC",
}, offset, limit) }, cs.RelationSelf, limit, offset)
}
func (s *tweetSrv) ListUserStarTweets(user *cs.VistUser, limit int, offset int) (res []*ms.PostStar, total int64, err error) {
star := &dbr.PostStar{
UserID: user.UserId,
}
if total, err = star.Count(s.db, user.RelTyp, &dbr.ConditionsT{}); err != nil {
return
}
res, err = star.List(s.db, &dbr.ConditionsT{
"ORDER": s.db.NamingStrategy.TableName("PostStar") + ".id DESC",
}, user.RelTyp, limit, offset)
return
}
func (s *tweetSrv) getUserTweets(db *gorm.DB, user *cs.VistUser, limit int, offset int) (res []*ms.Post, total int64, err error) {
visibilities := []core.PostVisibleT{core.PostVisitPublic}
switch user.RelTyp {
case cs.RelationAdmin, cs.RelationSelf:
visibilities = append(visibilities, core.PostVisitPrivate, core.PostVisitFriend)
case cs.RelationFriend:
visibilities = append(visibilities, core.PostVisitFriend)
case cs.RelationGuest:
fallthrough
default:
// nothing
}
db = db.Where("visibility IN ? AND is_del=0", visibilities)
err = db.Count(&total).Error
if err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
err = db.Order("latest_replied_on DESC").Find(&res).Error
return
}
func (s *tweetSrv) ListUserMediaTweets(user *cs.VistUser, limit int, offset int) ([]*ms.Post, int64, error) {
db := s.db.Table(_post_by_media_).Where("user_id=?", user.UserId)
return s.getUserTweets(db, user, limit, offset)
}
func (s *tweetSrv) ListUserCommentTweets(user *cs.VistUser, limit int, offset int) ([]*ms.Post, int64, error) {
db := s.db.Table(_post_by_comment_).Where("comment_user_id=?", user.UserId)
return s.getUserTweets(db, user, limit, offset)
} }
func (s *tweetSrv) GetUserPostStarCount(userID int64) (int64, error) { func (s *tweetSrv) GetUserPostStarCount(userID int64) (int64, error) {
star := &dbr.PostStar{ star := &dbr.PostStar{
UserID: userID, UserID: userID,
} }
return star.Count(s.db, &dbr.ConditionsT{}) return star.Count(s.db, cs.RelationSelf, &dbr.ConditionsT{})
} }
func (s *tweetSrv) GetUserPostCollection(postID, userID int64) (*ms.PostCollection, error) { func (s *tweetSrv) GetUserPostCollection(postID, userID int64) (*ms.PostCollection, error) {

@ -0,0 +1,16 @@
// 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 joint provider some common base type or logic for model define.
package joint
type BasePageInfo struct {
Page int `form:"-" binding:"-"`
PageSize int `form:"-" binding:"-"`
}
func (r *BasePageInfo) SetPageInfo(page int, pageSize int) {
r.Page, r.PageSize = page, pageSize
}

@ -27,14 +27,17 @@ type UserInfoReq struct {
} }
type UserInfoResp struct { type UserInfoResp struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Nickname string `json:"nickname"` Nickname string `json:"nickname"`
Username string `json:"username"` Username string `json:"username"`
Status int `json:"status"` Status int `json:"status"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
Balance int64 `json:"balance"` Balance int64 `json:"balance"`
Phone string `json:"phone"` Phone string `json:"phone"`
IsAdmin bool `json:"is_admin"` IsAdmin bool `json:"is_admin"`
CreatedOn int64 `json:"created_on"`
Follows int64 `json:"follows"`
Followings int64 `json:"followings"`
} }
type GetUnreadMsgCountReq struct { type GetUnreadMsgCountReq struct {

@ -4,24 +4,33 @@
package web package web
import "github.com/rocboss/paopao-ce/internal/servants/base" import (
"github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/internal/servants/base"
)
type AddFollowingReq struct { type FollowUserReq struct {
BaseInfo `json:"-" binding:"-"` BaseInfo `json:"-" binding:"-"`
UserId int64 `json:"user_id" binding:"required"`
} }
type DeleteFollowingReq struct { type UnfollowUserReq struct {
BaseInfo `json:"-" binding:"-"` BaseInfo `json:"-" binding:"-"`
UserId int64 `json:"user_id" binding:"required"`
} }
type ListFollowingsReq struct { type ListFollowsReq struct {
BaseInfo `json:"-" binding:"-"` BaseInfo `json:"-" binding:"-"`
joint.BasePageInfo
Username string `form:"username" binding:"required"`
} }
type ListFollowingsResp base.PageResp type ListFollowsResp base.PageResp
type ListFollowersReq struct { type ListFollowingsReq struct {
BaseInfo `form:"-" binding:"-"` BaseInfo `form:"-" binding:"-"`
joint.BasePageInfo
Username string `form:"username" binding:"required"`
} }
type ListFollowersResp base.PageResp type ListFollowingsResp base.PageResp

@ -67,13 +67,17 @@ type GetUserProfileReq struct {
} }
type GetUserProfileResp struct { type GetUserProfileResp struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Nickname string `json:"nickname"` Nickname string `json:"nickname"`
Username string `json:"username"` Username string `json:"username"`
Status int `json:"status"` Status int `json:"status"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
IsAdmin bool `json:"is_admin"` IsAdmin bool `json:"is_admin"`
IsFriend bool `json:"is_friend"` IsFriend bool `json:"is_friend"`
IsFollowing bool `json:"is_following"`
CreatedOn int64 `json:"created_on"`
Follows int64 `json:"follows"`
Followings int64 `json:"followings"`
} }
type TopicListReq struct { type TopicListReq struct {

@ -46,6 +46,7 @@ var (
ErrDownloadExecFail = xerror.NewError(30010, "附件下载失败:扣费失败") ErrDownloadExecFail = xerror.NewError(30010, "附件下载失败:扣费失败")
ErrStickPostFailed = xerror.NewError(30011, "动态置顶失败") ErrStickPostFailed = xerror.NewError(30011, "动态置顶失败")
ErrVisblePostFailed = xerror.NewError(30012, "更新可见性失败") ErrVisblePostFailed = xerror.NewError(30012, "更新可见性失败")
ErrHighlightPostFailed = xerror.NewError(30013, "动态设为亮点失败")
ErrGetCommentsFailed = xerror.NewError(40001, "获取评论列表失败") ErrGetCommentsFailed = xerror.NewError(40001, "获取评论列表失败")
ErrCreateCommentFailed = xerror.NewError(40002, "评论发布失败") ErrCreateCommentFailed = xerror.NewError(40002, "评论发布失败")
@ -78,6 +79,11 @@ var (
ErrDeleteFriendFailed = xerror.NewError(80006, "删除好友失败") ErrDeleteFriendFailed = xerror.NewError(80006, "删除好友失败")
ErrGetContactsFailed = xerror.NewError(80007, "获取联系人列表失败") ErrGetContactsFailed = xerror.NewError(80007, "获取联系人列表失败")
ErrNoActionToSelf = xerror.NewError(80008, "不允许对自己操作") ErrNoActionToSelf = xerror.NewError(80008, "不允许对自己操作")
ErrFolloUserFailed = xerror.NewError(80100, "关注失败")
ErrUnfollowUserFailed = xerror.NewError(80101, "取消关注失败")
ErrListFollowsFailed = xerror.NewError(80102, "获取关注列表失败")
ErrListFollowingsFailed = xerror.NewError(80103, "获取粉丝列表列表失败")
ErrGetFollowCountFailed = xerror.NewError(80104, "获取关注计数信息失败")
ErrFollowTopicFailed = xerror.NewError(90001, "关注话题失败") ErrFollowTopicFailed = xerror.NewError(90001, "关注话题失败")
ErrUnfollowTopicFailed = xerror.NewError(90002, "取消关注话题失败") ErrUnfollowTopicFailed = xerror.NewError(90002, "取消关注话题失败")

@ -17,6 +17,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/cs"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/dao" "github.com/rocboss/paopao-ce/internal/dao"
"github.com/rocboss/paopao-ce/internal/dao/cache" "github.com/rocboss/paopao-ce/internal/dao/cache"
@ -274,6 +275,37 @@ func (s *DaoServant) GetTweetList(conditions ms.ConditionsT, offset, limit int)
return posts, postFormated, err return posts, postFormated, err
} }
func (s *DaoServant) RelationTypFrom(me *ms.User, username string) (res *cs.VistUser, err error) {
res = &cs.VistUser{
RelTyp: cs.RelationSelf,
Username: username,
}
// visit by self
if me != nil && me.Username == username {
res.UserId = me.ID
return
}
he, xerr := s.Ds.GetUserByUsername(username)
if xerr != nil || (he.Model != nil && he.ID <= 0) {
return nil, errors.New("get user failed with username: " + username)
}
res.UserId = he.ID
// visit by guest
if me == nil {
res.RelTyp = cs.RelationGuest
return
}
// visit by admin/friend/other
if me.IsAdmin {
res.RelTyp = cs.RelationAdmin
} else if s.Ds.IsFriend(me.ID, he.ID) {
res.RelTyp = cs.RelationFriend
} else {
res.RelTyp = cs.RelationGuest
}
return
}
func NewBindAnyFn() func(c *gin.Context, obj any) mir.Error { func NewBindAnyFn() func(c *gin.Context, obj any) mir.Error {
if conf.UseSentryGin() { if conf.UseSentryGin() {
return bindAnySentry return bindAnySentry

@ -2,8 +2,8 @@
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !embed //go:build slim && embed
// +build !embed // +build slim,embed
package statick package statick

@ -2,8 +2,8 @@
// Use of this source code is governed by a MIT style // Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build embed //go:build !(slim && embed)
// +build embed // +build !slim !embed
package statick package statick

@ -60,14 +60,21 @@ func (s *coreSrv) GetUserInfo(req *web.UserInfoReq) (*web.UserInfoResp, mir.Erro
if user.Model == nil || user.ID < 0 { if user.Model == nil || user.ID < 0 {
return nil, xerror.UnauthorizedAuthNotExist return nil, xerror.UnauthorizedAuthNotExist
} }
follows, followings, err := s.Ds.GetFollowCount(user.ID)
if err != nil {
return nil, web.ErrGetFollowCountFailed
}
resp := &web.UserInfoResp{ resp := &web.UserInfoResp{
Id: user.ID, Id: user.ID,
Nickname: user.Nickname, Nickname: user.Nickname,
Username: user.Username, Username: user.Username,
Status: user.Status, Status: user.Status,
Avatar: user.Avatar, Avatar: user.Avatar,
Balance: user.Balance, Balance: user.Balance,
IsAdmin: user.IsAdmin, IsAdmin: user.IsAdmin,
CreatedOn: user.CreatedOn,
Follows: follows,
Followings: followings,
} }
if user.Phone != "" && len(user.Phone) == 11 { if user.Phone != "" && len(user.Phone) == 11 {
resp.Phone = user.Phone[0:3] + "****" + user.Phone[7:] resp.Phone = user.Phone[0:3] + "****" + user.Phone[7:]
@ -240,7 +247,7 @@ func (s *coreSrv) UserPhoneBind(req *web.UserPhoneBindReq) mir.Error {
} }
func (s *coreSrv) GetStars(req *web.GetStarsReq) (*web.GetStarsResp, mir.Error) { func (s *coreSrv) GetStars(req *web.GetStarsReq) (*web.GetStarsResp, mir.Error) {
stars, err := s.Ds.GetUserPostStars(req.UserId, (req.Page-1)*req.PageSize, req.PageSize) stars, err := s.Ds.GetUserPostStars(req.UserId, req.PageSize, (req.Page-1)*req.PageSize)
if err != nil { if err != nil {
logrus.Errorf("Ds.GetUserPostStars err: %s", err) logrus.Errorf("Ds.GetUserPostStars err: %s", err)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
@ -250,7 +257,6 @@ func (s *coreSrv) GetStars(req *web.GetStarsReq) (*web.GetStarsResp, mir.Error)
logrus.Errorf("Ds.GetUserPostStars err: %s", err) logrus.Errorf("Ds.GetUserPostStars err: %s", err)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
} }
var posts []*ms.Post var posts []*ms.Post
for _, star := range stars { for _, star := range stars {
posts = append(posts, star.Post) posts = append(posts, star.Post)
@ -261,7 +267,6 @@ func (s *coreSrv) GetStars(req *web.GetStarsReq) (*web.GetStarsResp, mir.Error)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
} }
resp := base.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows) resp := base.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows)
return (*web.GetStarsResp)(resp), nil return (*web.GetStarsResp)(resp), nil
} }

@ -5,10 +5,13 @@
package web package web
import ( import (
"github.com/alimy/mir/v4"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
api "github.com/rocboss/paopao-ce/auto/api/v1" api "github.com/rocboss/paopao-ce/auto/api/v1"
"github.com/rocboss/paopao-ce/internal/model/web"
"github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/internal/servants/base"
"github.com/rocboss/paopao-ce/internal/servants/chain" "github.com/rocboss/paopao-ce/internal/servants/chain"
"github.com/sirupsen/logrus"
) )
var ( var (
@ -24,6 +27,54 @@ func (s *followshipSrv) Chain() gin.HandlersChain {
return gin.HandlersChain{chain.JWT()} return gin.HandlersChain{chain.JWT()}
} }
func (s *followshipSrv) ListFollowings(r *web.ListFollowingsReq) (*web.ListFollowingsResp, mir.Error) {
he, err := s.Ds.GetUserByUsername(r.Username)
if err != nil {
logrus.Errorf("Ds.GetUserByUsername err: %s", err)
return nil, web.ErrNoExistUsername
}
res, err := s.Ds.ListFollowings(he.ID, r.PageSize, r.Page-1)
if err != nil {
logrus.Errorf("Ds.ListFollowings err: %s", err)
return nil, web.ErrListFollowingsFailed
}
resp := base.PageRespFrom(res.Contacts, r.Page, r.PageSize, res.Total)
return (*web.ListFollowingsResp)(resp), nil
}
func (s *followshipSrv) ListFollows(r *web.ListFollowsReq) (*web.ListFollowsResp, mir.Error) {
he, err := s.Ds.GetUserByUsername(r.Username)
if err != nil {
logrus.Errorf("Ds.GetUserByUsername err: %s", err)
return nil, web.ErrNoExistUsername
}
res, err := s.Ds.ListFollows(he.ID, r.PageSize, r.Page-1)
if err != nil {
logrus.Errorf("Ds.ListFollows err: %s", err)
return nil, web.ErrListFollowsFailed
}
resp := base.PageRespFrom(res.Contacts, r.Page, r.PageSize, res.Total)
return (*web.ListFollowsResp)(resp), nil
}
func (s *followshipSrv) UnfollowUser(r *web.UnfollowUserReq) mir.Error {
if err := s.Ds.UnfollowUser(r.User.ID, r.UserId); err != nil {
logrus.Errorf("Ds.UnfollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId)
return web.ErrUnfollowUserFailed
}
return nil
}
func (s *followshipSrv) FollowUser(r *web.FollowUserReq) mir.Error {
if err := s.Ds.FollowUser(r.User.ID, r.UserId); err != nil {
logrus.Errorf("Ds.FollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId)
return web.ErrUnfollowUserFailed
}
return nil
}
func newFollowshipSrv(s *base.DaoServant) api.Followship { func newFollowshipSrv(s *base.DaoServant) api.Followship {
return &followshipSrv{} return &followshipSrv{
DaoServant: s,
}
} }

@ -5,6 +5,7 @@
package web package web
import ( import (
"fmt"
"github.com/alimy/mir/v4" "github.com/alimy/mir/v4"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
api "github.com/rocboss/paopao-ce/auto/api/v1" api "github.com/rocboss/paopao-ce/auto/api/v1"
@ -62,77 +63,36 @@ func (s *looseSrv) Timeline(req *web.TimelineReq) (*web.TimelineResp, mir.Error)
} }
func (s *looseSrv) GetUserTweets(req *web.GetUserTweetsReq) (res *web.GetUserTweetsResp, err mir.Error) { func (s *looseSrv) GetUserTweets(req *web.GetUserTweetsReq) (res *web.GetUserTweetsResp, err mir.Error) {
isSelf := (req.User != nil && req.User.Username == req.Username) user, xerr := s.RelationTypFrom(req.User, req.Username)
if xerr != nil {
return nil, err
}
switch req.Style { switch req.Style {
case web.UserPostsStyleComment: case web.UserPostsStyleComment, web.UserPostsStyleMedia:
res, err = s.getUserCommentTweets(req, isSelf) res, err = s.listUserTweets(req, user)
case web.UserPostsStyleHighlight: case web.UserPostsStyleHighlight:
res, err = s.getUserHighlightTweets(req, isSelf) res, err = s.getUserPostTweets(req, user, true)
case web.UserPostsStyleMedia:
res, err = s.getUserMediaTweets(req, isSelf)
case web.UserPostsStyleStar: case web.UserPostsStyleStar:
res, err = s.getUserStarTweets(req, isSelf) res, err = s.getUserStarTweets(req, user)
case web.UserPostsStylePost: case web.UserPostsStylePost:
fallthrough fallthrough
default: default:
res, err = s.getUserPostTweets(req) res, err = s.getUserPostTweets(req, user, false)
} }
return return
} }
func (s *looseSrv) getUserCommentTweets(req *web.GetUserTweetsReq, isSelf bool) (*web.GetUserTweetsResp, mir.Error) { func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, user *cs.VistUser) (*web.GetUserTweetsResp, mir.Error) {
// TODO: add implement logic stars, totalRows, err := s.Ds.ListUserStarTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
resp := base.PageRespFrom(nil, req.Page, req.PageSize, 0)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) getUserHighlightTweets(req *web.GetUserTweetsReq, isSelf bool) (*web.GetUserTweetsResp, mir.Error) {
// TODO: add implement logic
resp := base.PageRespFrom(nil, req.Page, req.PageSize, 0)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) getUserMediaTweets(req *web.GetUserTweetsReq, isSelf bool) (*web.GetUserTweetsResp, mir.Error) {
// TODO: add implement logic
resp := base.PageRespFrom(nil, req.Page, req.PageSize, 0)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, isSelf bool) (*web.GetUserTweetsResp, mir.Error) {
if isSelf {
return s.getSelfStarTweets(req)
}
// TODO: add implement logic for not self star tweets
resp := base.PageRespFrom(nil, req.Page, req.PageSize, 0)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) getSelfCommentTweets(req *web.GetUserTweetsReq) (*web.GetUserTweetsResp, mir.Error) {
// TODO: add implement logic
resp := base.PageRespFrom(nil, req.Page, req.PageSize, 0)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) getSelfMediaTweets(req *web.GetUserTweetsReq) (*web.GetUserTweetsResp, mir.Error) {
// TODO: add implement logic
resp := base.PageRespFrom(nil, req.Page, req.PageSize, 0)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) getSelfStarTweets(req *web.GetUserTweetsReq) (*web.GetUserTweetsResp, mir.Error) {
stars, err := s.Ds.GetUserPostStars(req.User.ID, (req.Page-1)*req.PageSize, req.PageSize)
if err != nil {
logrus.Errorf("Ds.GetUserPostStars err: %s", err)
return nil, web.ErrGetStarsFailed
}
totalRows, err := s.Ds.GetUserPostStarCount(req.User.ID)
if err != nil { if err != nil {
logrus.Errorf("Ds.GetUserPostStars err: %s", err) logrus.Errorf("Ds.GetUserPostStars err: %s", err)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
} }
var posts []*ms.Post var posts []*ms.Post
for _, star := range stars { for _, star := range stars {
posts = append(posts, star.Post) if star.Post != nil {
posts = append(posts, star.Post)
}
} }
postsFormated, err := s.Ds.MergePosts(posts) postsFormated, err := s.Ds.MergePosts(posts)
if err != nil { if err != nil {
@ -143,28 +103,54 @@ func (s *looseSrv) getSelfStarTweets(req *web.GetUserTweetsReq) (*web.GetUserTwe
return (*web.GetUserTweetsResp)(resp), nil return (*web.GetUserTweetsResp)(resp), nil
} }
func (s *looseSrv) getUserPostTweets(req *web.GetUserTweetsReq) (*web.GetUserTweetsResp, mir.Error) { func (s *looseSrv) listUserTweets(req *web.GetUserTweetsReq, user *cs.VistUser) (*web.GetUserTweetsResp, mir.Error) {
other, xerr := s.GetUserProfile(&web.GetUserProfileReq{ var (
BaseInfo: req.BaseInfo, tweets []*ms.Post
Username: req.Username, total int64
}) err error
if xerr != nil { )
return nil, xerr fmt.Print(user, user.UserId, req.Style, req.PageSize, (req.Page-1)*req.PageSize)
if req.Style == web.UserPostsStyleComment {
tweets, total, err = s.Ds.ListUserCommentTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
} else if req.Style == web.UserPostsStyleMedia {
tweets, total, err = s.Ds.ListUserMediaTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
} else {
logrus.Errorf("s.listUserTweets unknow style: %s", req.Style)
return nil, web.ErrGetPostsFailed
} }
if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err)
return nil, web.ErrGetPostsFailed
}
postFormated, err := s.Ds.MergePosts(tweets)
if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := base.PageRespFrom(postFormated, req.Page, req.PageSize, total)
return (*web.GetUserTweetsResp)(resp), nil
}
func (s *looseSrv) getUserPostTweets(req *web.GetUserTweetsReq, user *cs.VistUser, isHighlight bool) (*web.GetUserTweetsResp, mir.Error) {
visibilities := []core.PostVisibleT{core.PostVisitPublic} visibilities := []core.PostVisibleT{core.PostVisitPublic}
if req.User != nil { switch user.RelTyp {
if req.User.ID == other.ID || req.User.IsAdmin { case cs.RelationAdmin, cs.RelationSelf:
visibilities = append(visibilities, core.PostVisitPrivate, core.PostVisitFriend) visibilities = append(visibilities, core.PostVisitPrivate, core.PostVisitFriend)
} else if other.IsFriend { case cs.RelationFriend:
visibilities = append(visibilities, core.PostVisitFriend) visibilities = append(visibilities, core.PostVisitFriend)
} case cs.RelationGuest:
fallthrough
default:
// nothing
} }
conditions := ms.ConditionsT{ conditions := ms.ConditionsT{
"user_id": other.ID, "user_id": user.UserId,
"visibility IN ?": visibilities, "visibility IN ?": visibilities,
"ORDER": "latest_replied_on DESC", "ORDER": "latest_replied_on DESC",
} }
if isHighlight {
conditions["is_essence"] = 1
}
_, posts, err := s.GetTweetList(conditions, (req.Page-1)*req.PageSize, req.PageSize) _, posts, err := s.GetTweetList(conditions, (req.Page-1)*req.PageSize, req.PageSize)
if err != nil { if err != nil {
logrus.Errorf("s.GetTweetList err: %s", err) logrus.Errorf("s.GetTweetList err: %s", err)
@ -175,7 +161,6 @@ func (s *looseSrv) getUserPostTweets(req *web.GetUserTweetsReq) (*web.GetUserTwe
logrus.Errorf("s.GetPostCount err: %s", err) logrus.Errorf("s.GetPostCount err: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
resp := base.PageRespFrom(posts, req.Page, req.PageSize, totalRows) resp := base.PageRespFrom(posts, req.Page, req.PageSize, totalRows)
return (*web.GetUserTweetsResp)(resp), nil return (*web.GetUserTweetsResp)(resp), nil
} }
@ -194,14 +179,26 @@ func (s *looseSrv) GetUserProfile(req *web.GetUserProfileReq) (*web.GetUserProfi
if req.User != nil && req.User.ID != he.ID { if req.User != nil && req.User.ID != he.ID {
isFriend = s.Ds.IsFriend(req.User.ID, he.ID) isFriend = s.Ds.IsFriend(req.User.ID, he.ID)
} }
isFollowing := false
if req.User != nil {
isFollowing = s.Ds.IsFollow(req.User.ID, he.ID)
}
follows, followings, err := s.Ds.GetFollowCount(he.ID)
if err != nil {
return nil, web.ErrGetPostsFailed
}
return &web.GetUserProfileResp{ return &web.GetUserProfileResp{
ID: he.ID, ID: he.ID,
Nickname: he.Nickname, Nickname: he.Nickname,
Username: he.Username, Username: he.Username,
Status: he.Status, Status: he.Status,
Avatar: he.Avatar, Avatar: he.Avatar,
IsAdmin: he.IsAdmin, IsAdmin: he.IsAdmin,
IsFriend: isFriend, IsFriend: isFriend,
IsFollowing: isFollowing,
CreatedOn: he.CreatedOn,
Follows: follows,
Followings: followings,
}, nil }, nil
} }

@ -634,9 +634,19 @@ func (s *privSrv) StickTweet(req *web.StickTweetReq) (*web.StickTweetResp, mir.E
}, nil }, nil
} }
func (s *privSrv) HighlightTweet(req *web.HighlightTweetReq) (*web.HighlightTweetResp, mir.Error) { func (s *privSrv) HighlightTweet(req *web.HighlightTweetReq) (res *web.HighlightTweetResp, err mir.Error) {
// TODO if status, xerr := s.Ds.HighlightPost(req.User.ID, req.ID); xerr == nil {
return nil, web.ErrNotImplemented res = &web.HighlightTweetResp{
HighlightStatus: status,
}
} else if xerr == cs.ErrNoPermission {
err = web.ErrNoPermission
logrus.Warnf("highlight tweet occurs no permision error with userId=%d postId=%d", req.User.ID, req.ID)
} else {
err = web.ErrHighlightPostFailed
logrus.Warnf("highlight tweet err: %s with userId=%d postId=%d", xerr, req.User.ID, req.ID)
}
return
} }
func (s *privSrv) LockTweet(req *web.LockTweetReq) (*web.LockTweetResp, mir.Error) { func (s *privSrv) LockTweet(req *web.LockTweetReq) (*web.LockTweetResp, mir.Error) {

@ -34,19 +34,13 @@ func RouteWeb(e *gin.Engine) {
api.RegisterPubServant(e, newPubSrv(ds)) api.RegisterPubServant(e, newPubSrv(ds))
api.RegisterKeyQueryServant(e, NewShareKeyServant(ds)) api.RegisterKeyQueryServant(e, NewShareKeyServant(ds))
api.RegisterRankServant(e, NewRankServant(ds)) api.RegisterRankServant(e, NewRankServant(ds))
api.RegisterFollowshipServant(e, newFollowshipSrv(ds))
api.RegisterFriendshipServant(e, newFriendshipSrv(ds))
// regster servants if needed by configure // regster servants if needed by configure
cfg.In(cfg.Actions{ cfg.Be("Alipay", func() {
"Alipay": func() { client := conf.MustAlipayClient()
client := conf.MustAlipayClient() api.RegisterAlipayPubServant(e, newAlipayPubSrv(ds))
api.RegisterAlipayPubServant(e, newAlipayPubSrv(ds)) api.RegisterAlipayPrivServant(e, newAlipayPrivSrv(ds, client))
api.RegisterAlipayPrivServant(e, newAlipayPrivSrv(ds, client))
},
"Followship": func() {
api.RegisterFollowshipServant(e, newFollowshipSrv(ds))
},
"Friendship": func() {
api.RegisterFriendshipServant(e, newFriendshipSrv(ds))
},
}) })
} }

@ -5,94 +5,11 @@
package main package main
import ( import (
"flag" "github.com/rocboss/paopao-ce/cmd"
"fmt" _ "github.com/rocboss/paopao-ce/cmd/migrate"
"os" _ "github.com/rocboss/paopao-ce/cmd/serve"
"os/signal"
"strings"
"syscall"
"time"
"github.com/alimy/cfg"
"github.com/fatih/color"
"github.com/getsentry/sentry-go"
"github.com/rocboss/paopao-ce/internal"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/service"
"github.com/rocboss/paopao-ce/pkg/debug"
"github.com/rocboss/paopao-ce/pkg/utils"
"github.com/rocboss/paopao-ce/pkg/version"
"github.com/sourcegraph/conc"
_ "go.uber.org/automaxprocs"
)
var (
noDefaultFeatures bool
features suites
) )
type suites []string
func (s *suites) String() string {
return strings.Join(*s, ",")
}
func (s *suites) Set(value string) error {
for _, item := range strings.Split(value, ",") {
*s = append(*s, strings.TrimSpace(item))
}
return nil
}
func init() {
flagParse()
conf.Initial(features, noDefaultFeatures)
internal.Initial()
}
func deferFn() {
if cfg.If("Sentry") {
// Flush buffered events before the program terminates.
sentry.Flush(2 * time.Second)
}
}
func flagParse() {
flag.BoolVar(&noDefaultFeatures, "no-default-features", false, "whether not use default features")
flag.Var(&features, "features", "use special features")
flag.Parse()
}
func main() { func main() {
utils.PrintHelloBanner(version.VersionInfo()) cmd.Execute()
ss := service.MustInitService()
if len(ss) < 1 {
fmt.Fprintln(color.Output, "no service need start so just exit")
return
}
// do defer function
defer deferFn()
// start pyroscope if need
debug.StartPyroscope()
// start services
wg := conc.NewWaitGroup()
fmt.Fprintf(color.Output, "\nstarting run service...\n\n")
service.Start(wg)
// graceful stop services
wg.Go(func() {
quit := make(chan os.Signal, 1)
// kill (no param) default send syscall.SIGTERM
// kill -2 is syscall.SIGINT
// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
fmt.Fprintf(color.Output, "\nshutting down server...\n\n")
service.Stop()
})
wg.Wait()
} }

@ -15,15 +15,15 @@ type Followship struct {
Chain `mir:"-"` Chain `mir:"-"`
Group `mir:"v1"` Group `mir:"v1"`
// AddFollowing 添加关注 // FollowUser 关注用户
AddFollowing func(Post, web.AddFollowingReq) `mir:"/following/add"` FollowUser func(Post, web.FollowUserReq) `mir:"/user/follow"`
// DeleteFollowing 取消关注 // UnfollowUser 取消关注用户
DeleteFollowing func(Post, web.DeleteFollowingReq) `mir:"/following/delete"` UnfollowUser func(Post, web.UnfollowUserReq) `mir:"/user/unfollow"`
// ListFollowings 获取用户的关注列表 // ListFollows 获取用户的关注列表
ListFollowings func(Get, web.ListFollowingsReq) web.ListFollowingsResp `mir:"/following/list"` ListFollows func(Get, web.ListFollowsReq) web.ListFollowsResp `mir:"/user/follows"`
// ListFollowers 获取用户的追随者列表 // ListFollowings 获取用户的追随者列表
ListFollowers func(Get, web.ListFollowersReq) web.ListFollowersResp `mir:"/follower/list"` ListFollowings func(Get, web.ListFollowingsReq) web.ListFollowingsResp `mir:"/user/followings"`
} }

@ -21,6 +21,9 @@ func VersionInfo() string {
} }
func ReadBuildInfo() *BuildInfo { func ReadBuildInfo() *BuildInfo {
if version == "" {
version = "unknow"
}
return &BuildInfo{ return &BuildInfo{
Version: version, Version: version,
Sum: commitID, Sum: commitID,

@ -1,3 +1,3 @@
ALTER TABLE `p_post_content` MODIFY COLUMN `content` varchar(65535) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容'; ALTER TABLE `p_post_content` MODIFY COLUMN `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容';
ALTER TABLE `p_comment_content` MODIFY COLUMN `content` varchar(65535) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容'; ALTER TABLE `p_comment_content` MODIFY COLUMN `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容';
ALTER TABLE `p_comment_reply` MODIFY COLUMN `content` varchar(65535) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容'; ALTER TABLE `p_comment_reply` MODIFY COLUMN `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容';

@ -0,0 +1,5 @@
DROP VIEW IF EXISTS p_post_by_media;
DROP VIEW IF EXISTS p_post_by_comment;

@ -0,0 +1,32 @@
CREATE VIEW p_post_by_media AS
SELECT post.*
FROM
( SELECT DISTINCT post_id FROM p_post_content WHERE ( TYPE = 3 OR TYPE = 4 OR TYPE = 7 OR TYPE = 8 ) AND is_del = 0 ) media
JOIN p_post post ON media.post_id = post.ID
WHERE
post.is_del = 0;
CREATE VIEW p_post_by_comment AS
SELECT P.*, C.user_id comment_user_id
FROM
(
SELECT
post_id,
user_id
FROM
p_comment
WHERE
is_del = 0 UNION
SELECT
post_id,
reply.user_id user_id
FROM
p_comment_reply reply
JOIN p_comment COMMENT ON reply.comment_id = COMMENT.ID
WHERE
reply.is_del = 0
AND COMMENT.is_del = 0
)
C JOIN p_post P ON C.post_id = P.ID
WHERE
P.is_del = 0;

@ -0,0 +1 @@
DROP TABLE IF EXISTS `p_following`;

@ -0,0 +1,11 @@
CREATE TABLE `p_following` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`follow_id` bigint unsigned NOT NULL,
`is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_following_user_follow` (`user_id`,`follow_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

@ -0,0 +1,5 @@
DROP VIEW IF EXISTS p_post_by_media;
DROP VIEW IF EXISTS p_post_by_comment;

@ -0,0 +1,32 @@
CREATE VIEW p_post_by_media AS
SELECT post.*
FROM
( SELECT DISTINCT post_id FROM p_post_content WHERE ( TYPE = 3 OR TYPE = 4 OR TYPE = 7 OR TYPE = 8 ) AND is_del = 0 ) media
JOIN p_post post ON media.post_id = post.ID
WHERE
post.is_del = 0;
CREATE VIEW p_post_by_comment AS
SELECT P.*, C.user_id comment_user_id
FROM
(
SELECT
post_id,
user_id
FROM
p_comment
WHERE
is_del = 0 UNION
SELECT
post_id,
reply.user_id user_id
FROM
p_comment_reply reply
JOIN p_comment COMMENT ON reply.comment_id = COMMENT.ID
WHERE
reply.is_del = 0
AND COMMENT.is_del = 0
)
C JOIN p_post P ON C.post_id = P.ID
WHERE
P.is_del = 0;

@ -0,0 +1 @@
DROP TABLE IF EXISTS p_following;

@ -0,0 +1,10 @@
CREATE TABLE p_following (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
follow_id BIGINT NOT NULL,
is_del SMALLINT NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_following_user_follow ON p_following USING btree (user_id, follow_id);

@ -0,0 +1,5 @@
DROP VIEW IF EXISTS p_post_by_media;
DROP VIEW IF EXISTS p_post_by_comment;

@ -0,0 +1,32 @@
CREATE VIEW p_post_by_media AS
SELECT post.*
FROM
( SELECT DISTINCT post_id FROM p_post_content WHERE ( TYPE = 3 OR TYPE = 4 OR TYPE = 7 OR TYPE = 8 ) AND is_del = 0 ) media
JOIN p_post post ON media.post_id = post.ID
WHERE
post.is_del = 0;
CREATE VIEW p_post_by_comment AS
SELECT P.*, C.user_id comment_user_id
FROM
(
SELECT
post_id,
user_id
FROM
p_comment
WHERE
is_del = 0 UNION
SELECT
post_id,
reply.user_id user_id
FROM
p_comment_reply reply
JOIN p_comment COMMENT ON reply.comment_id = COMMENT.ID
WHERE
reply.is_del = 0
AND COMMENT.is_del = 0
)
C JOIN p_post P ON C.post_id = P.ID
WHERE
P.is_del = 0;

@ -0,0 +1 @@
DROP TABLE IF EXISTS "p_following";

@ -0,0 +1,15 @@
CREATE TABLE "p_following" (
"id" integer NOT NULL,
"user_id" integer NOT NULL,
"follow_id" integer NOT NULL,
"is_del" integer NOT NULL,
"created_on" integer NOT NULL,
"modified_on" integer NOT NULL,
"deleted_on" integer NOT NULL,
PRIMARY KEY ("id")
);
CREATE INDEX "idx_following_user_follow"
ON "p_following" (
"user_id" ASC,
"follow_id" ASC
);

@ -70,7 +70,7 @@ CREATE TABLE `p_comment_content` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID', `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID', `comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`content` varchar(65535) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容', `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容',
`type` tinyint unsigned NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址', `type` tinyint unsigned NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址',
`sort` bigint unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前', `sort` bigint unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
@ -93,7 +93,7 @@ CREATE TABLE `p_comment_reply` (
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID', `comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`at_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '@用户ID', `at_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '@用户ID',
`content` varchar(65535) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容', `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容',
`ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址', `ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址',
`ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址', `ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址',
`thumbs_up_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点赞数', `thumbs_up_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点赞数',
@ -224,7 +224,7 @@ CREATE TABLE `p_post_content` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID', `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID', `post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`content` varchar(65535) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容', `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容',
`type` tinyint unsigned NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址7附件资源8收费资源', `type` tinyint unsigned NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址7附件资源8收费资源',
`sort` int unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前', `sort` int unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
@ -318,6 +318,22 @@ CREATE TABLE `p_user` (
KEY `idx_user_phone` (`phone`) USING BTREE KEY `idx_user_phone` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=100058 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户'; ) ENGINE=InnoDB AUTO_INCREMENT=100058 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户';
-- ----------------------------
-- Table structure for p_following
-- ----------------------------
DROP TABLE IF EXISTS `p_following`;
CREATE TABLE `p_following` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`follow_id` bigint unsigned NOT NULL,
`is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_following_user_follow` (`user_id`,`follow_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ---------------------------- -- ----------------------------
-- Table structure for p_contact -- Table structure for p_contact
-- ---------------------------- -- ----------------------------
@ -395,4 +411,39 @@ CREATE TABLE `p_wallet_statement` (
KEY `idx_wallet_statement_user_id` (`user_id`) USING BTREE KEY `idx_wallet_statement_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10010 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='钱包流水'; ) ENGINE=InnoDB AUTO_INCREMENT=10010 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='钱包流水';
DROP VIEW IF EXISTS p_post_by_media;
CREATE VIEW p_post_by_media AS
SELECT post.*
FROM
( SELECT DISTINCT post_id FROM p_post_content WHERE ( TYPE = 3 OR TYPE = 4 OR TYPE = 7 OR TYPE = 8 ) AND is_del = 0 ) media
JOIN p_post post ON media.post_id = post.ID
WHERE
post.is_del = 0;
DROP VIEW IF EXISTS p_post_by_comment;
CREATE VIEW p_post_by_comment AS
SELECT P.*, C.user_id comment_user_id
FROM
(
SELECT
post_id,
user_id
FROM
p_comment
WHERE
is_del = 0 UNION
SELECT
post_id,
reply.user_id user_id
FROM
p_comment_reply reply
JOIN p_comment COMMENT ON reply.comment_id = COMMENT.ID
WHERE
reply.is_del = 0
AND COMMENT.is_del = 0
)
C JOIN p_post P ON C.post_id = P.ID
WHERE
P.is_del = 0;
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;

@ -265,6 +265,18 @@ CREATE TABLE p_user (
CREATE UNIQUE INDEX idx_user_username ON p_user USING btree (username); CREATE UNIQUE INDEX idx_user_username ON p_user USING btree (username);
CREATE INDEX idx_user_phone ON p_user USING btree (phone); CREATE INDEX idx_user_phone ON p_user USING btree (phone);
DROP TABLE IF EXISTS p_following;
CREATE TABLE p_following (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
follow_id BIGINT NOT NULL,
is_del SMALLINT NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_following_user_follow ON p_following USING btree (user_id, follow_id);
DROP TABLE IF EXISTS p_contact; DROP TABLE IF EXISTS p_contact;
CREATE TABLE p_contact ( CREATE TABLE p_contact (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -325,3 +337,38 @@ CREATE TABLE p_wallet_statement (
is_del SMALLINT NOT NULL DEFAULT 0 is_del SMALLINT NOT NULL DEFAULT 0
); );
CREATE INDEX idx_wallet_statement_user_id ON p_wallet_statement USING btree (user_id); CREATE INDEX idx_wallet_statement_user_id ON p_wallet_statement USING btree (user_id);
DROP VIEW IF EXISTS p_post_by_media;
CREATE VIEW p_post_by_media AS
SELECT post.*
FROM
( SELECT DISTINCT post_id FROM p_post_content WHERE ( TYPE = 3 OR TYPE = 4 OR TYPE = 7 OR TYPE = 8 ) AND is_del = 0 ) media
JOIN p_post post ON media.post_id = post.ID
WHERE
post.is_del = 0;
DROP VIEW IF EXISTS p_post_by_comment;
CREATE VIEW p_post_by_comment AS
SELECT P.*, C.user_id comment_user_id
FROM
(
SELECT
post_id,
user_id
FROM
p_comment
WHERE
is_del = 0 UNION
SELECT
post_id,
reply.user_id user_id
FROM
p_comment_reply reply
JOIN p_comment COMMENT ON reply.comment_id = COMMENT.ID
WHERE
reply.is_del = 0
AND COMMENT.is_del = 0
)
C JOIN p_post P ON C.post_id = P.ID
WHERE
P.is_del = 0;

@ -113,6 +113,21 @@ CREATE TABLE "p_tweet_comment_thumbs" (
"is_del" integer NOT NULL DEFAULT 0 -- 是否删除 0 为未删除、1 为已删除 "is_del" integer NOT NULL DEFAULT 0 -- 是否删除 0 为未删除、1 为已删除
); );
-- ----------------------------
-- Table structure for p_following
-- ----------------------------
DROP TABLE IF EXISTS "p_following";
CREATE TABLE "p_following" (
"id" integer NOT NULL,
"user_id" integer NOT NULL,
"follow_id" integer NOT NULL,
"is_del" integer NOT NULL,
"created_on" integer NOT NULL,
"modified_on" integer NOT NULL,
"deleted_on" integer NOT NULL,
PRIMARY KEY ("id")
);
-- ---------------------------- -- ----------------------------
-- Table structure for p_contact -- Table structure for p_contact
-- ---------------------------- -- ----------------------------
@ -356,6 +371,41 @@ CREATE TABLE "p_wallet_statement" (
PRIMARY KEY ("id") PRIMARY KEY ("id")
); );
DROP VIEW IF EXISTS p_post_by_media;
CREATE VIEW p_post_by_media AS
SELECT post.*
FROM
( SELECT DISTINCT post_id FROM p_post_content WHERE ( TYPE = 3 OR TYPE = 4 OR TYPE = 7 OR TYPE = 8 ) AND is_del = 0 ) media
JOIN p_post post ON media.post_id = post.ID
WHERE
post.is_del = 0;
DROP VIEW IF EXISTS p_post_by_comment;
CREATE VIEW p_post_by_comment AS
SELECT P.*, C.user_id comment_user_id
FROM
(
SELECT
post_id,
user_id
FROM
p_comment
WHERE
is_del = 0 UNION
SELECT
post_id,
reply.user_id user_id
FROM
p_comment_reply reply
JOIN p_comment COMMENT ON reply.comment_id = COMMENT.ID
WHERE
reply.is_del = 0
AND COMMENT.is_del = 0
)
C JOIN p_post P ON C.post_id = P.ID
WHERE
P.is_del = 0;
-- ---------------------------- -- ----------------------------
-- Indexes structure for table p_attachment -- Indexes structure for table p_attachment
-- ---------------------------- -- ----------------------------
@ -429,6 +479,15 @@ ON "p_tweet_comment_thumbs"(
"tweet_id" ASC "tweet_id" ASC
); );
-- ----------------------------
-- Indexes structure for table p_following
-- ----------------------------
CREATE INDEX "idx_following_user_follow"
ON "p_following" (
"user_id" ASC,
"follow_id" ASC
);
-- ---------------------------- -- ----------------------------
-- Indexes structure for table p_contact -- Indexes structure for table p_contact
-- ---------------------------- -- ----------------------------

@ -1 +1 @@
import{_ as s}from"./main-nav.vue_vue_type_style_index_0_lang-18d4a8d3.js";import{u as a}from"./vue-router-b8e3382f.js";import{F as i,e as c,a2 as u}from"./naive-ui-62663ad7.js";import{d as l,c as d,V as t,a1 as o,o as f,e as x}from"./@vue-e0e89260.js";import{_ as g}from"./index-08d8af97.js";import"./vuex-473b3783.js";import"./vooks-a50491fd.js";import"./evtd-b614532e.js";import"./@vicons-6332ad63.js";import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./@css-render-580d83ec.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";/* empty css */const v=l({__name:"404",setup(h){const e=a(),_=()=>{e.push({path:"/"})};return(k,w)=>{const n=s,p=c,r=u,m=i;return f(),d("div",null,[t(n,{title:"404"}),t(m,{class:"main-content-wrap wrap404",bordered:""},{default:o(()=>[t(r,{status:"404",title:"404 资源不存在",description:"再看看其他的吧"},{footer:o(()=>[t(p,{onClick:_},{default:o(()=>[x("回主页")]),_:1})]),_:1})]),_:1})])}}});const M=g(v,[["__scopeId","data-v-e62daa85"]]);export{M as default}; import{_ as s}from"./main-nav.vue_vue_type_style_index_0_lang-32d416c3.js";import{u as a}from"./vue-router-b8e3382f.js";import{F as i,e as c,a2 as u}from"./naive-ui-62663ad7.js";import{d as l,c as d,V as t,a1 as o,o as f,e as x}from"./@vue-e0e89260.js";import{_ as g}from"./index-152c5794.js";import"./vuex-473b3783.js";import"./vooks-a50491fd.js";import"./evtd-b614532e.js";import"./@vicons-0524c43e.js";import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./@css-render-580d83ec.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";/* empty css */const v=l({__name:"404",setup(h){const e=a(),_=()=>{e.push({path:"/"})};return(k,w)=>{const n=s,p=c,r=u,m=i;return f(),d("div",null,[t(n,{title:"404"}),t(m,{class:"main-content-wrap wrap404",bordered:""},{default:o(()=>[t(r,{status:"404",title:"404 资源不存在",description:"再看看其他的吧"},{footer:o(()=>[t(p,{onClick:_},{default:o(()=>[x("回主页")]),_:1})]),_:1})]),_:1})])}}});const M=g(v,[["__scopeId","data-v-e62daa85"]]);export{M as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{_ as F}from"./post-skeleton-41befd31.js";import{_ as N}from"./main-nav.vue_vue_type_style_index_0_lang-18d4a8d3.js";import{u as V}from"./vuex-473b3783.js";import{b as z}from"./vue-router-b8e3382f.js";import{a as A}from"./formatTime-cdf4e6f1.js";import{d as R,r as n,j as S,c as o,V as a,a1 as p,o as e,_ as u,O as l,F as I,a4 as L,Q as M,a as s,M as _,L as O}from"./@vue-e0e89260.js";import{F as P,G as j,I as q,H as D}from"./naive-ui-62663ad7.js";import{_ as E}from"./index-08d8af97.js";import"./vooks-a50491fd.js";import"./evtd-b614532e.js";import"./@vicons-6332ad63.js";import"./moment-2ab8298d.js";import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./@css-render-580d83ec.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";/* empty css */const G={key:0,class:"pagination-wrap"},H={key:0,class:"skeleton-wrap"},Q={key:1},T={key:0,class:"empty-wrap"},U={class:"bill-line"},$=R({__name:"Anouncement",setup(J){const d=V(),g=z(),v=n(!1),r=n([]),i=n(+g.query.p||1),f=n(20),c=n(0),h=m=>{i.value=m};return S(()=>{}),(m,K)=>{const y=N,k=j,x=F,w=q,B=D,C=P;return e(),o("div",null,[a(y,{title:"公告"}),a(C,{class:"main-content-wrap",bordered:""},{footer:p(()=>[c.value>1?(e(),o("div",G,[a(k,{page:i.value,"onUpdate:page":h,"page-slot":u(d).state.collapsedRight?5:8,"page-count":c.value},null,8,["page","page-slot","page-count"])])):l("",!0)]),default:p(()=>[v.value?(e(),o("div",H,[a(x,{num:f.value},null,8,["num"])])):(e(),o("div",Q,[r.value.length===0?(e(),o("div",T,[a(w,{size:"large",description:"暂无数据"})])):l("",!0),(e(!0),o(I,null,L(r.value,t=>(e(),M(B,{key:t.id},{default:p(()=>[s("div",U,[s("div",null,"NO."+_(t.id),1),s("div",null,_(t.reason),1),s("div",{class:O({income:t.change_amount>=0,out:t.change_amount<0})},_((t.change_amount>0?"+":"")+(t.change_amount/100).toFixed(2)),3),s("div",null,_(u(A)(t.created_on)),1)])]),_:2},1024))),128))]))]),_:1})])}}});const kt=E($,[["__scopeId","data-v-d4d04859"]]);export{kt as default}; import{_ as F}from"./post-skeleton-d2e839d6.js";import{_ as N}from"./main-nav.vue_vue_type_style_index_0_lang-32d416c3.js";import{u as V}from"./vuex-473b3783.js";import{b as z}from"./vue-router-b8e3382f.js";import{a as A}from"./formatTime-4210fcd1.js";import{d as R,r as n,j as S,c as o,V as a,a1 as p,o as e,_ as u,O as l,F as I,a4 as L,Q as M,a as s,M as _,L as O}from"./@vue-e0e89260.js";import{F as P,G as j,I as q,H as D}from"./naive-ui-62663ad7.js";import{_ as E}from"./index-152c5794.js";import"./vooks-a50491fd.js";import"./evtd-b614532e.js";import"./@vicons-0524c43e.js";import"./moment-2ab8298d.js";import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./@css-render-580d83ec.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";/* empty css */const G={key:0,class:"pagination-wrap"},H={key:0,class:"skeleton-wrap"},Q={key:1},T={key:0,class:"empty-wrap"},U={class:"bill-line"},$=R({__name:"Anouncement",setup(J){const d=V(),g=z(),v=n(!1),r=n([]),i=n(+g.query.p||1),f=n(20),c=n(0),h=m=>{i.value=m};return S(()=>{}),(m,K)=>{const y=N,k=j,x=F,w=q,B=D,C=P;return e(),o("div",null,[a(y,{title:"公告"}),a(C,{class:"main-content-wrap",bordered:""},{footer:p(()=>[c.value>1?(e(),o("div",G,[a(k,{page:i.value,"onUpdate:page":h,"page-slot":u(d).state.collapsedRight?5:8,"page-count":c.value},null,8,["page","page-slot","page-count"])])):l("",!0)]),default:p(()=>[v.value?(e(),o("div",H,[a(x,{num:f.value},null,8,["num"])])):(e(),o("div",Q,[r.value.length===0?(e(),o("div",T,[a(w,{size:"large",description:"暂无数据"})])):l("",!0),(e(!0),o(I,null,L(r.value,t=>(e(),M(B,{key:t.id},{default:p(()=>[s("div",U,[s("div",null,"NO."+_(t.id),1),s("div",null,_(t.reason),1),s("div",{class:O({income:t.change_amount>=0,out:t.change_amount<0})},_((t.change_amount>0?"+":"")+(t.change_amount/100).toFixed(2)),3),s("div",null,_(u(A)(t.created_on)),1)])]),_:2},1024))),128))]))]),_:1})])}}});const kt=E($,[["__scopeId","data-v-d4d04859"]]);export{kt as default};

@ -0,0 +1 @@
import{_ as N,a as P}from"./post-item.vue_vue_type_style_index_0_lang-25504051.js";import{_ as S}from"./post-skeleton-d2e839d6.js";import{_ as V}from"./main-nav.vue_vue_type_style_index_0_lang-32d416c3.js";import{u as $}from"./vuex-473b3783.js";import{b as I}from"./vue-router-b8e3382f.js";import{N as R,_ as j}from"./index-152c5794.js";import{d as q,r as s,j as E,c as o,V as e,a1 as c,_ as g,O as v,o as t,F as f,a4 as h,Q as k}from"./@vue-e0e89260.js";import{F as G,G as H,I as L,H as O}from"./naive-ui-62663ad7.js";import"./content-ff44e340.js";import"./@vicons-0524c43e.js";import"./paopao-video-player-aa5e8b3f.js";import"./formatTime-4210fcd1.js";import"./moment-2ab8298d.js";import"./copy-to-clipboard-1dd3075d.js";import"./toggle-selection-93f4ad84.js";import"./vooks-a50491fd.js";import"./evtd-b614532e.js";import"./axios-4a70c6fc.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./@css-render-580d83ec.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const Q={key:0,class:"skeleton-wrap"},T={key:1},U={key:0,class:"empty-wrap"},A={key:1},D={key:2},J={key:0,class:"pagination-wrap"},K=q({__name:"Collection",setup(W){const m=$(),y=I(),_=s(!1),i=s([]),p=s(+y.query.p||1),l=s(20),r=s(0),u=()=>{_.value=!0,R({page:p.value,page_size:l.value}).then(n=>{_.value=!1,i.value=n.list,r.value=Math.ceil(n.pager.total_rows/l.value),window.scrollTo(0,0)}).catch(n=>{_.value=!1})},w=n=>{p.value=n,u()};return E(()=>{u()}),(n,X)=>{const C=V,b=S,x=L,z=N,d=O,B=P,F=G,M=H;return t(),o("div",null,[e(C,{title:"收藏"}),e(F,{class:"main-content-wrap",bordered:""},{default:c(()=>[_.value?(t(),o("div",Q,[e(b,{num:l.value},null,8,["num"])])):(t(),o("div",T,[i.value.length===0?(t(),o("div",U,[e(x,{size:"large",description:"暂无数据"})])):v("",!0),g(m).state.desktopModelShow?(t(),o("div",A,[(t(!0),o(f,null,h(i.value,a=>(t(),k(d,{key:a.id},{default:c(()=>[e(z,{post:a},null,8,["post"])]),_:2},1024))),128))])):(t(),o("div",D,[(t(!0),o(f,null,h(i.value,a=>(t(),k(d,{key:a.id},{default:c(()=>[e(B,{post:a},null,8,["post"])]),_:2},1024))),128))]))]))]),_:1}),r.value>0?(t(),o("div",J,[e(M,{page:p.value,"onUpdate:page":w,"page-slot":g(m).state.collapsedRight?5:8,"page-count":r.value},null,8,["page","page-slot","page-count"])])):v("",!0)])}}});const Mt=j(K,[["__scopeId","data-v-a5302c9b"]]);export{Mt as default};

@ -1 +0,0 @@
import{_ as P,a as S}from"./post-item.vue_vue_type_style_index_0_lang-3baf8ba8.js";import{_ as V}from"./post-skeleton-41befd31.js";import{_ as $}from"./main-nav.vue_vue_type_style_index_0_lang-18d4a8d3.js";import{u as I}from"./vuex-473b3783.js";import{b as L}from"./vue-router-b8e3382f.js";import{L as N,_ as R}from"./index-08d8af97.js";import{d as j,r as s,j as q,c as o,V as e,a1 as c,_ as g,O as v,o as t,F as f,a4 as h,Q as k}from"./@vue-e0e89260.js";import{F as E,G,I as H,H as O}from"./naive-ui-62663ad7.js";import"./content-91ba374b.js";import"./@vicons-6332ad63.js";import"./paopao-video-player-aa5e8b3f.js";import"./formatTime-cdf4e6f1.js";import"./moment-2ab8298d.js";import"./copy-to-clipboard-1dd3075d.js";import"./toggle-selection-93f4ad84.js";import"./vooks-a50491fd.js";import"./evtd-b614532e.js";import"./axios-4a70c6fc.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./@css-render-580d83ec.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const Q={key:0,class:"skeleton-wrap"},T={key:1},U={key:0,class:"empty-wrap"},A={key:1},D={key:2},J={key:0,class:"pagination-wrap"},K=j({__name:"Collection",setup(W){const m=I(),y=L(),_=s(!1),i=s([]),p=s(+y.query.p||1),l=s(20),r=s(0),u=()=>{_.value=!0,N({page:p.value,page_size:l.value}).then(n=>{_.value=!1,i.value=n.list,r.value=Math.ceil(n.pager.total_rows/l.value),window.scrollTo(0,0)}).catch(n=>{_.value=!1})},w=n=>{p.value=n,u()};return q(()=>{u()}),(n,X)=>{const C=$,b=V,x=H,z=P,d=O,B=S,F=E,M=G;return t(),o("div",null,[e(C,{title:"收藏"}),e(F,{class:"main-content-wrap",bordered:""},{default:c(()=>[_.value?(t(),o("div",Q,[e(b,{num:l.value},null,8,["num"])])):(t(),o("div",T,[i.value.length===0?(t(),o("div",U,[e(x,{size:"large",description:"暂无数据"})])):v("",!0),g(m).state.desktopModelShow?(t(),o("div",A,[(t(!0),o(f,null,h(i.value,a=>(t(),k(d,{key:a.id},{default:c(()=>[e(z,{post:a},null,8,["post"])]),_:2},1024))),128))])):(t(),o("div",D,[(t(!0),o(f,null,h(i.value,a=>(t(),k(d,{key:a.id},{default:c(()=>[e(B,{post:a},null,8,["post"])]),_:2},1024))),128))]))]))]),_:1}),r.value>0?(t(),o("div",J,[e(M,{page:p.value,"onUpdate:page":w,"page-slot":g(m).state.collapsedRight?5:8,"page-count":r.value},null,8,["page","page-slot","page-count"])])):v("",!0)])}}});const Mt=R(K,[["__scopeId","data-v-a5302c9b"]]);export{Mt as default};

@ -1 +0,0 @@
import{u as N,b as P}from"./vue-router-b8e3382f.js";import{d as k,o as e,c as n,a as s,V as a,M as d,r as c,j as R,a1 as f,_ as S,O as h,F as y,a4 as U,Q as q}from"./@vue-e0e89260.js";import{o as x,F as D,G as O,I as T,H as j}from"./naive-ui-62663ad7.js";import{_ as b,O as E}from"./index-08d8af97.js";import{_ as G}from"./post-skeleton-41befd31.js";import{_ as H}from"./main-nav.vue_vue_type_style_index_0_lang-18d4a8d3.js";import{u as L}from"./vuex-473b3783.js";import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./evtd-b614532e.js";import"./@css-render-580d83ec.js";import"./vooks-a50491fd.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";import"./@vicons-6332ad63.js";/* empty css */const Q={class:"avatar"},A={class:"base-info"},J={class:"username"},K={class:"uid"},W=k({__name:"contact-item",props:{contact:{}},setup(C){const l=N(),u=t=>{l.push({name:"user",query:{username:t}})};return(t,o)=>{const _=x;return e(),n("div",{class:"contact-item",onClick:o[0]||(o[0]=r=>u(t.contact.username))},[s("div",Q,[a(_,{size:"large",src:t.contact.avatar},null,8,["src"])]),s("div",A,[s("div",J,[s("strong",null,d(t.contact.nickname),1),s("span",null," @"+d(t.contact.username),1)]),s("div",K,"UID. "+d(t.contact.user_id),1)])])}}});const X=b(W,[["__scopeId","data-v-08ee9b2e"]]),Y={key:0,class:"skeleton-wrap"},Z={key:1},tt={key:0,class:"empty-wrap"},et={key:0,class:"pagination-wrap"},ot=k({__name:"Contacts",setup(C){const l=L(),u=P(),t=c(!1),o=c([]),_=c(+u.query.p||1),r=c(20),m=c(0),w=i=>{_.value=i,v()};R(()=>{v()});const v=(i=!1)=>{o.value.length===0&&(t.value=!0),E({page:_.value,page_size:r.value}).then(p=>{t.value=!1,o.value=p.list,m.value=Math.ceil(p.pager.total_rows/r.value),i&&setTimeout(()=>{window.scrollTo(0,99999)},50)}).catch(p=>{t.value=!1})};return(i,p)=>{const $=H,I=G,z=T,B=X,V=j,F=D,M=O;return e(),n(y,null,[s("div",null,[a($,{title:"好友"}),a(F,{class:"main-content-wrap",bordered:""},{default:f(()=>[t.value?(e(),n("div",Y,[a(I,{num:r.value},null,8,["num"])])):(e(),n("div",Z,[o.value.length===0?(e(),n("div",tt,[a(z,{size:"large",description:"暂无数据"})])):h("",!0),(e(!0),n(y,null,U(o.value,g=>(e(),q(V,{key:g.user_id},{default:f(()=>[a(B,{contact:g},null,8,["contact"])]),_:2},1024))),128))]))]),_:1})]),m.value>0?(e(),n("div",et,[a(M,{page:_.value,"onUpdate:page":w,"page-slot":S(l).state.collapsedRight?5:8,"page-count":m.value},null,8,["page","page-slot","page-count"])])):h("",!0)],64)}}});const zt=b(ot,[["__scopeId","data-v-3b2bf978"]]);export{zt as default};

@ -0,0 +1 @@
.contact-item[data-v-0f1bf4ae]{display:flex;width:100%;padding:12px 16px}.contact-item[data-v-0f1bf4ae]:hover{background:#f7f9f9;cursor:pointer}.contact-item .avatar[data-v-0f1bf4ae]{width:55px}.contact-item .base-info[data-v-0f1bf4ae]{position:relative;width:calc(100% - 55px)}.contact-item .base-info .username[data-v-0f1bf4ae]{line-height:16px;font-size:16px}.contact-item .base-info .uid[data-v-0f1bf4ae]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.dark .contact-item[data-v-0f1bf4ae]{background-color:#101014bf}.dark .contact-item[data-v-0f1bf4ae]:hover{background:#18181c}.pagination-wrap[data-v-3b2bf978]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .main-content-wrap[data-v-3b2bf978],.dark .empty-wrap[data-v-3b2bf978],.dark .skeleton-wrap[data-v-3b2bf978]{background-color:#101014bf}

@ -1 +0,0 @@
.contact-item[data-v-08ee9b2e]{display:flex;width:100%;padding:12px 16px}.contact-item[data-v-08ee9b2e]:hover{background:#f7f9f9;cursor:pointer}.contact-item .avatar[data-v-08ee9b2e]{width:55px}.contact-item .base-info[data-v-08ee9b2e]{position:relative;width:calc(100% - 55px)}.contact-item .base-info .username[data-v-08ee9b2e]{line-height:16px;font-size:16px}.contact-item .base-info .uid[data-v-08ee9b2e]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.dark .contact-item[data-v-08ee9b2e]{background-color:#101014bf}.dark .contact-item[data-v-08ee9b2e]:hover{background:#18181c}.pagination-wrap[data-v-3b2bf978]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .main-content-wrap[data-v-3b2bf978],.dark .empty-wrap[data-v-3b2bf978],.dark .skeleton-wrap[data-v-3b2bf978]{background-color:#101014bf}

@ -0,0 +1 @@
import{u as N,b as P}from"./vue-router-b8e3382f.js";import{d as k,o as e,c as n,a as s,V as a,M as d,r as c,j as R,a1 as f,_ as S,O as h,F as y,a4 as U,Q as q}from"./@vue-e0e89260.js";import{o as x,F as D,G as Q,I as T,H as j}from"./naive-ui-62663ad7.js";import{_ as b,Q as E}from"./index-152c5794.js";import{_ as G}from"./post-skeleton-d2e839d6.js";import{_ as H}from"./main-nav.vue_vue_type_style_index_0_lang-32d416c3.js";import{u as L}from"./vuex-473b3783.js";import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./evtd-b614532e.js";import"./@css-render-580d83ec.js";import"./vooks-a50491fd.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";import"./@vicons-0524c43e.js";/* empty css */const O={class:"avatar"},A={class:"base-info"},J={class:"username"},K={class:"uid"},W=k({__name:"contact-item",props:{contact:{}},setup(C){const l=N(),u=t=>{l.push({name:"user",query:{s:t}})};return(t,o)=>{const _=x;return e(),n("div",{class:"contact-item",onClick:o[0]||(o[0]=r=>u(t.contact.username))},[s("div",O,[a(_,{size:"large",src:t.contact.avatar},null,8,["src"])]),s("div",A,[s("div",J,[s("strong",null,d(t.contact.nickname),1),s("span",null," @"+d(t.contact.username),1)]),s("div",K,"UID. "+d(t.contact.user_id),1)])])}}});const X=b(W,[["__scopeId","data-v-0f1bf4ae"]]),Y={key:0,class:"skeleton-wrap"},Z={key:1},tt={key:0,class:"empty-wrap"},et={key:0,class:"pagination-wrap"},ot=k({__name:"Contacts",setup(C){const l=L(),u=P(),t=c(!1),o=c([]),_=c(+u.query.p||1),r=c(20),m=c(0),w=i=>{_.value=i,v()};R(()=>{v()});const v=(i=!1)=>{o.value.length===0&&(t.value=!0),E({page:_.value,page_size:r.value}).then(p=>{t.value=!1,o.value=p.list,m.value=Math.ceil(p.pager.total_rows/r.value),i&&setTimeout(()=>{window.scrollTo(0,99999)},50)}).catch(p=>{t.value=!1})};return(i,p)=>{const $=H,I=G,z=T,B=X,V=j,F=D,M=Q;return e(),n(y,null,[s("div",null,[a($,{title:"好友"}),a(F,{class:"main-content-wrap",bordered:""},{default:f(()=>[t.value?(e(),n("div",Y,[a(I,{num:r.value},null,8,["num"])])):(e(),n("div",Z,[o.value.length===0?(e(),n("div",tt,[a(z,{size:"large",description:"暂无数据"})])):h("",!0),(e(!0),n(y,null,U(o.value,g=>(e(),q(V,{key:g.user_id},{default:f(()=>[a(B,{contact:g},null,8,["contact"])]),_:2},1024))),128))]))]),_:1})]),m.value>0?(e(),n("div",et,[a(M,{page:_.value,"onUpdate:page":w,"page-slot":S(l).state.collapsedRight?5:8,"page-count":m.value},null,8,["page","page-slot","page-count"])])):h("",!0)],64)}}});const zt=b(ot,[["__scopeId","data-v-3b2bf978"]]);export{zt as default};

@ -0,0 +1 @@
import{u as j,b as E}from"./vue-router-b8e3382f.js";import{d as q,o as s,c as l,a as _,V as o,M as h,r as c,j as G,_ as F,a1 as y,O as $,F as U,a4 as H,Q as L}from"./@vue-e0e89260.js";import{o as O,F as Q,G as A,f as J,g as K,I as W,H as X}from"./naive-ui-62663ad7.js";import{_ as z,R as Y,S as Z}from"./index-152c5794.js";import{_ as ee}from"./post-skeleton-d2e839d6.js";import{_ as oe}from"./main-nav.vue_vue_type_style_index_0_lang-32d416c3.js";import{u as te}from"./vuex-473b3783.js";import"./seemly-76b7b838.js";import"./vueuc-59ca65c3.js";import"./evtd-b614532e.js";import"./@css-render-580d83ec.js";import"./vooks-a50491fd.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";import"./@vicons-0524c43e.js";/* empty css */const ne={class:"avatar"},ae={class:"base-info"},se={class:"username"},le={class:"uid"},_e=q({__name:"follow-item",props:{contact:{}},setup(I){const v=j(),u=e=>{v.push({name:"user",query:{s:e}})};return(e,t)=>{const g=O;return s(),l("div",{class:"follow-item",onClick:t[0]||(t[0]=f=>u(e.contact.username))},[_("div",ne,[o(g,{size:"large",src:e.contact.avatar},null,8,["src"])]),_("div",ae,[_("div",se,[_("strong",null,h(e.contact.nickname),1),_("span",null," @"+h(e.contact.username),1)]),_("div",le,"UID. "+h(e.contact.user_id),1)])])}}});const ue=z(_e,[["__scopeId","data-v-6e07cba3"]]),ce={key:0,class:"skeleton-wrap"},ie={key:1},re={key:0,class:"empty-wrap"},pe={key:0,class:"pagination-wrap"},me=q({__name:"Following",setup(I){const v=te(),u=E(),e=c(!1),t=c([]),g=u.query.n||"粉丝详情",f=u.query.s||"",r=c(u.query.t||"follows"),p=c(+u.query.p||1),i=c(20),m=c(0),T=a=>{p.value=a,w()},B=a=>{r.value=a,w()},w=()=>{r.value==="follows"?C(f):r.value==="followings"&&M(f)},C=(a,d=!1)=>{t.value.length===0&&(e.value=!0),Y({username:a,page:p.value,page_size:i.value}).then(n=>{e.value=!1,t.value=n.list||[],m.value=Math.ceil(n.pager.total_rows/i.value),d&&setTimeout(()=>{window.scrollTo(0,99999)},50)}).catch(n=>{e.value=!1})},M=(a,d=!1)=>{t.value.length===0&&(e.value=!0),Z({username:a,page:p.value,page_size:i.value}).then(n=>{e.value=!1,t.value=n.list||[],m.value=Math.ceil(n.pager.total_rows/i.value),d&&setTimeout(()=>{window.scrollTo(0,99999)},50)}).catch(n=>{e.value=!1})};return G(()=>{w()}),(a,d)=>{const n=oe,k=J,P=K,R=ee,S=W,V=ue,N=X,x=Q,D=A;return s(),l(U,null,[_("div",null,[o(n,{title:F(g),back:!0},null,8,["title"]),o(x,{class:"main-content-wrap",bordered:""},{default:y(()=>[o(P,{type:"line",animated:"","default-value":r.value,"onUpdate:value":B},{default:y(()=>[o(k,{name:"follows",tab:"正在关注"}),o(k,{name:"followings",tab:"我的粉丝"})]),_:1},8,["default-value"]),e.value?(s(),l("div",ce,[o(R,{num:i.value},null,8,["num"])])):(s(),l("div",ie,[t.value.length===0?(s(),l("div",re,[o(S,{size:"large",description:"暂无数据"})])):$("",!0),(s(!0),l(U,null,H(t.value,b=>(s(),L(N,{key:b.user_id},{default:y(()=>[o(V,{contact:b},null,8,["contact"])]),_:2},1024))),128))]))]),_:1})]),m.value>0?(s(),l("div",pe,[o(D,{page:p.value,"onUpdate:page":T,"page-slot":F(v).state.collapsedRight?5:8,"page-count":m.value},null,8,["page","page-slot","page-count"])])):$("",!0)],64)}}});const Ne=z(me,[["__scopeId","data-v-1f0f223d"]]);export{Ne as default};

@ -0,0 +1 @@
.follow-item[data-v-6e07cba3]{display:flex;width:100%;padding:12px 16px}.follow-item[data-v-6e07cba3]:hover{background:#f7f9f9;cursor:pointer}.follow-item .avatar[data-v-6e07cba3]{width:55px}.follow-item .base-info[data-v-6e07cba3]{position:relative;width:calc(100% - 55px)}.follow-item .base-info .username[data-v-6e07cba3]{line-height:16px;font-size:16px}.follow-item .base-info .uid[data-v-6e07cba3]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.dark .follow-item[data-v-6e07cba3]{background-color:#101014bf}.dark .follow-item[data-v-6e07cba3]:hover{background:#18181c}.main-content-wrap[data-v-1f0f223d]{padding:20px}.pagination-wrap[data-v-1f0f223d]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .main-content-wrap[data-v-1f0f223d],.dark .empty-wrap[data-v-1f0f223d],.dark .skeleton-wrap[data-v-1f0f223d]{background-color:#101014bf}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.message-item[data-v-07fc447f]{padding:16px}.message-item.unread[data-v-07fc447f]{background:#fcfffc}.message-item .sender-wrap[data-v-07fc447f]{display:flex;align-items:center}.message-item .sender-wrap .username[data-v-07fc447f]{opacity:.75;font-size:14px}.message-item .timestamp[data-v-07fc447f]{opacity:.75;font-size:12px;display:flex;align-items:center}.message-item .timestamp .timestamp-txt[data-v-07fc447f]{margin-left:6px}.message-item .brief-wrap[data-v-07fc447f]{margin-top:10px}.message-item .brief-wrap .brief-content[data-v-07fc447f],.message-item .brief-wrap .whisper-content-wrap[data-v-07fc447f],.message-item .brief-wrap .requesting-friend-wrap[data-v-07fc447f]{display:flex;width:100%}.message-item .view-link[data-v-07fc447f]{margin-left:8px;display:flex;align-items:center}.message-item .status-info[data-v-07fc447f]{margin-left:8px;align-items:center}.dark .message-item[data-v-07fc447f]{background-color:#101014bf}.dark .message-item.unread[data-v-07fc447f]{background:#0f180b}.dark .message-item .brief-wrap[data-v-07fc447f]{background-color:#18181c}.skeleton-item[data-v-01d2e871]{padding:12px;display:flex}.skeleton-item .content[data-v-01d2e871]{width:100%}.dark .skeleton-item[data-v-01d2e871]{background-color:#101014bf}.pagination-wrap[data-v-4e7b1342]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .empty-wrap[data-v-4e7b1342],.dark .messages-wrap[data-v-4e7b1342],.dark .pagination-wrap[data-v-4e7b1342]{background-color:#101014bf}

@ -1 +0,0 @@
.message-item[data-v-4a0e27fa]{padding:16px}.message-item.unread[data-v-4a0e27fa]{background:#fcfffc}.message-item .sender-wrap[data-v-4a0e27fa]{display:flex;align-items:center}.message-item .sender-wrap .username[data-v-4a0e27fa]{opacity:.75;font-size:14px}.message-item .timestamp[data-v-4a0e27fa]{opacity:.75;font-size:12px;display:flex;align-items:center}.message-item .timestamp .timestamp-txt[data-v-4a0e27fa]{margin-left:6px}.message-item .brief-wrap[data-v-4a0e27fa]{margin-top:10px}.message-item .brief-wrap .brief-content[data-v-4a0e27fa],.message-item .brief-wrap .whisper-content-wrap[data-v-4a0e27fa],.message-item .brief-wrap .requesting-friend-wrap[data-v-4a0e27fa]{display:flex;width:100%}.message-item .view-link[data-v-4a0e27fa]{margin-left:8px;display:flex;align-items:center}.message-item .status-info[data-v-4a0e27fa]{margin-left:8px;align-items:center}.dark .message-item[data-v-4a0e27fa]{background-color:#101014bf}.dark .message-item.unread[data-v-4a0e27fa]{background:#0f180b}.dark .message-item .brief-wrap[data-v-4a0e27fa]{background-color:#18181c}.skeleton-item[data-v-01d2e871]{padding:12px;display:flex}.skeleton-item .content[data-v-01d2e871]{width:100%}.dark .skeleton-item[data-v-01d2e871]{background-color:#101014bf}.pagination-wrap[data-v-4e7b1342]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .empty-wrap[data-v-4e7b1342],.dark .messages-wrap[data-v-4e7b1342],.dark .pagination-wrap[data-v-4e7b1342]{background-color:#101014bf}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
.profile-baseinfo[data-v-08661398]{display:flex;padding:16px}.profile-baseinfo .avatar[data-v-08661398]{width:55px}.profile-baseinfo .base-info[data-v-08661398]{position:relative;width:calc(100% - 55px)}.profile-baseinfo .base-info .username[data-v-08661398]{line-height:16px;font-size:16px}.profile-baseinfo .base-info .uid[data-v-08661398]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.profile-tabs-wrap[data-v-08661398]{padding:0 16px}.pagination-wrap[data-v-08661398]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .profile-baseinfo[data-v-08661398]{background-color:#18181c}.dark .profile-wrap[data-v-08661398],.dark .pagination-wrap[data-v-08661398]{background-color:#101014bf}

@ -0,0 +1 @@
.profile-baseinfo[data-v-79a284ce]{display:flex;padding:16px}.profile-baseinfo .avatar[data-v-79a284ce]{width:72px}.profile-baseinfo .base-info[data-v-79a284ce]{position:relative;margin-left:12px;width:calc(100% - 84px)}.profile-baseinfo .base-info .username[data-v-79a284ce]{line-height:16px;font-size:16px}.profile-baseinfo .base-info .userinfo[data-v-79a284ce]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.profile-baseinfo .base-info .userinfo .info-item[data-v-79a284ce]{margin-right:12px}.profile-baseinfo .base-info .top-tag[data-v-79a284ce]{transform:scale(.75)}.profile-tabs-wrap[data-v-79a284ce]{padding:0 16px}.pagination-wrap[data-v-79a284ce]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .profile-wrap[data-v-79a284ce],.dark .pagination-wrap[data-v-79a284ce]{background-color:#101014bf}

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

Loading…
Cancel
Save