数据初始化

dev
truthhun 2 years ago
parent c7eec0e04c
commit c007c30472

@ -37,3 +37,9 @@ make api
- 除了文件上传相关的接口其他接口一律使用proto进行定义。
## 管理员初始账号密码
```
账号admin
密码mnt.ltd
```

@ -352,7 +352,7 @@ func (m *DBModel) initConfig() (err error) {
{Category: ConfigCategorySystem, Name: ConfigSystemLogo, Label: "网站Logo", Value: "", Placeholder: "请输入您网站的Logo路径", InputType: "image", Sort: 6, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemFavicon, Label: "网站Favicon", Value: "", Placeholder: "请输入您网站的Favicon路径", InputType: "image", Sort: 6, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemIcp, Label: "网站备案号", Value: "", Placeholder: "请输入您网站的备案号", InputType: "text", Sort: 6, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemDomain, Label: "网站域名", Value: "", Placeholder: "请输入您网站的域名访问地址,如 https://moredoc.mnt.ltd用以生成网站地图sitemap", InputType: "text", Sort: 7, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemDomain, Label: "网站域名", Value: "https://moredoc.mnt.ltd", Placeholder: "请输入您网站的域名访问地址,如 https://moredoc.mnt.ltd用以生成网站地图sitemap", InputType: "text", Sort: 7, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemCopyrightStartYear, Label: "版权起始年", Value: "2019", Placeholder: "请输入您网站版权起始年2019则前台会显示如 ©2019 - 2022 的字样", InputType: "text", Sort: 8, Options: ""},
{Category: ConfigCategorySystem, Name: ConfigSystemAnalytics, Label: "网站统计代码", Value: "", Placeholder: "请输入您网站的统计代码", InputType: "textarea", Sort: 9, Options: ""},
@ -373,11 +373,11 @@ func (m *DBModel) initConfig() (err error) {
{Category: ConfigCategorySecurity, Name: ConfigSecurityEnableCaptchaFindPassword, Label: "是否开启找回密码验证码", Value: "true", Placeholder: "请选择是否开启找回密码验证码", InputType: "switch", Sort: 22, Options: ""},
// 底部链接
{Category: ConfigCategoryFooter, Name: ConfigFooterAbout, Label: "关于我们", Value: "", Placeholder: "请输入关于我们的链接地址,留空表示不显示", InputType: "text", Sort: 24, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterContact, Label: "联系我们", Value: "", Placeholder: "请输入联系我们的链接地址,留空表示不显示", InputType: "text", Sort: 25, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterAgreement, Label: "文库协议", Value: "", Placeholder: "请输入文库协议的链接地址,留空表示不显示", InputType: "text", Sort: 26, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterCopyright, Label: "免责声明", Value: "", Placeholder: "请输入免责声明的链接地址,留空表示不显示", InputType: "text", Sort: 27, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterFeedback, Label: "意见反馈", Value: "", Placeholder: "请输入意见反馈的链接地址,留空表示不显示", InputType: "text", Sort: 28, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterAbout, Label: "关于我们", Value: "/article/about", Placeholder: "请输入关于我们的链接地址,留空表示不显示", InputType: "text", Sort: 24, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterContact, Label: "联系我们", Value: "/article/contact", Placeholder: "请输入联系我们的链接地址,留空表示不显示", InputType: "text", Sort: 25, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterAgreement, Label: "文库协议", Value: "/article/agreement", Placeholder: "请输入文库协议的链接地址,留空表示不显示", InputType: "text", Sort: 26, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterCopyright, Label: "免责声明", Value: "/article/copyright", Placeholder: "请输入免责声明的链接地址,留空表示不显示", InputType: "text", Sort: 27, Options: ""},
{Category: ConfigCategoryFooter, Name: ConfigFooterFeedback, Label: "意见反馈", Value: "/article/feedback", Placeholder: "请输入意见反馈的链接地址,留空表示不显示", InputType: "text", Sort: 28, Options: ""},
}
for _, cfg := range cfgs {

@ -0,0 +1,59 @@
package model
func getPermissions() (permissions []Permission) {
permissions = []Permission{
{Title: "查看用户列表", Description: "", Method: "GRPC", Path: "/api.v1.UserAPI/ListUser"},
{Title: "创建用户组", Description: "", Method: "GRPC", Path: "/api.v1.GroupAPI/CreateGroup"},
{Title: "查看友链列表", Description: "", Method: "GRPC", Path: "/api.v1.FriendlinkAPI/ListFriendlink"},
{Title: "创建友链", Description: "", Method: "GRPC", Path: "/api.v1.FriendlinkAPI/CreateFriendlink"},
{Title: "更新友链", Description: "", Method: "GRPC", Path: "/api.v1.FriendlinkAPI/UpdateFriendlink"},
{Title: "删除友链", Description: "", Method: "GRPC", Path: "/api.v1.FriendlinkAPI/DeleteFriendlink"},
{Title: "查看附件列表", Description: "", Method: "GRPC", Path: "/api.v1.AttachmentAPI/ListAttachment"},
{Title: "删除附件", Description: "", Method: "GRPC", Path: "/api.v1.AttachmentAPI/DeleteAttachment"},
{Title: "更新附件信息", Description: "", Method: "GRPC", Path: "/api.v1.AttachmentAPI/UpdateAttachment"},
{Title: "获取横幅列表", Description: "", Method: "GRPC", Path: "/api.v1.BannerAPI/ListBanner"},
{Title: "上传横幅", Description: "", Method: "POST", Path: "/api/v1/upload/banner"},
{Title: "创建横幅", Description: "", Method: "GRPC", Path: "/api.v1.BannerAPI/CreateBanner"},
{Title: "更新横幅", Description: "", Method: "GRPC", Path: "/api.v1.BannerAPI/UpdateBanner"},
{Title: "删除横幅", Description: "", Method: "GRPC", Path: "/api.v1.BannerAPI/DeleteBanner"},
{Title: "根据ID查询附件", Description: "", Method: "GRPC", Path: "/api.v1.AttachmentAPI/GetAttachment"},
{Title: "根据ID查询横幅", Description: "", Method: "GRPC", Path: "/api.v1.BannerAPI/GetBanner"},
{Title: "根据ID查询友链", Description: "", Method: "GRPC", Path: "/api.v1.FriendlinkAPI/GetFriendlink"},
{Title: "删除用户组", Description: "", Method: "GRPC", Path: "/api.v1.GroupAPI/DeleteGroup"},
{Title: "更新用户组", Description: "", Method: "GRPC", Path: "/api.v1.GroupAPI/UpdateGroup"},
{Title: "获取用户组列表", Description: "", Method: "GRPC", Path: "/api.v1.GroupAPI/ListGroup"},
{Title: "获取权限列表", Description: "", Method: "GRPC", Path: "/api.v1.PermissionAPI/ListPermission"},
{Title: "根据ID查询权限", Description: "", Method: "GRPC", Path: "/api.v1.PermissionAPI/GetPermission"},
{Title: "更新权限信息", Description: "", Method: "GRPC", Path: "/api.v1.PermissionAPI/UpdatePermission"},
{Title: "获取用户组授权", Description: "", Method: "GRPC", Path: "/api.v1.GroupAPI/GetGroupPermission"},
{Title: "给用户组授权", Description: "", Method: "GRPC", Path: "/api.v1.GroupAPI/UpdateGroupPermission"},
{Title: "获取系统配置列表", Description: "", Method: "GRPC", Path: "/api.v1.ConfigAPI/ListConfig"},
{Title: "更新系统配置", Description: "", Method: "GRPC", Path: "/api.v1.ConfigAPI/UpdateConfig"},
{Title: "新增用户", Description: "", Method: "GRPC", Path: "/api.v1.UserAPI/AddUser"},
{Title: "设置用户密码与分组", Description: "", Method: "GRPC", Path: "/api.v1.UserAPI/SetUser"},
{Title: "删除用户", Description: "", Method: "GRPC", Path: "/api.v1.UserAPI/DeleteUser"},
{Title: "更新用户资料", Description: "", Method: "GRPC", Path: "/api.v1.UserAPI/UpdateUserProfile"},
{Title: "根据ID查询用户", Description: "", Method: "GRPC", Path: "/api.v1.UserAPI/GetUser"},
{Title: "查询文档分类列表", Description: "", Method: "GRPC", Path: "/api.v1.CategoryAPI/ListCategory"},
{Title: "根据ID查询文档分类", Description: "", Method: "GRPC", Path: "/api.v1.CategoryAPI/GetCategory"},
{Title: "新增文档分类", Description: "", Method: "GRPC", Path: "/api.v1.CategoryAPI/CreateCategory"},
{Title: "更新文档分类", Description: "", Method: "GRPC", Path: "/api.v1.CategoryAPI/UpdateCategory"},
{Title: "删除文档分类", Description: "", Method: "GRPC", Path: "/api.v1.CategoryAPI/DeleteCategory"},
{Title: "获取文档列表", Description: "", Method: "GRPC", Path: "/api.v1.DocumentAPI/ListDocument"},
{Title: "删除文档", Description: "", Method: "GRPC", Path: "/api.v1.DocumentAPI/DeleteDocument"},
{Title: "根据ID查询文档", Description: "", Method: "GRPC", Path: "/api.v1.DocumentAPI/GetDocument"},
{Title: "更新文档", Description: "", Method: "GRPC", Path: "/api.v1.DocumentAPI/UpdateDocument"},
{Title: "获取回收站文档列表", Description: "", Method: "GRPC", Path: "/api.v1.RecycleAPI/ListRecycleDocument"},
{Title: "恢复回收站文档", Description: "", Method: "GRPC", Path: "/api.v1.RecycleAPI/RecoverRecycleDocument"},
{Title: "清空回收站文档", Description: "", Method: "GRPC", Path: "/api.v1.RecycleAPI/ClearRecycleDocument"},
{Title: "删除回收站文档", Description: "", Method: "GRPC", Path: "/api.v1.RecycleAPI/DeleteRecycleDocument"},
{Title: "文章/单页管理", Description: "", Method: "GRPC", Path: "/api.v1.ArticleAPI/ListArticle"},
{Title: "更新文章/单页", Description: "", Method: "GRPC", Path: "/api.v1.ArticleAPI/UpdateArticle"},
{Title: "删除文章/单页", Description: "", Method: "GRPC", Path: "/api.v1.ArticleAPI/DeleteArticle"},
{Title: "创建文章/单页", Description: "", Method: "GRPC", Path: "/api.v1.ArticleAPI/CreateArticle"},
{Title: "上传文章图片和音视频", Description: "", Method: "POST", Path: "/api/v1/upload/article"},
{Title: "上传文档分类封面", Description: "", Method: "POST", Path: "/api/v1/upload/category"},
{Title: "上传配置图片文件", Description: "", Method: "POST", Path: "/api/v1/upload/config"},
}
return
}

@ -0,0 +1,77 @@
package model
import (
"bytes"
"os"
"strings"
"testing"
"text/template"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
const dataGoTpl = `
package model
func getPermissions() (permissions []Permission) {
permissions = []Permission{
{{ range .Permissions }}{Title: "{{.Title}}", Description: "{{.Description}}", Method: "{{.Method}}", Path: "{{.Path}}"},
{{end}}
}
return
}
`
func TestGenData(t *testing.T) {
// 访问的数据库链接地址。 dsn: data source name
// 【注意】以哪个数据库的【菜单】和【API】为准则配置查询哪个数据库以生成menu和api基础数据
dsn := "root:root@tcp(127.0.0.1)/moredoc?charset=utf8mb4&parseTime=True&loc=Local"
t.Log("开始生成 data.go 文件")
t.Log("dsn:", dsn)
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: dsn, // DSN
}), &gorm.Config{})
if err != nil {
return
}
defer func() {
d, _ := db.DB()
d.Close()
}()
var (
permissions []Permission
permissionTableName = Permission{}.TableName()
)
err = db.Table(permissionTableName).Find(&permissions).Error
if err != nil {
t.Errorf("生成 data.go 文件失败: %s", err.Error())
return
}
replacer := strings.NewReplacer("\"", "\\\"")
for idx, permission := range permissions {
permissions[idx].Title = replacer.Replace(permission.Title)
permissions[idx].Description = replacer.Replace(permission.Description)
}
tmpl, err := template.New("data.go").Parse(dataGoTpl)
if err != nil {
t.Fatal(err.Error())
}
buf := new(bytes.Buffer)
if err := tmpl.Execute(buf, map[string]interface{}{"Permissions": permissions}); err != nil {
t.Fatal(err.Error())
}
err = os.WriteFile("data.go", buf.Bytes(), 0666)
if err != nil {
t.Fatalf("生成 data.go 文件失败: %s", err.Error())
}
t.Log("生成 data.go 文件成功")
}

@ -7,9 +7,9 @@ import (
)
type GroupPermission struct {
Id int64 `form:"id" json:"id,omitempty" gorm:"column:id;type:bigint(20);size:20;default:0;comment:;"`
GroupId int64 `form:"group_id" json:"group_id,omitempty" gorm:"primaryKey;autoIncrement;index:group_permission,unique;index:group_id;column:group_id;comment:组ID;"`
PermissionId int64 `form:"permission_id" json:"permission_id,omitempty" gorm:"primaryKey;autoIncrement;index:group_permission,unique;column:permission_id;comment:权限ID;"`
Id int64 `form:"id" json:"id,omitempty" gorm:"primaryKey;autoIncrement;column:id;comment:自增主键;"`
GroupId int64 `form:"group_id" json:"group_id,omitempty" gorm:"index:group_permission,unique;index:group_id;column:group_id;comment:组ID;"`
PermissionId int64 `form:"permission_id" json:"permission_id,omitempty" gorm:"index:group_permission,unique;column:permission_id;comment:权限ID;"`
CreatedAt *time.Time `form:"created_at" json:"created_at,omitempty" gorm:"column:created_at;type:datetime;comment:创建时间;"`
UpdatedAt *time.Time `form:"updated_at" json:"updated_at,omitempty" gorm:"column:updated_at;type:datetime;comment:更新时间;"`
}

@ -27,7 +27,8 @@ type TableColumn struct {
Comment string `gorm:"Comment"`
}
var tablePrefix string
// 默认表前缀
var tablePrefix string = "mnt_"
type DBModel struct {
db *gorm.DB
@ -204,26 +205,27 @@ func (m *DBModel) showTableColumn(tableName string) (columns []TableColumn, err
// initialDatabase 初始化数据库相关数据
func (m *DBModel) initDatabase() (err error) {
// if err = m.initPermission(); err != nil {
// m.logger.Error("initialDatabase", zap.Error(err))
// return
// }
// 初始化用户组及其权限
if err = m.initGroupAndPermission(); err != nil {
m.logger.Error("initialDatabase", zap.Error(err))
m.logger.Error("initGroupAndPermission", zap.Error(err))
return
}
// 初始化用户
if err = m.initUser(); err != nil {
m.logger.Error("initialDatabase", zap.Error(err))
m.logger.Error("initUser", zap.Error(err))
return
}
// 初始化配置
if err = m.initConfig(); err != nil {
m.logger.Error("initialDatabase", zap.Error(err))
m.logger.Error("initConfig", zap.Error(err))
return
}
// 初始化友情链接
if err = m.initFriendlink(); err != nil {
m.logger.Error("initFriendlink", zap.Error(err))
return
}
return
@ -234,7 +236,6 @@ func (m *DBModel) initGroupAndPermission() (err error) {
groups := []Group{
{Id: 1, Title: "超级管理员", IsDisplay: true, Description: "系统超级管理员", UserCount: 0, Sort: 0},
{Id: 2, Title: "普通用户", IsDisplay: true, Description: "普通用户", UserCount: 0, Sort: 0, IsDefault: true},
{Id: 3, Title: "游客", IsDisplay: true, Description: "游客", UserCount: 0, Sort: 0},
}
// 如果没有任何用户组,则初始化
@ -244,11 +245,50 @@ func (m *DBModel) initGroupAndPermission() (err error) {
return
}
err = m.db.Create(&groups).Error
sess := m.db.Begin()
defer func() {
if err != nil {
sess.Rollback()
} else {
sess.Commit()
}
}()
err = sess.Create(&groups).Error
if err != nil {
m.logger.Error("initGroup", zap.Error(err))
return
}
// 初始化权限
for _, permission := range getPermissions() {
err = sess.Where("method = ? and path = ?", permission.Method, permission.Path).FirstOrCreate(&permission).Error
if err != nil {
m.logger.Error("initPermission", zap.Error(err))
return
}
}
return
}
func (m *DBModel) initFriendlink() (err error) {
var friendlink Friendlink
m.db.Find(&friendlink)
if friendlink.Id > 0 {
return
}
// 默认友链
var friendlinks = []Friendlink{
{Title: "摩枫网络科技", Link: "https://mnt.ltd", Enable: true},
{Title: "书栈网", Link: "https://www.bookstack.cn", Enable: true},
}
err = m.db.Create(&friendlinks).Error
if err != nil {
m.logger.Error("initFriendlink", zap.Error(err))
}
return
}

@ -119,10 +119,10 @@ func (m *DBModel) CheckPermissionByUserId(userId int64, path string, httpMethod
)
// NOTE: ID为1的用户拥有所有权限可以理解为类似linux的root用户
// TODO: 后续应该直接打开这里的注释
// if userId == 1 {
// return true
// }
if userId == 1 {
yes = true
return
}
if len(httpMethod) > 0 {
method = httpMethod[0]

@ -305,7 +305,7 @@ func (m *DBModel) initUser() (err error) {
}
// 初始化一个用户
user := &User{Username: "admin", Password: "123456"}
user := &User{Username: "admin", Password: "mnt.ltd"}
var groupId int64 = 1 // ID==1的用户组为管理员组
err = m.CreateUser(user, groupId)
if err != nil {

@ -245,6 +245,7 @@ export default {
</script>
<style lang="scss">
.layout-default {
min-width: 1000px !important;
.el-table th {
height: 45px;
line-height: 45px;

@ -1,7 +1,7 @@
<template>
<div class="page page-index">
<el-row :gutter="20">
<el-col :span="6" :xs="24" class="float-right">
<el-col :span="6" class="float-right">
<el-card class="text-center stat-info" shadow="never">
<el-row>
<el-col :span="12">
@ -55,7 +55,7 @@
</el-form>
</el-card>
</el-col>
<el-col :span="18" :xs="24" class="banners">
<el-col :span="18" class="banners">
<el-carousel :interval="5000" arrow="always" :height="'323px'">
<a
v-for="banner in banners"
@ -102,9 +102,7 @@
<el-col
v-for="category in categoryTrees"
:key="'card-cate-' + category.id"
:md="12"
:sm="12"
:xs="24"
:span="12"
>
<el-card class="box-card mgt-20px" shadow="never">
<div slot="header" class="clearfix">

@ -7,7 +7,7 @@ export const category = {
},
mutations: {
setCategories(state, categories) {
state.categories = categories
state.categories = categories || []
},
},
actions: {

@ -117,20 +117,25 @@ export function formatBytes(bytes, decimals = 2) {
export function categoryToTrees(categories, withDisabled = true) {
const result = []
const map = {}
categories.forEach((item) => {
if (withDisabled) {
item.disabled = !item.enable
}
map[item.id] = item
})
categories.forEach((item) => {
const parent = map[item.parent_id]
if (parent) {
if (parent.disabled) item.disabled = true
;(parent.children || (parent.children = [])).push(item)
} else {
result.push(item)
}
})
try {
categories.forEach((item) => {
if (withDisabled) {
item.disabled = !item.enable
}
map[item.id] = item
})
categories.forEach((item) => {
const parent = map[item.parent_id]
if (parent) {
if (parent.disabled) item.disabled = true
;(parent.children || (parent.children = [])).push(item)
} else {
result.push(item)
}
})
} catch (error) {
console.log(error)
}
return result
}

Loading…
Cancel
Save