|
|
|
|
@ -116,45 +116,45 @@ module.exports = {
|
|
|
|
|
['slug', 'type'] // 唯一约束:同一类型的文章不能有相同的slug
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
posts_meta: {
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
post_id: {type: 'string', maxlength: 24, nullable: false, references: 'posts.id', unique: true},
|
|
|
|
|
og_image: {type: 'string', maxlength: 2000, nullable: true},
|
|
|
|
|
og_title: {type: 'string', maxlength: 300, nullable: true},
|
|
|
|
|
og_description: {type: 'string', maxlength: 500, nullable: true},
|
|
|
|
|
twitter_image: {type: 'string', maxlength: 2000, nullable: true},
|
|
|
|
|
twitter_title: {type: 'string', maxlength: 300, nullable: true},
|
|
|
|
|
twitter_description: {type: 'string', maxlength: 500, nullable: true},
|
|
|
|
|
meta_title: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 300}}},
|
|
|
|
|
meta_description: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 500}}},
|
|
|
|
|
email_subject: {type: 'string', maxlength: 300, nullable: true},
|
|
|
|
|
frontmatter: {type: 'text', maxlength: 65535, nullable: true},
|
|
|
|
|
feature_image_alt: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 191}}},
|
|
|
|
|
feature_image_caption: {type: 'text', maxlength: 65535, nullable: true},
|
|
|
|
|
email_only: {type: 'boolean', nullable: false, defaultTo: false}
|
|
|
|
|
posts_meta: { //用于存储文章的额外元数据
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},//主键ID,唯一标识文章元数据
|
|
|
|
|
post_id: {type: 'string', maxlength: 24, nullable: false, references: 'posts.id', unique: true}, // 关联的文章ID,唯一标识
|
|
|
|
|
og_image: {type: 'string', maxlength: 2000, nullable: true}, // Open Graph 图片URL
|
|
|
|
|
og_title: {type: 'string', maxlength: 300, nullable: true}, // Open Graph 标题,最大300字符
|
|
|
|
|
og_description: {type: 'string', maxlength: 500, nullable: true}, // Open Graph 描述,最大500字符
|
|
|
|
|
twitter_image: {type: 'string', maxlength: 2000, nullable: true}, // Twitter 图片URL
|
|
|
|
|
twitter_title: {type: 'string', maxlength: 300, nullable: true}, // Twitter 标题,最大300字符
|
|
|
|
|
twitter_description: {type: 'string', maxlength: 500, nullable: true}, // Twitter 描述,最大500字符
|
|
|
|
|
meta_title: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 300}}},// SEO 标题,最大300字符
|
|
|
|
|
meta_description: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 500}}},// SEO 描述,最大500字符
|
|
|
|
|
email_subject: {type: 'string', maxlength: 300, nullable: true},// 邮件主题,最大300字符
|
|
|
|
|
frontmatter: {type: 'text', maxlength: 65535, nullable: true},// 文章的Frontmatter内容,用于自定义元数据
|
|
|
|
|
feature_image_alt: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 191}}},// 封面图替代文本,最大191字符
|
|
|
|
|
feature_image_caption: {type: 'text', maxlength: 65535, nullable: true},// 封面图标题,用于图片描述
|
|
|
|
|
email_only: {type: 'boolean', nullable: false, defaultTo: false}, // 是否仅通过邮件发送,默认为否
|
|
|
|
|
},
|
|
|
|
|
// NOTE: this is the staff table
|
|
|
|
|
users: {
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
name: {type: 'string', maxlength: 191, nullable: false},
|
|
|
|
|
slug: {type: 'string', maxlength: 191, nullable: false, unique: true},
|
|
|
|
|
password: {type: 'string', maxlength: 60, nullable: false},
|
|
|
|
|
email: {type: 'string', maxlength: 191, nullable: false, unique: true, validations: {isEmail: true}},
|
|
|
|
|
profile_image: {type: 'string', maxlength: 2000, nullable: true},
|
|
|
|
|
cover_image: {type: 'string', maxlength: 2000, nullable: true},
|
|
|
|
|
bio: {type: 'text', maxlength: 65535, nullable: true, validations: {isLength: {max: 250}}},
|
|
|
|
|
website: {type: 'string', maxlength: 2000, nullable: true, validations: {isEmptyOrURL: true}},
|
|
|
|
|
location: {type: 'text', maxlength: 65535, nullable: true, validations: {isLength: {max: 150}}},
|
|
|
|
|
facebook: {type: 'string', maxlength: 2000, nullable: true},
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},//主键ID,唯一标识用户
|
|
|
|
|
name: {type: 'string', maxlength: 191, nullable: false}, // 用户名
|
|
|
|
|
slug: {type: 'string', maxlength: 191, nullable: false, unique: true},//用户slug,唯一标识
|
|
|
|
|
password: {type: 'string', maxlength: 60, nullable: false},//用户密码
|
|
|
|
|
email: {type: 'string', maxlength: 191, nullable: false, unique: true, validations: {isEmail: true}},//用户邮箱,唯一标识
|
|
|
|
|
profile_image: {type: 'string', maxlength: 2000, nullable: true},// 用户头像URL
|
|
|
|
|
cover_image: {type: 'string', maxlength: 2000, nullable: true},//用户封面图URL
|
|
|
|
|
bio: {type: 'text', maxlength: 65535, nullable: true, validations: {isLength: {max: 250}}},//用户简介,最大250字符
|
|
|
|
|
website: {type: 'string', maxlength: 2000, nullable: true, validations: {isEmptyOrURL: true}},//用户网站URL
|
|
|
|
|
location: {type: 'text', maxlength: 65535, nullable: true, validations: {isLength: {max: 150}}},//用户位置,最大150字符
|
|
|
|
|
facebook: {type: 'string', maxlength: 2000, nullable: true},//用户Facebook链接
|
|
|
|
|
twitter: {type: 'string', maxlength: 2000, nullable: true},
|
|
|
|
|
threads: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
bluesky: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
mastodon: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
tiktok: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
youtube: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
instagram: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
linkedin: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
accessibility: {type: 'text', maxlength: 65535, nullable: true},
|
|
|
|
|
threads: {type: 'string', maxlength: 191, nullable: true},//用户Threads链接
|
|
|
|
|
bluesky: {type: 'string', maxlength: 191, nullable: true},//用户Bluesky链接
|
|
|
|
|
mastodon: {type: 'string', maxlength: 191, nullable: true},//用户Mastodon链接
|
|
|
|
|
tiktok: {type: 'string', maxlength: 191, nullable: true},//用户TikTok链接
|
|
|
|
|
youtube: {type: 'string', maxlength: 191, nullable: true}, //用户YouTube链接
|
|
|
|
|
instagram: {type: 'string', maxlength: 191, nullable: true},//用户Instagram链接
|
|
|
|
|
linkedin: {type: 'string', maxlength: 191, nullable: true},//用户LinkedIn链接
|
|
|
|
|
accessibility: {type: 'text', maxlength: 65535, nullable: true},//用户可访问性设置
|
|
|
|
|
status: {
|
|
|
|
|
type: 'string',
|
|
|
|
|
maxlength: 50,
|
|
|
|
|
@ -173,7 +173,7 @@ module.exports = {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// NOTE: unused at the moment and reserved for future features
|
|
|
|
|
locale: {type: 'string', maxlength: 6, nullable: true},
|
|
|
|
|
locale: {type: 'string', maxlength: 6, nullable: true},//用户语言设置
|
|
|
|
|
visibility: {
|
|
|
|
|
type: 'string',
|
|
|
|
|
maxlength: 50,
|
|
|
|
|
@ -197,25 +197,25 @@ module.exports = {
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
posts_authors: {
|
|
|
|
|
posts_authors: { // 文章作者关联表
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
post_id: {type: 'string', maxlength: 24, nullable: false, references: 'posts.id'},
|
|
|
|
|
author_id: {type: 'string', maxlength: 24, nullable: false, references: 'users.id'},
|
|
|
|
|
sort_order: {type: 'integer', nullable: false, unsigned: true, defaultTo: 0}
|
|
|
|
|
},
|
|
|
|
|
roles: {
|
|
|
|
|
roles: {// 角色
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
name: {type: 'string', maxlength: 50, nullable: false, unique: true},
|
|
|
|
|
description: {type: 'string', maxlength: 2000, nullable: true},
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
roles_users: {
|
|
|
|
|
roles_users: { // 角色用户关联表
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
role_id: {type: 'string', maxlength: 24, nullable: false},
|
|
|
|
|
user_id: {type: 'string', maxlength: 24, nullable: false}
|
|
|
|
|
},
|
|
|
|
|
permissions: {
|
|
|
|
|
permissions: {// 权限
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
name: {type: 'string', maxlength: 50, nullable: false, unique: true},
|
|
|
|
|
object_type: {type: 'string', maxlength: 50, nullable: false},
|
|
|
|
|
@ -224,17 +224,17 @@ module.exports = {
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
permissions_users: {
|
|
|
|
|
permissions_users: {// 权限用户关联表
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
user_id: {type: 'string', maxlength: 24, nullable: false},
|
|
|
|
|
permission_id: {type: 'string', maxlength: 24, nullable: false}
|
|
|
|
|
},
|
|
|
|
|
permissions_roles: {
|
|
|
|
|
permissions_roles: {// 权限角色关联表
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
role_id: {type: 'string', maxlength: 24, nullable: false},
|
|
|
|
|
permission_id: {type: 'string', maxlength: 24, nullable: false}
|
|
|
|
|
},
|
|
|
|
|
settings: {
|
|
|
|
|
settings: {// 设置
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
group: {
|
|
|
|
|
type: 'string',
|
|
|
|
|
@ -278,7 +278,7 @@ module.exports = {
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
tags: {
|
|
|
|
|
tags: {// 标签
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
name: {type: 'string', maxlength: 191, nullable: false, validations: {matches: /^([^,]|$)/}},
|
|
|
|
|
slug: {type: 'string', maxlength: 191, nullable: false, unique: true},
|
|
|
|
|
@ -307,7 +307,7 @@ module.exports = {
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
posts_tags: {
|
|
|
|
|
posts_tags: {// 文章标签关联表
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
post_id: {type: 'string', maxlength: 24, nullable: false, references: 'posts.id'},
|
|
|
|
|
tag_id: {type: 'string', maxlength: 24, nullable: false, references: 'tags.id'},
|
|
|
|
|
@ -316,7 +316,7 @@ module.exports = {
|
|
|
|
|
['post_id','tag_id']
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
invites: {
|
|
|
|
|
invites: { // 邀请
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
role_id: {type: 'string', maxlength: 24, nullable: false},
|
|
|
|
|
status: {
|
|
|
|
|
@ -332,14 +332,14 @@ module.exports = {
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
brute: {
|
|
|
|
|
brute: {// 暴力破解
|
|
|
|
|
key: {type: 'string', maxlength: 191, primary: true},
|
|
|
|
|
firstRequest: {type: 'bigInteger'},
|
|
|
|
|
lastRequest: {type: 'bigInteger'},
|
|
|
|
|
lifetime: {type: 'bigInteger'},
|
|
|
|
|
count: {type: 'integer'}
|
|
|
|
|
},
|
|
|
|
|
sessions: {
|
|
|
|
|
sessions: {// 会话
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
session_id: {type: 'string', maxlength: 32, nullable: false, unique: true},
|
|
|
|
|
user_id: {type: 'string', maxlength: 24, nullable: false},
|
|
|
|
|
@ -347,7 +347,7 @@ module.exports = {
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
integrations: {
|
|
|
|
|
integrations: {// 集成
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
type: {
|
|
|
|
|
type: 'string',
|
|
|
|
|
@ -363,12 +363,12 @@ module.exports = {
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true}
|
|
|
|
|
},
|
|
|
|
|
webhooks: {
|
|
|
|
|
webhooks: {//用于实现事件驱动的外部系统集成,当系统中发生特定时间的时候,会自动向配置的外部url发送http通知
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
event: {type: 'string', maxlength: 50, nullable: false, validations: {isLowercase: true}},
|
|
|
|
|
target_url: {type: 'string', maxlength: 2000, nullable: false},
|
|
|
|
|
name: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
secret: {type: 'string', maxlength: 191, nullable: true},
|
|
|
|
|
event: {type: 'string', maxlength: 50, nullable: false, validations: {isLowercase: true}},// 事件类型
|
|
|
|
|
target_url: {type: 'string', maxlength: 2000, nullable: false},// 目标url
|
|
|
|
|
name: {type: 'string', maxlength: 191, nullable: true},// 名称
|
|
|
|
|
secret: {type: 'string', maxlength: 191, nullable: true},// 密钥
|
|
|
|
|
// @NOTE: the defaultTo does not make sense to set on DB layer as it leads to unnecessary maintenance every major release
|
|
|
|
|
// would be ideal if we can remove the default and instead have "isIn" validation checking if it's a valid version e.g: 'v3', 'v4', 'canary'
|
|
|
|
|
api_version: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'v2'},
|
|
|
|
|
@ -389,14 +389,14 @@ module.exports = {
|
|
|
|
|
nullable: false,
|
|
|
|
|
validations: {isIn: [['content', 'admin']]}
|
|
|
|
|
},
|
|
|
|
|
secret: {
|
|
|
|
|
secret: { //密钥字符串
|
|
|
|
|
type: 'string',
|
|
|
|
|
maxlength: 191,
|
|
|
|
|
nullable: false,
|
|
|
|
|
unique: true,
|
|
|
|
|
unique: true,//防止出现重复
|
|
|
|
|
validations: {isLength: {min: 26, max: 128}}
|
|
|
|
|
},
|
|
|
|
|
role_id: {type: 'string', maxlength: 24, nullable: true},
|
|
|
|
|
role_id: {type: 'string', maxlength: 24, nullable: true}, // 角色ID:关联到roles表,定义密钥的权限级别
|
|
|
|
|
// integration_id is nullable to allow "internal" API keys that don't show in the UI
|
|
|
|
|
integration_id: {type: 'string', maxlength: 24, nullable: true},
|
|
|
|
|
user_id: {type: 'string', maxlength: 24, nullable: true},
|
|
|
|
|
@ -427,7 +427,7 @@ module.exports = {
|
|
|
|
|
feature_image_caption: {type: 'text', maxlength: 65535, nullable: true},
|
|
|
|
|
custom_excerpt: {type: 'string', maxlength: 2000, nullable: true, validations: {isLength: {max: 300}}}
|
|
|
|
|
},
|
|
|
|
|
members: {
|
|
|
|
|
members: {// 会员
|
|
|
|
|
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
|
|
|
|
|
uuid: {type: 'string', maxlength: 36, nullable: false, unique: true, validations: {isUUID: true}},
|
|
|
|
|
transient_id: {type: 'string', maxlength: 191, nullable: false, unique: true},
|
|
|
|
|
@ -450,7 +450,7 @@ module.exports = {
|
|
|
|
|
last_commented_at: {type: 'dateTime', nullable: true},
|
|
|
|
|
created_at: {type: 'dateTime', nullable: false},
|
|
|
|
|
updated_at: {type: 'dateTime', nullable: true},
|
|
|
|
|
'@@INDEXES@@': [
|
|
|
|
|
'@@INDEXES@@': [ // 索引
|
|
|
|
|
['email_disabled']
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
|