You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sonic/service/impl/install.go

311 lines
10 KiB
Go

2 years ago
package impl
import (
"context"
"crypto/md5"
"encoding/hex"
"strconv"
"strings"
"time"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/dal"
"github.com/go-sonic/sonic/event"
"github.com/go-sonic/sonic/model/entity"
"github.com/go-sonic/sonic/model/param"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util"
"github.com/go-sonic/sonic/util/xerr"
)
type installServiceImpl struct {
OptionService service.OptionService
Event event.Bus
UerService service.UserService
CategoryService service.CategoryService
PostService service.PostService
PostCommentService service.PostCommentService
SheetService service.SheetService
MenuService service.MenuService
}
func NewInstallService(
optionService service.OptionService,
event event.Bus,
uerService service.UserService,
categoryService service.CategoryService,
postService service.PostService,
postCommentService service.PostCommentService,
sheetService service.SheetService,
menuService service.MenuService,
) service.InstallService {
return &installServiceImpl{
OptionService: optionService,
Event: event,
UerService: uerService,
CategoryService: categoryService,
PostService: postService,
PostCommentService: postCommentService,
SheetService: sheetService,
MenuService: menuService,
}
}
func (i installServiceImpl) InstallBlog(ctx context.Context, installParam param.Install) error {
isInstalled, err := i.OptionService.GetOrByDefaultWithErr(ctx, property.IsInstalled, false)
if err != nil {
return nil
}
if isInstalled.(bool) {
return xerr.BadParam.New("").WithStatus(xerr.StatusBadRequest).WithMsg("Blog has been installed")
}
var user *entity.User
2 years ago
err = dal.Transaction(ctx, func(txCtx context.Context) error {
if err := i.createJWTSecret(txCtx); err != nil {
return err
}
if err := i.createDefaultSetting(txCtx, installParam); err != nil {
return err
}
user, err = i.createUser(txCtx, installParam.User)
2 years ago
if err != nil {
return err
}
category, err := i.createDefaultCategory(txCtx)
if err != nil {
return err
}
post, err := i.createDefaultPost(txCtx, category)
if err != nil {
return err
}
_, err = i.createDefaultSheet(txCtx)
if err != nil {
return err
}
_, err = i.createDefaultComment(txCtx, post)
if err != nil {
return err
}
err = i.createDefaultMenu(txCtx)
return err
})
if err != nil {
return err
}
if user != nil {
i.Event.Publish(ctx, &event.LogEvent{
2 years ago
LogKey: strconv.Itoa(int(user.ID)),
LogType: consts.LogTypeBlogInitialized,
Content: "博客已成功初始化",
})
}
2 years ago
return err
}
func (i installServiceImpl) createDefaultSetting(ctx context.Context, installParam param.Install) error {
optionMap := make(map[string]string)
optionMap[property.IsInstalled.KeyValue] = "true"
optionMap[property.GlobalAbsolutePathEnabled.KeyValue] = "false"
optionMap[property.BlogTitle.KeyValue] = installParam.Title
2 years ago
if installParam.URL == "" {
2 years ago
blogURL, err := i.OptionService.GetBlogBaseURL(ctx)
if err != nil {
return err
}
2 years ago
optionMap[property.BlogURL.KeyValue] = blogURL
2 years ago
} else {
2 years ago
optionMap[property.BlogURL.KeyValue] = installParam.URL
2 years ago
}
if installParam.Locale == "" {
optionMap[property.BlogLocale.KeyValue] = property.BlogLocale.DefaultValue.(string)
}
optionMap[property.BirthDay.KeyValue] = strconv.FormatInt(time.Now().UnixMilli(), 10)
err := i.OptionService.Save(ctx, optionMap)
return err
}
func (i installServiceImpl) createUser(ctx context.Context, user param.User) (*entity.User, error) {
emailMd5 := md5.Sum([]byte(user.Email))
avatar := "//cn.gravatar.com/avatar/" + hex.EncodeToString(emailMd5[:]) + "?s=256&d=mm"
user.Avatar = avatar
userEntity, err := i.UerService.CreateByParam(ctx, user)
return userEntity, err
}
func (i installServiceImpl) createDefaultCategory(ctx context.Context) (*entity.Category, error) {
categoryDal := dal.GetQueryByCtx(ctx).Category
2 years ago
count, err := categoryDal.WithContext(ctx).Count()
if err != nil {
return nil, WrapDBErr(err)
}
if count > 0 {
return nil, nil
}
categoryParam := param.Category{
Name: "默认分类",
Slug: "default",
Description: "这是你的默认分类,如不需要,删除即可",
}
category, err := i.CategoryService.Create(ctx, &categoryParam)
if err != nil {
return nil, err
}
return category, nil
}
func (i installServiceImpl) createDefaultPost(ctx context.Context, category *entity.Category) (*entity.Post, error) {
if category == nil {
return nil, nil
}
postDAL := dal.GetQueryByCtx(ctx).Post
2 years ago
count, err := postDAL.WithContext(ctx).Where(postDAL.Status.Eq(consts.PostStatusPublished)).Count()
if err != nil {
return nil, err
}
if count > 0 {
return nil, nil
}
content := `
## Hello Sonic
使 [Sonic](https://github.com/go-sonic) 进行创作,希望能够使用愉快。
2 years ago
##
2 years ago
- [https://github.com/go-sonic](https://github.com/go-sonic)
- [https://github.com/go-sonic/default-theme-anatole](https://github.com/go-sonic/default-theme-anatole)
2 years ago
- [https://github.com/go-sonic/sonic](https://github.com/go-sonic/sonic)
使
>
`
formatContent := `<h2 id="hello-sonic" tabindex="-1">Hello Sonic</h2>
<p>使 <a href="https://go-sonic.org" target="_blank">Sonic</a> 使</p>
<h2 id="%E7%9B%B8%E5%85%B3%E9%93%BE%E6%8E%A5" tabindex="-1"></h2>
<ul>
<li><a href="https://github.com/go-sonic" target="_blank">https://github.com/go-sonic</a></li>
<li><a href="https://github.com/go-sonic/default-theme-anatole" target="_blank">https://github.com/go-sonic/default-theme-anatole</a></li>
<li><a href="https://github.com/go-sonic/sonic" target="_blank">https://github.com/go-sonic/sonic</a></li>
</ul>
<p>使</p>
<blockquote>
<p></p>
</blockquote>
`
2 years ago
postParam := param.Post{
Title: "Hello Sonic",
Status: consts.PostStatusPublished,
Slug: "hello-sonic",
OriginalContent: content,
Content: formatContent,
2 years ago
CategoryIDs: []int32{category.ID},
}
return i.PostService.Create(ctx, &postParam)
}
func (i installServiceImpl) createDefaultSheet(ctx context.Context) (*entity.Post, error) {
postDAL := dal.GetQueryByCtx(ctx).Post
count, err := postDAL.WithContext(ctx).Where(postDAL.Status.Eq(consts.PostStatusPublished), postDAL.Type.Eq(consts.PostTypeSheet)).Count()
2 years ago
if err != nil {
return nil, err
}
if count > 0 {
return nil, nil
}
originalContent := "## 关于页面 \n\n" +
2 years ago
" 这是一个自定义页面,你可以在后台的 `页面` -> `所有页面` -> `自定义页面` 找到它," +
"你可以用于新建关于页面、留言板页面等等。发挥你自己的想象力!\n\n" +
"> 这是一篇自动生成的页面,你可以在后台删除它。"
formatContent := `<h2 id="%E5%85%B3%E4%BA%8E%E9%A1%B5%E9%9D%A2" tabindex="-1"></h2>
<p> <code></code> -&gt; <code></code> -&gt; <code></code> </p>
<blockquote>
<p></p>
</blockquote>`
2 years ago
sheetParam := param.Sheet{
Title: "关于页面",
Status: consts.PostStatusPublished,
Slug: "about",
OriginalContent: originalContent,
Content: formatContent,
2 years ago
}
return i.SheetService.Create(ctx, &sheetParam)
}
func (i installServiceImpl) createDefaultComment(ctx context.Context, post *entity.Post) (*entity.Comment, error) {
if post == nil {
return nil, nil
}
count, err := i.PostCommentService.CountByStatus(ctx, consts.CommentStatusPublished)
if err != nil {
return nil, err
}
if count > 0 {
return nil, nil
}
content := "欢迎使用 Sonic这是你的第一条评论头像来自 [Gravatar](https://cn.gravatar.com)" +
"你也可以通过注册 [Gravatar]" +
"(https://cn.gravatar.com) 来显示自己的头像。"
comment := &entity.Comment{
Type: consts.CommentTypePost,
AllowNotification: true,
Author: "Sonic",
AuthorURL: "https://sonic.run",
Content: content,
Email: "hi@sonic.run",
ParentID: 0,
PostID: post.ID,
Status: consts.CommentStatusPublished,
}
return i.PostCommentService.Create(ctx, comment)
}
func (i installServiceImpl) createDefaultMenu(ctx context.Context) error {
menuIndex := &param.Menu{
Name: "首页",
URL: "/",
Priority: 1,
}
menuArchive := &param.Menu{
Name: "文章归档",
URL: "/archives",
Priority: 2,
}
menuCategory := &param.Menu{
Name: "默认分类",
URL: "/categories/default",
Priority: 3,
}
menuSheet := &param.Menu{
Name: "关于页面",
URL: "/s/about",
Priority: 4,
}
createMenu := func(menu *param.Menu, err error) error {
if err != nil {
return err
}
_, err = i.MenuService.Create(ctx, menu)
return err
}
err := createMenu(menuIndex, nil)
err = createMenu(menuArchive, err)
err = createMenu(menuCategory, err)
err = createMenu(menuSheet, err)
return err
}
func (i installServiceImpl) createJWTSecret(ctx context.Context) error {
secret := &strings.Builder{}
secret.Grow(256)
for i := 0; i < 8; i++ {
secret.WriteString(util.GenUUIDWithOutDash())
}
m := map[string]string{property.JWTSecret.KeyValue: secret.String()}
return i.OptionService.Save(ctx, m)
}