feat: publish Dever core with project scaffolding and versioned AI skills
This commit is contained in:
1 parent
70fa73cdc2
commit
ac458ffa7f
960 files changed
+221319
-1163
No files matched your search
@@ -0,0 +1,58 @@
|
||||
# 后台文章接口
|
||||
|
||||
普通管理使用 Model REST,发布保留为业务动作。
|
||||
|
||||
- 包:`news.article.api.admin.manage`
|
||||
- 公开类型:无
|
||||
- 公开方法:无
|
||||
- 使用:无
|
||||
|
||||
## get list
|
||||
|
||||
普通管理使用 Model REST,发布保留为业务动作。
|
||||
|
||||
- 声明:`get list`
|
||||
|
||||
```dever
|
||||
get list = app.list
|
||||
```
|
||||
|
||||
## get detail
|
||||
|
||||
普通管理使用 Model REST,发布保留为业务动作。
|
||||
|
||||
- 声明:`get detail`
|
||||
|
||||
```dever
|
||||
get detail = app.detail
|
||||
```
|
||||
|
||||
## post create
|
||||
|
||||
普通管理使用 Model REST,发布保留为业务动作。
|
||||
|
||||
- 声明:`post create`
|
||||
|
||||
```dever
|
||||
post create = app.create
|
||||
```
|
||||
|
||||
## delete remove
|
||||
|
||||
普通管理使用 Model REST,发布保留为业务动作。
|
||||
|
||||
- 声明:`delete remove`
|
||||
|
||||
```dever
|
||||
delete remove = app.remove
|
||||
```
|
||||
|
||||
## 发布文章
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 声明:`post publish`
|
||||
|
||||
```dever
|
||||
post publish = app.publish
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
# 前台文章接口
|
||||
|
||||
前台只查询已发布内容,不开放自动 REST 写路由。
|
||||
|
||||
- 包:`news.article.api.front.browse`
|
||||
- 公开类型:无
|
||||
- 公开方法:无
|
||||
- 使用:无
|
||||
|
||||
## 文章列表
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 声明:`get list`
|
||||
|
||||
```dever
|
||||
get list = app.published
|
||||
```
|
||||
|
||||
## 文章详情
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 声明:`get detail`
|
||||
|
||||
```dever
|
||||
get detail = app.published_detail
|
||||
```
|
||||
@@ -0,0 +1,244 @@
|
||||
# news.article.app.editing
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 包:`news.article.app.editing`
|
||||
- 公开类型:
|
||||
- `ArticleView`
|
||||
- `ArticlePage`
|
||||
- 公开方法:
|
||||
- `create`
|
||||
- `list`
|
||||
- `detail`
|
||||
- `remove`
|
||||
- `edit`
|
||||
- `require_schedulable`
|
||||
- 使用:
|
||||
- `news.article.create(slug, title, body, category_id, asset_id)`
|
||||
- `news.article.list(size)`
|
||||
- `news.article.detail(id)`
|
||||
- `news.article.remove(id)`
|
||||
- `news.article.edit(id, expected_version, title, body, category_id, asset_id)`
|
||||
- `news.article.require_schedulable(article_id)`
|
||||
|
||||
## ArticleView
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 类型:`ArticleView`
|
||||
- 字段:
|
||||
- `id: model.id`:记录标识
|
||||
- `slug: Text`:规范化标识
|
||||
- `title: Text`:文章标题
|
||||
- `body: Text`:正文
|
||||
- `version: Int`:当前编辑版本
|
||||
- `category_id: content.category.model.id?`:可选分类引用
|
||||
- `asset_id: media.asset.model.id?`:可选媒体引用
|
||||
|
||||
```dever
|
||||
type ArticleView {
|
||||
id: model.id
|
||||
slug: Text
|
||||
title: Text
|
||||
body: Text
|
||||
version: Int
|
||||
category_id: content.category.model.id?
|
||||
asset_id: media.asset.model.id?
|
||||
}
|
||||
```
|
||||
|
||||
## ArticlePage
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 类型:`ArticlePage`
|
||||
- 字段:
|
||||
- `rows: List<ArticleView>`:页面记录
|
||||
- `total: Int`:所有权范围内总数
|
||||
|
||||
```dever
|
||||
type ArticlePage {
|
||||
rows: List<ArticleView>
|
||||
total: Int
|
||||
}
|
||||
```
|
||||
|
||||
## create
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 函数:`create`
|
||||
- 输入:
|
||||
- `slug: Text`:规范化标识
|
||||
- `title: Text`:文章标题
|
||||
- `body: Text`:正文
|
||||
- `category_id: content.category.model.id?`:可选分类引用
|
||||
- `asset_id: media.asset.model.id?`:可选媒体引用
|
||||
- 输出:
|
||||
- `article: ArticleView`:该声明的业务值
|
||||
|
||||
```dever
|
||||
create(
|
||||
slug: Text,
|
||||
title: Text,
|
||||
body: Text,
|
||||
category_id: content.category.model.id?,
|
||||
asset_id: media.asset.model.id?
|
||||
) (article: ArticleView) {
|
||||
normalized_slug = domain.normalize_slug(slug)
|
||||
normalized_title = domain.normalize_title(title)
|
||||
domain.require_content(normalized_slug, normalized_title, body)
|
||||
content.category.require_active(category_id)
|
||||
media.asset.require_ready(asset_id)
|
||||
stored = model.create(
|
||||
{
|
||||
author_id = user.account.current_user()
|
||||
slug = normalized_slug
|
||||
title = normalized_title
|
||||
body = body
|
||||
category_id = category_id
|
||||
asset_id = asset_id
|
||||
}
|
||||
)
|
||||
article = detail(stored.id)
|
||||
}
|
||||
```
|
||||
|
||||
## list
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 函数:`list`
|
||||
- 输入:
|
||||
- `size: Int`:受限页大小
|
||||
- 输出:
|
||||
- `articles: ArticlePage`:该声明的业务值
|
||||
|
||||
```dever
|
||||
list(size: Int) (articles: ArticlePage) {
|
||||
author = user.account.current_user()
|
||||
articles = ArticlePage {
|
||||
rows = model.owned_articles(author, domain.page_size(size))
|
||||
total = model.count(
|
||||
{
|
||||
where = author_id == author
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## detail
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 函数:`detail`
|
||||
- 输入:
|
||||
- `id: news.article.model.id`:记录标识
|
||||
- 输出:
|
||||
- `article: ArticleView`:该声明的业务值
|
||||
|
||||
```dever
|
||||
detail(id: model.id) (article: ArticleView) {
|
||||
stored = model.get(id)
|
||||
domain.require_owner(dever.auth.owns_user(stored.author_id))
|
||||
article = ArticleView {
|
||||
id = stored.id
|
||||
slug = stored.slug
|
||||
title = stored.title
|
||||
body = stored.body
|
||||
version = stored.version
|
||||
category_id = stored.category_id
|
||||
asset_id = stored.asset_id
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## remove
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 函数:`remove`
|
||||
- 输入:
|
||||
- `id: news.article.model.id`:记录标识
|
||||
- 输出:
|
||||
- `removed: Int`:该声明的业务值
|
||||
|
||||
```dever
|
||||
remove(id: model.id) (removed: Int) {
|
||||
stored = model.get(id)
|
||||
domain.require_owner(dever.auth.owns_user(stored.author_id))
|
||||
domain.require_draft(stored.status == model.ArticleStatus.Draft)
|
||||
removed = model.delete(
|
||||
{
|
||||
where = id == stored.id and version == stored.version
|
||||
}
|
||||
)
|
||||
domain.require_updated(removed)
|
||||
}
|
||||
```
|
||||
|
||||
## edit
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 函数:`edit`
|
||||
- 输入:
|
||||
- `id: news.article.model.id`:记录标识
|
||||
- `expected_version: Int`:调用者读取的编辑版本
|
||||
- `title: Text`:文章标题
|
||||
- `body: Text`:正文
|
||||
- `category_id: content.category.model.id?`:可选分类引用
|
||||
- `asset_id: media.asset.model.id?`:可选媒体引用
|
||||
- 输出:
|
||||
- `article: ArticleView`:该声明的业务值
|
||||
|
||||
```dever
|
||||
edit(
|
||||
id: model.id,
|
||||
expected_version: Int,
|
||||
title: Text,
|
||||
body: Text,
|
||||
category_id: content.category.model.id?,
|
||||
asset_id: media.asset.model.id?
|
||||
) (article: ArticleView) {
|
||||
stored = model.get(id)
|
||||
domain.require_owner(dever.auth.owns_user(stored.author_id))
|
||||
domain.require_draft(stored.status == model.ArticleStatus.Draft)
|
||||
normalized_title = domain.normalize_title(title)
|
||||
domain.require_content(stored.slug, normalized_title, body)
|
||||
content.category.require_active(category_id)
|
||||
media.asset.require_ready(asset_id)
|
||||
changed = model.update(
|
||||
{
|
||||
where = id == stored.id and version == expected_version and status == model.ArticleStatus.Draft
|
||||
},
|
||||
{
|
||||
title = normalized_title
|
||||
body = body
|
||||
category_id = category_id
|
||||
asset_id = asset_id
|
||||
version = expected_version + 1
|
||||
}
|
||||
)
|
||||
domain.require_updated(changed)
|
||||
article = detail(stored.id)
|
||||
}
|
||||
```
|
||||
|
||||
## require_schedulable
|
||||
|
||||
文章创建、所有权查询与带版本的编辑;所有写入校验分类和媒体引用。
|
||||
|
||||
- 函数:`require_schedulable`
|
||||
- 输入:
|
||||
- `article_id: news.article.model.id`:文章标识
|
||||
- 输出:无
|
||||
|
||||
```dever
|
||||
require_schedulable(article_id: model.id) () {
|
||||
stored = model.get(article_id)
|
||||
domain.require_owner(dever.auth.owns_user(stored.author_id))
|
||||
domain.require_draft(stored.status == model.ArticleStatus.Draft)
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,203 @@
|
||||
# news.article.app.publication
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 包:`news.article.app.publication`
|
||||
- 公开类型:无
|
||||
- 公开方法:
|
||||
- `publish`
|
||||
- `published`
|
||||
- `published_detail`
|
||||
- `publish_scheduled`
|
||||
- `scheduled_publication`
|
||||
- `publish_draft`
|
||||
- `existing_publication`
|
||||
- 使用:
|
||||
- `news.article.publish(article_id)`
|
||||
- `news.article.published(size)`
|
||||
- `news.article.published_detail(id)`
|
||||
- `news.article.publish_scheduled(article_id)`
|
||||
- `news.article.scheduled_publication(status, article_id)`
|
||||
- `news.article.publish_draft(article_id)`
|
||||
- `news.article.existing_publication(stored)`
|
||||
|
||||
## publish
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 函数:`publish`
|
||||
- 输入:
|
||||
- `article_id: news.article.model.id`:文章标识
|
||||
- 输出:
|
||||
- `publication: news.article.model.publication.Publication`:该声明的业务值
|
||||
|
||||
```dever
|
||||
transaction publish(article_id: model.id) (publication: model.publication.Publication) {
|
||||
stored = model.get(article_id)
|
||||
domain.require_owner(dever.auth.owns_user(stored.author_id))
|
||||
domain.require_draft(stored.status == model.ArticleStatus.Draft)
|
||||
publication = publish_draft(article_id)
|
||||
}
|
||||
```
|
||||
|
||||
## published
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 函数:`published`
|
||||
- 输入:
|
||||
- `size: Int`:受限页大小
|
||||
- 输出:
|
||||
- `articles: news.article.model.publication.Page`:该声明的业务值
|
||||
|
||||
```dever
|
||||
published(size: Int) (articles: model.publication.Page) {
|
||||
articles = model.publication.list(
|
||||
{
|
||||
order = [published_at.desc, id.desc]
|
||||
size = domain.page_size(size)
|
||||
}
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## published_detail
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 函数:`published_detail`
|
||||
- 输入:
|
||||
- `id: news.article.model.publication.id`:记录标识
|
||||
- 输出:
|
||||
- `article: news.article.model.publication.Publication`:该声明的业务值
|
||||
|
||||
```dever
|
||||
published_detail(id: model.publication.id) (article: model.publication.Publication) {
|
||||
article = model.publication.get(id)
|
||||
domain.require_published(text.trim(article.body) != "")
|
||||
}
|
||||
```
|
||||
|
||||
## publish_scheduled
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 函数:`publish_scheduled`
|
||||
- 输入:
|
||||
- `article_id: news.article.model.id`:文章标识
|
||||
- 输出:
|
||||
- `publication: news.article.model.publication.Publication`:该声明的业务值
|
||||
|
||||
```dever
|
||||
transaction publish_scheduled(article_id: model.id) (
|
||||
publication: model.publication.Publication
|
||||
) {
|
||||
stored = model.get(article_id)
|
||||
publication = scheduled_publication(stored.status, article_id)
|
||||
}
|
||||
```
|
||||
|
||||
## scheduled_publication
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 函数:`scheduled_publication`
|
||||
- 输入:
|
||||
- `status: news.article.model.ArticleStatus`:业务状态
|
||||
- `article_id: news.article.model.id`:文章标识
|
||||
- 输出:
|
||||
- `publication: news.article.model.publication.Publication`:该声明的业务值
|
||||
|
||||
```dever
|
||||
scheduled_publication(status: model.ArticleStatus.Published, article_id: model.id) (
|
||||
publication: model.publication.Publication
|
||||
) {
|
||||
stored = model.get(article_id)
|
||||
publication = existing_publication(
|
||||
model.publication.first(
|
||||
{
|
||||
where = slug == stored.slug
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
scheduled_publication(status: model.ArticleStatus.Draft, article_id: model.id) (
|
||||
publication: model.publication.Publication
|
||||
) {
|
||||
publication = publish_draft(article_id)
|
||||
}
|
||||
```
|
||||
|
||||
## publish_draft
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 函数:`publish_draft`
|
||||
- 输入:
|
||||
- `article_id: news.article.model.id`:文章标识
|
||||
- 输出:
|
||||
- `publication: news.article.model.publication.Publication`:该声明的业务值
|
||||
|
||||
```dever
|
||||
publish_draft(article_id: model.id) (publication: model.publication.Publication) {
|
||||
stored = model.get(article_id)
|
||||
domain.require_draft(stored.status == model.ArticleStatus.Draft)
|
||||
content.category.require_active(stored.category_id)
|
||||
media.asset.require_ready(stored.asset_id)
|
||||
published_at = dever.time.now()
|
||||
changed = model.update(
|
||||
{
|
||||
where = id == stored.id and version == stored.version and status == model.ArticleStatus.Draft
|
||||
},
|
||||
{
|
||||
status = model.ArticleStatus.Published
|
||||
published_at = published_at
|
||||
version = stored.version + 1
|
||||
}
|
||||
)
|
||||
domain.require_updated(changed)
|
||||
audit.operation.record(
|
||||
audit.operation.model.OperationKind.Publish,
|
||||
"article",
|
||||
stored.slug
|
||||
)
|
||||
publication = model.publication.upsert(
|
||||
{
|
||||
slug = stored.slug
|
||||
},
|
||||
{
|
||||
title = stored.title
|
||||
body = stored.body
|
||||
published_at = published_at
|
||||
},
|
||||
{
|
||||
title = stored.title
|
||||
body = stored.body
|
||||
published_at = published_at
|
||||
}
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## existing_publication
|
||||
|
||||
手动发布和定时任务共用原子发布流程,发布快照与审计同步提交。
|
||||
|
||||
- 函数:`existing_publication`
|
||||
- 输入:
|
||||
- `stored: news.article.model.publication.Publication?`:该声明的业务值
|
||||
- 输出:
|
||||
- `publication: news.article.model.publication.Publication`:该声明的业务值
|
||||
|
||||
```dever
|
||||
existing_publication(stored: model.publication.Publication) (
|
||||
publication: model.publication.Publication
|
||||
) {
|
||||
publication = stored
|
||||
}
|
||||
|
||||
existing_publication(stored: null) (publication: model.publication.Publication) {
|
||||
fail(dever.api.Error.NotFound)
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,162 @@
|
||||
# 文章规则
|
||||
|
||||
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
|
||||
|
||||
- 包:`news.article.domain`
|
||||
- 公开类型:无
|
||||
- 公开方法:无
|
||||
- 使用:无
|
||||
|
||||
## 规范文章标识
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 函数:`normalize_slug`
|
||||
- 输入:
|
||||
- `value: Text`:该声明的业务值
|
||||
- 输出:
|
||||
- `slug: Text`:规范化标识
|
||||
|
||||
```dever
|
||||
normalize_slug(value: Text) (slug: Text) pure {
|
||||
slug = text.lower(text.trim(value))
|
||||
}
|
||||
```
|
||||
|
||||
## 规范标题
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 函数:`normalize_title`
|
||||
- 输入:
|
||||
- `value: Text`:该声明的业务值
|
||||
- 输出:
|
||||
- `title: Text`:文章标题
|
||||
|
||||
```dever
|
||||
normalize_title(value: Text) (title: Text) pure {
|
||||
title = text.trim(value)
|
||||
}
|
||||
```
|
||||
|
||||
## 限制分页大小
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 函数:`page_size`
|
||||
- 输入:
|
||||
- `value: Int`:该声明的业务值
|
||||
- 输出:
|
||||
- `size: Int`:受限页大小
|
||||
|
||||
```dever
|
||||
page_size(value: Int >= 1 and <= 100) (size: Int) pure {
|
||||
size = value
|
||||
}
|
||||
|
||||
page_size(value: other) (size: Int) pure {
|
||||
fail(dever.api.Error.Invalid)
|
||||
}
|
||||
```
|
||||
|
||||
## 检查草稿状态
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 函数:`require_draft`
|
||||
- 输入:
|
||||
- `draft: Bool`:该声明的业务值
|
||||
- 输出:无
|
||||
|
||||
```dever
|
||||
require_draft(draft: true) () pure {}
|
||||
|
||||
require_draft(draft: false) () pure {
|
||||
fail(dever.api.Error.Conflict)
|
||||
}
|
||||
```
|
||||
|
||||
## 检查文章所有权
|
||||
|
||||
发布操作只允许文章作者执行。
|
||||
|
||||
- 函数:`require_owner`
|
||||
- 输入:
|
||||
- `owned: Bool`:该声明的业务值
|
||||
- 输出:无
|
||||
|
||||
```dever
|
||||
require_owner(owned: true) () pure {}
|
||||
|
||||
require_owner(owned: false) () pure {
|
||||
fail(dever.api.Error.Forbidden)
|
||||
}
|
||||
```
|
||||
|
||||
## require_published
|
||||
|
||||
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
|
||||
|
||||
- 函数:`require_published`
|
||||
- 输入:
|
||||
- `published: Bool`:该声明的业务值
|
||||
- 输出:无
|
||||
|
||||
```dever
|
||||
require_published(published: true) () pure {}
|
||||
|
||||
require_published(published: false) () pure {
|
||||
fail(dever.api.Error.NotFound)
|
||||
}
|
||||
```
|
||||
|
||||
## require_updated
|
||||
|
||||
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
|
||||
|
||||
- 函数:`require_updated`
|
||||
- 输入:
|
||||
- `changed: Int`:条件更新影响行数
|
||||
- 输出:无
|
||||
|
||||
```dever
|
||||
require_updated(changed: 1) () pure {}
|
||||
|
||||
require_updated(changed: other) () pure {
|
||||
fail(dever.api.Error.Conflict)
|
||||
}
|
||||
```
|
||||
|
||||
## require_content
|
||||
|
||||
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
|
||||
|
||||
- 函数:`require_content`
|
||||
- 输入:
|
||||
- `slug: Text`:规范化标识
|
||||
- `title: Text`:文章标题
|
||||
- `body: Text`:正文
|
||||
- 输出:无
|
||||
|
||||
```dever
|
||||
require_content(slug: Text, title: Text, body: Text) () pure {
|
||||
require_valid(slug != "" and title != "" and text.trim(body) != "")
|
||||
}
|
||||
```
|
||||
|
||||
## require_valid
|
||||
|
||||
文章字段规范化、分页边界和发布状态规则集中在纯 Domain。
|
||||
|
||||
- 函数:`require_valid`
|
||||
- 输入:
|
||||
- `valid: Bool`:该声明的业务值
|
||||
- 输出:无
|
||||
|
||||
```dever
|
||||
require_valid(valid: true) () pure {}
|
||||
|
||||
require_valid(valid: false) () pure {
|
||||
fail(dever.api.Error.Invalid)
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,86 @@
|
||||
# 文章模型
|
||||
|
||||
草稿位于租户数据库,REST 由可信用户 owner 限定到作者范围。
|
||||
|
||||
- 包:`news.article.model`
|
||||
- 公开类型:
|
||||
- `ArticleStatus`
|
||||
- `Article`
|
||||
- 公开方法:无
|
||||
- 使用:无
|
||||
|
||||
## 文章状态
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 类型:`ArticleStatus`
|
||||
- 分支:
|
||||
- `Draft`:该声明的业务值
|
||||
- `Published`:该声明的业务值
|
||||
|
||||
```dever
|
||||
type ArticleStatus {
|
||||
Draft = "草稿"
|
||||
Published = "已发布"
|
||||
}
|
||||
```
|
||||
|
||||
## 文章记录
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 类型:`Article`
|
||||
- 字段:
|
||||
- `private author_id: user.account.model.principal.id`:可信作者标识
|
||||
- `slug: Text(1, 180)`:规范化标识
|
||||
- `title: Text(1, 160)`:文章标题
|
||||
- `body: Text`:正文
|
||||
- `category_id: content.category.model.id?`:可选分类引用
|
||||
- `asset_id: media.asset.model.id?`:可选媒体引用
|
||||
- `private version: Int`:当前编辑版本
|
||||
- `private status: ArticleStatus`:业务状态
|
||||
- `private published_at: DateTime?`:实际发布时间
|
||||
|
||||
```dever
|
||||
type Article {
|
||||
private owner author_id: user.account.model.principal.id = dever.auth.user_id()
|
||||
slug: Text(1, 180) unique
|
||||
title: Text(1, 160)
|
||||
body: Text
|
||||
category_id: content.category.model.id?
|
||||
asset_id: media.asset.model.id?
|
||||
private version: Int default 1
|
||||
private status: ArticleStatus default ArticleStatus.Draft index
|
||||
private published_at: DateTime?
|
||||
}
|
||||
```
|
||||
|
||||
## 作者索引
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 声明:`index(author_id, created_at)`
|
||||
|
||||
```dever
|
||||
index(author_id, created_at)
|
||||
```
|
||||
|
||||
## sql owned_articles
|
||||
|
||||
草稿位于租户数据库,REST 由可信用户 owner 限定到作者范围。
|
||||
|
||||
- 声明:`sql owned_articles`
|
||||
- 输入:
|
||||
- `author: user.account.model.principal.id`:该声明的业务值
|
||||
- `size: Int`:受限页大小
|
||||
- 输出:
|
||||
- `articles: List<app.ArticleView>`:该声明的业务值
|
||||
|
||||
```dever
|
||||
sql owned_articles(author: user.account.model.principal.id, size: Int) (
|
||||
articles: List<app.ArticleView>
|
||||
) {
|
||||
sqlite = "SELECT id, slug, title, body, version, category_id, asset_id FROM article WHERE author_id = ?1 ORDER BY id DESC LIMIT ?2"
|
||||
postgres = "SELECT id, slug, title, body, version, category_id, asset_id FROM article WHERE author_id = $1 ORDER BY id DESC LIMIT $2"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
# 文章公开读模型
|
||||
|
||||
发布动作把可公开内容写入无私密字段的租户内读模型。
|
||||
|
||||
- 包:`news.article.model.publication`
|
||||
- 公开类型:
|
||||
- `Publication`
|
||||
- 公开方法:无
|
||||
- 使用:无
|
||||
|
||||
## 发布记录
|
||||
|
||||
本节定义对应的源码合同。
|
||||
|
||||
- 类型:`Publication`
|
||||
- 字段:
|
||||
- `slug: Text(1, 180)`:文章标识
|
||||
- `title: Text(1, 160)`:标题
|
||||
- `body: Text`:正文
|
||||
- `published_at: DateTime`:发布时间
|
||||
|
||||
```dever
|
||||
type Publication {
|
||||
slug: Text(1, 180) unique
|
||||
title: Text(1, 160)
|
||||
body: Text
|
||||
published_at: DateTime index
|
||||
}
|
||||
```
|
||||
Reference in new issue
Block a user