Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,24 @@
|
||||
# account
|
||||
|
||||
本领域的职责与行为见主题说明;函数签名和调用关系从源码读取。
|
||||
|
||||
## 说明
|
||||
|
||||
- [任务权限入口](doc/api-admin-jobs.md)
|
||||
- [请求元数据入口](doc/api-admin-metadata.md)
|
||||
- [自动资源接口](doc/api-admin-profile.md)
|
||||
- [角色接口](doc/api-admin-roles.md)
|
||||
- [Secret 输入验收](doc/api-admin-secret.md)
|
||||
- [身份认证接口](doc/api-admin-session.md)
|
||||
- [认证测试命令](doc/api.md)
|
||||
- [身份任务](doc/app-jobs.md)
|
||||
- [请求元数据业务](doc/app-metadata.md)
|
||||
- [角色业务验收](doc/app-roles.md)
|
||||
- [敏感 HTTP 输入](doc/app-secret.md)
|
||||
- [会话认证验收](doc/app-session.md)
|
||||
- [可信任务执行](doc/job.md)
|
||||
- [自动 REST 数据](doc/model-profile.md)
|
||||
- [租户身份类型](doc/model-tenant.md)
|
||||
- [全局会话账号](doc/model.md)
|
||||
|
||||
[调用流程](link.md)由 `dever inspect . --links` 生成。
|
||||
@@ -0,0 +1,5 @@
|
||||
cmd seed = app.seed
|
||||
|
||||
cmd set_deadline = app.setDeadline
|
||||
|
||||
cmd revoke = app.revoke
|
||||
@@ -0,0 +1,5 @@
|
||||
post job_submit = app.jobSubmit
|
||||
|
||||
cmd job_submit = app.jobSubmit
|
||||
|
||||
cmd job_count = app.jobCount
|
||||
@@ -0,0 +1,3 @@
|
||||
public post metadata = app.metadata
|
||||
|
||||
public post metadata_fail = app.metadataFail
|
||||
@@ -0,0 +1 @@
|
||||
rest model.profile
|
||||
@@ -0,0 +1,25 @@
|
||||
authenticated get permissions = app.permissions
|
||||
|
||||
authenticated get current_permissions = app.currentPermissions
|
||||
|
||||
authenticated get roles = app.roles
|
||||
|
||||
authenticated get role = app.role
|
||||
|
||||
authenticated get user_roles = app.userRoles
|
||||
|
||||
authenticated get is_owner = app.isOwner
|
||||
|
||||
post save_role = app.saveRole
|
||||
|
||||
post grant_role = app.grantRole
|
||||
|
||||
post revoke_role = app.revokeRole
|
||||
|
||||
post disable_role = app.disableRole
|
||||
|
||||
post delete_role = app.deleteRole
|
||||
|
||||
post role_fail = app.roleFail
|
||||
|
||||
get protected_me = app.me
|
||||
@@ -0,0 +1 @@
|
||||
public post probe = app.probe
|
||||
@@ -0,0 +1,11 @@
|
||||
authenticated get me = app.me
|
||||
|
||||
authenticated post me = app.me
|
||||
|
||||
public get health = app.health
|
||||
|
||||
public post login = app.login
|
||||
|
||||
public post logout = app.logout
|
||||
|
||||
public post login_fail = app.loginFail
|
||||
@@ -0,0 +1,11 @@
|
||||
type Work { subject: Text }
|
||||
|
||||
jobSubmit(subject: Text, key: Text) (id: Id) {
|
||||
id = dever.job.enqueue(job.perform, Work { subject = subject }, key)
|
||||
}
|
||||
|
||||
jobApply(input: Work) () {
|
||||
created = seed(input.subject, "from-job")
|
||||
}
|
||||
|
||||
jobCount() (total: Int) { total = model.count() }
|
||||
@@ -0,0 +1,22 @@
|
||||
type Metadata {
|
||||
request_id: Text
|
||||
method: Text
|
||||
path: Text
|
||||
address: Text
|
||||
header: Text?
|
||||
cookie: Text?
|
||||
}
|
||||
|
||||
metadata() (value: Metadata) {
|
||||
id = dever.api.requestId()
|
||||
dever.api.setHeader("X-Request-Id", id)
|
||||
dever.api.setCookie("theme", "dark", dever.api.secureCookieOptions())
|
||||
options = dever.api.CookieOptions { path = "/", domain = null, same_site = dever.api.SameSite.Strict, secure = true, http_only = true, max_age = 60 }
|
||||
dever.api.setCookie("strict", "yes", options)
|
||||
value = Metadata { request_id = id, method = dever.api.method(), path = dever.api.path(), address = dever.api.clientAddress(), header = dever.api.header("X-Test"), cookie = dever.api.cookie("theme") }
|
||||
}
|
||||
|
||||
metadataFail() () {
|
||||
value = metadata()
|
||||
fail(dever.api.Error.Conflict)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
permissions() (values: List<dever.auth.Permission>) {
|
||||
values = dever.auth.permissions()
|
||||
}
|
||||
|
||||
currentPermissions() (values: List<dever.auth.Permission>) {
|
||||
values = dever.auth.currentPermissions()
|
||||
}
|
||||
|
||||
roles() (values: List<dever.auth.Role>) {
|
||||
values = dever.auth.roles()
|
||||
}
|
||||
|
||||
role(id: Text) (value: dever.auth.Role?) {
|
||||
value = dever.auth.role(id)
|
||||
}
|
||||
|
||||
userRoles(user_id: Int) (values: List<dever.auth.Role>) {
|
||||
values = dever.auth.userRoles(user_id)
|
||||
}
|
||||
|
||||
isOwner(user_id: Int) (value: Bool) {
|
||||
value = dever.auth.isOwner(user_id)
|
||||
}
|
||||
|
||||
saveRole(id: Text, name: Text, all_permissions: Bool, permission_keys: List<Text>) () {
|
||||
dever.auth.saveRole(id, name, all_permissions, permission_keys)
|
||||
}
|
||||
|
||||
grantRole(user_id: Int, role_id: Text) () {
|
||||
dever.auth.grantRole(user_id, role_id)
|
||||
}
|
||||
|
||||
revokeRole(user_id: Int, role_id: Text) () {
|
||||
dever.auth.revokeRole(user_id, role_id)
|
||||
}
|
||||
|
||||
disableRole(role_id: Text) () {
|
||||
dever.auth.disableRole(role_id)
|
||||
}
|
||||
|
||||
deleteRole(role_id: Text) () {
|
||||
dever.auth.deleteRole(role_id)
|
||||
}
|
||||
|
||||
roleFail(id: Text) () {
|
||||
dever.auth.saveRole(id, "failed", false, [])
|
||||
fail(dever.api.Error.Conflict)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
type Credentials { key: Secret }
|
||||
|
||||
probe(input: Credentials) (size: Int) {
|
||||
digest = dever.crypto.hmacSha256(input.key, dever.bytes.fromText("fixture"))
|
||||
size = length(digest)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
type Identity {
|
||||
id: Text
|
||||
user_id: model.id?
|
||||
tenant_id: model.tenant.id?
|
||||
}
|
||||
|
||||
verify(claims: dever.auth.Claims) (verified: Identity) {
|
||||
account = model.first({ where = subject == claims.subject and session == claims.session and active == true and expires_at > dever.time.unixMillis() })
|
||||
verified = identity(account)
|
||||
}
|
||||
|
||||
identity(account: model.Account) (verified: Identity) {
|
||||
verified = Identity { id = account.subject, user_id = account.id, tenant_id = null }
|
||||
}
|
||||
identity(account: null) (verified: Identity) { fail(dever.api.Error.Unauthorized) }
|
||||
|
||||
seed(subject: Text, session: Text) (account: model.Account) {
|
||||
account = model.create({ subject = subject, session = session, active = true, expires_at = dever.time.unixMillis() + 600000 })
|
||||
}
|
||||
|
||||
setDeadline(id: model.id, expires: Int) (deadline: Int) {
|
||||
account = model.update(id, { expires_at = expires })
|
||||
deadline = account.expires_at
|
||||
}
|
||||
|
||||
revoke(id: model.id) (disabled: Bool) {
|
||||
account = model.update(id, { active = false })
|
||||
disabled = not account.active
|
||||
}
|
||||
|
||||
me() (profile: Profile) {
|
||||
profile = Profile { id = dever.auth.id(), session = dever.auth.session(), site = dever.site.key(), user_id = dever.auth.userId(), tenant_id = dever.auth.tenantId() }
|
||||
}
|
||||
|
||||
health() (ready: Bool) { ready = true }
|
||||
|
||||
type Profile { id: Text
|
||||
session: Text
|
||||
site: Text
|
||||
user_id: model.id?
|
||||
tenant_id: model.tenant.id?
|
||||
}
|
||||
|
||||
login(subject: Text, session: Text) () {
|
||||
verified = verify(dever.auth.Claims { subject = subject, session = session, tenant = null, site = dever.site.key() })
|
||||
dever.auth.issueCookie(verified.id, session, null)
|
||||
}
|
||||
|
||||
logout() () { dever.auth.clearCookie() }
|
||||
|
||||
loginFail(subject: Text, session: Text) () {
|
||||
login(subject, session)
|
||||
fail(dever.api.Error.Conflict)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# 任务权限入口
|
||||
|
||||
只有受保护入口才能以 User 身份提交任务。
|
||||
|
||||
### submit
|
||||
|
||||
权限成功后保存可信上下文。
|
||||
|
||||
### system
|
||||
|
||||
本机命令拥有明确 System 身份。
|
||||
|
||||
### count
|
||||
|
||||
本机读取业务结果。
|
||||
@@ -0,0 +1,11 @@
|
||||
# 请求元数据入口
|
||||
|
||||
公开 POST 也遵守 Cookie 写入的同源要求。
|
||||
|
||||
### metadata
|
||||
|
||||
成功时发布头与 Cookie。
|
||||
|
||||
### metadata_fail
|
||||
|
||||
失败时丢弃暂存响应字段。
|
||||
@@ -0,0 +1,7 @@
|
||||
# 自动资源接口
|
||||
|
||||
生成受保护的列表、详情、创建、替换与删除接口。
|
||||
|
||||
### resource
|
||||
|
||||
显式选择同领域 Model topic。
|
||||
@@ -0,0 +1,55 @@
|
||||
# 角色接口
|
||||
|
||||
写入仅允许受保护 API;读取允许已认证用户。
|
||||
|
||||
### permissions
|
||||
|
||||
已认证读取当前站点。
|
||||
|
||||
### current_permissions
|
||||
|
||||
已认证读取当前站点。
|
||||
|
||||
### roles
|
||||
|
||||
已认证读取当前站点。
|
||||
|
||||
### role
|
||||
|
||||
已认证读取当前站点。
|
||||
|
||||
### user_roles
|
||||
|
||||
已认证读取当前站点。
|
||||
|
||||
### is_owner
|
||||
|
||||
已认证读取当前站点。
|
||||
|
||||
### save_role
|
||||
|
||||
执行前核验精确角色权限。
|
||||
|
||||
### grant_role
|
||||
|
||||
执行前核验精确角色权限。
|
||||
|
||||
### revoke_role
|
||||
|
||||
执行前核验精确角色权限。
|
||||
|
||||
### disable_role
|
||||
|
||||
执行前核验精确角色权限。
|
||||
|
||||
### delete_role
|
||||
|
||||
执行前核验精确角色权限。
|
||||
|
||||
### role_fail
|
||||
|
||||
执行前核验精确角色权限。
|
||||
|
||||
### protected_me
|
||||
|
||||
只有持有本入口权限的可信用户才能读取。
|
||||
@@ -0,0 +1,7 @@
|
||||
# Secret 输入验收
|
||||
|
||||
验证合法敏感输入不被输出 codec 错误拒绝。
|
||||
|
||||
### probe
|
||||
|
||||
通过 JSON 输入 Secret record。
|
||||
@@ -0,0 +1,27 @@
|
||||
# 身份认证接口
|
||||
|
||||
authenticated 仅验证身份;角色授权入口仍使用独立的权限检查。
|
||||
|
||||
### read
|
||||
|
||||
未认证请求不能执行 App。
|
||||
|
||||
### write
|
||||
|
||||
Cookie 非安全方法必须进行同源检查。
|
||||
|
||||
### health
|
||||
|
||||
允许匿名访问的单个声明。
|
||||
|
||||
### login
|
||||
|
||||
登录入口验证凭据之后签发 Cookie。
|
||||
|
||||
### logout
|
||||
|
||||
匿名也能清除旧 Cookie,但不能绕过同源检查。
|
||||
|
||||
### login_fail
|
||||
|
||||
业务失败时不发布 Cookie。
|
||||
@@ -0,0 +1,15 @@
|
||||
# 认证测试命令
|
||||
|
||||
测试命令只操作自有临时数据库。
|
||||
|
||||
### seed
|
||||
|
||||
创建测试账号。
|
||||
|
||||
### set_deadline
|
||||
|
||||
调整本测试数据库的会话截止时间。
|
||||
|
||||
### revoke
|
||||
|
||||
禁用测试账号。
|
||||
@@ -0,0 +1,32 @@
|
||||
# 身份任务
|
||||
|
||||
排队身份由入口建立,payload 只包含业务名称。
|
||||
|
||||
## demo.account.Work
|
||||
|
||||
保存业务输入。
|
||||
|
||||
字段:`subject`:名称
|
||||
|
||||
## demo.account.jobSubmit
|
||||
|
||||
提交任务,不能用输入替代执行者。
|
||||
|
||||
输入:
|
||||
- `subject`:名称
|
||||
- `key`:幂等键
|
||||
输出:`id`:任务 ID
|
||||
|
||||
## demo.account.jobApply
|
||||
|
||||
通过已有账号业务保存任务结果。
|
||||
|
||||
输入:`input`:业务数据
|
||||
输出:无
|
||||
|
||||
## demo.account.jobCount
|
||||
|
||||
从独立命令读取已提交结果数量。
|
||||
|
||||
输入:无
|
||||
输出:`total`:账号数量
|
||||
@@ -0,0 +1,29 @@
|
||||
# 请求元数据业务
|
||||
|
||||
读取直接请求信息,并暂存成功响应的头和 Cookie。
|
||||
|
||||
## demo.account.Metadata
|
||||
|
||||
输出不含身份令牌或敏感请求头。
|
||||
|
||||
字段:
|
||||
- `request_id`:请求标识
|
||||
- `method`:方法
|
||||
- `path`:路径
|
||||
- `address`:直接客户端 IP
|
||||
- `header`:自定义测试头
|
||||
- `cookie`:普通 Cookie
|
||||
|
||||
## demo.account.metadata
|
||||
|
||||
读取当前请求,并为成功响应设置元数据。
|
||||
|
||||
输入:无
|
||||
输出:`value`:元数据
|
||||
|
||||
## demo.account.metadataFail
|
||||
|
||||
业务失败时必须丢弃之前暂存的元数据。
|
||||
|
||||
输入:无
|
||||
输出:无
|
||||
@@ -0,0 +1,101 @@
|
||||
# 角色业务验收
|
||||
|
||||
通过 Dever 标准库操作当前站点角色,用真实 HTTP 验证事务和权限。
|
||||
|
||||
## demo.account.permissions
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:无
|
||||
输出:`values`:授权结果
|
||||
|
||||
## demo.account.currentPermissions
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:无
|
||||
输出:`values`:授权结果
|
||||
|
||||
## demo.account.roles
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:无
|
||||
输出:`values`:授权结果
|
||||
|
||||
## demo.account.role
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `id`:授权参数
|
||||
输出:`value`:授权结果
|
||||
|
||||
## demo.account.userRoles
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `user_id`:授权参数
|
||||
输出:`values`:授权结果
|
||||
|
||||
## demo.account.isOwner
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `user_id`:授权参数
|
||||
输出:`value`:授权结果
|
||||
|
||||
## demo.account.saveRole
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `id`:授权参数
|
||||
- `name`:授权参数
|
||||
- `all_permissions`:授权参数
|
||||
- `permission_keys`:授权参数
|
||||
输出:无
|
||||
|
||||
## demo.account.grantRole
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `user_id`:授权参数
|
||||
- `role_id`:授权参数
|
||||
输出:无
|
||||
|
||||
## demo.account.revokeRole
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `user_id`:授权参数
|
||||
- `role_id`:授权参数
|
||||
输出:无
|
||||
|
||||
## demo.account.disableRole
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `role_id`:授权参数
|
||||
输出:无
|
||||
|
||||
## demo.account.deleteRole
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `role_id`:授权参数
|
||||
输出:无
|
||||
|
||||
## demo.account.roleFail
|
||||
|
||||
复用当前入口的可信上下文和数据库事务。
|
||||
|
||||
输入:
|
||||
- `id`:授权参数
|
||||
输出:无
|
||||
@@ -0,0 +1,16 @@
|
||||
# 敏感 HTTP 输入
|
||||
|
||||
输入 record 可以包含 Secret,但不能生成该 record 的输出序列化器。
|
||||
|
||||
## demo.account.Credentials
|
||||
|
||||
密钥只能传给密码学函数。
|
||||
|
||||
字段:`key`:测试密钥
|
||||
|
||||
## demo.account.probe
|
||||
|
||||
只返回摘要的长度。
|
||||
|
||||
输入:`input`:密钥输入
|
||||
输出:`size`:摘要字节数
|
||||
@@ -0,0 +1,101 @@
|
||||
# 会话认证验收
|
||||
|
||||
Token 验证之后仍读取账号与会话状态;认证入口不能绕过此函数。
|
||||
|
||||
## demo.account.Identity
|
||||
|
||||
身份字段不携带权限,两个 ID 保持各自 Model 类型。
|
||||
|
||||
字段:
|
||||
- `id`:身份标识
|
||||
- `user_id`:用户 ID
|
||||
- `tenant_id`:租户 ID
|
||||
|
||||
## demo.account.verify
|
||||
|
||||
只读取全局库和当前时钟,校验账号、会话与服务端截止时间。
|
||||
|
||||
输入:`claims`:已签名的声明
|
||||
输出:`verified`:可信身份
|
||||
|
||||
## demo.account.identity
|
||||
|
||||
未找到有效会话时显式拒绝。
|
||||
|
||||
输入:`account`:匹配的账号
|
||||
输出:`verified`:可信身份
|
||||
|
||||
## demo.account.seed
|
||||
|
||||
只通过测试 CMD 准备临时数据库。
|
||||
|
||||
输入:
|
||||
- `subject`:账号标识
|
||||
- `session`:会话标识
|
||||
输出:`account`:新账号
|
||||
|
||||
## demo.account.setDeadline
|
||||
|
||||
仅供测试 CMD 调整截止时间,不依赖等待或修改 Token。
|
||||
|
||||
输入:
|
||||
- `id`:账号 ID
|
||||
- `expires`:新的截止时间
|
||||
输出:`deadline`:保存后的截止时间
|
||||
|
||||
## demo.account.revoke
|
||||
|
||||
禁用账号后,原有 Token 也必须被 verify 拒绝。
|
||||
|
||||
输入:`id`:账号 ID
|
||||
输出:`disabled`:是否已禁用
|
||||
|
||||
## demo.account.me
|
||||
|
||||
验证认证发生在调用业务之前。
|
||||
|
||||
输入:无
|
||||
输出:`profile`:当前可信身份
|
||||
|
||||
## demo.account.health
|
||||
|
||||
公开接口不因浏览器旧 Cookie 无法访问。
|
||||
|
||||
输入:无
|
||||
输出:`ready`:是否可用
|
||||
|
||||
## demo.account.Profile
|
||||
|
||||
身份数据来自隐藏上下文,业务参数不能覆盖它。
|
||||
|
||||
字段:
|
||||
- `id`:身份标识
|
||||
- `session`:会话标识
|
||||
- `site`:当前站点
|
||||
- `user_id`:用户 ID
|
||||
- `tenant_id`:租户 ID
|
||||
|
||||
## demo.account.login
|
||||
|
||||
测试凭据匹配后暂存 Cookie;使用同一全局会话验证函数。
|
||||
|
||||
输入:
|
||||
- `subject`:账号标识
|
||||
- `session`:测试会话凭据
|
||||
输出:无
|
||||
|
||||
## demo.account.logout
|
||||
|
||||
清除当前站点 Cookie,仍需同源检查。
|
||||
|
||||
输入:无
|
||||
输出:无
|
||||
|
||||
## demo.account.loginFail
|
||||
|
||||
在暂存 Cookie 后失败,验证响应不能发布尚未提交的凭据。
|
||||
|
||||
输入:
|
||||
- `subject`:账号标识
|
||||
- `session`:测试会话凭据
|
||||
输出:无
|
||||
@@ -0,0 +1,14 @@
|
||||
# 可信任务执行
|
||||
|
||||
worker 必须重新验证入队者。
|
||||
|
||||
### database
|
||||
|
||||
任务和账号共用连接。
|
||||
|
||||
## demo.account.job.perform
|
||||
|
||||
调用同领域业务。
|
||||
|
||||
输入:`input`:业务数据
|
||||
输出:无
|
||||
@@ -0,0 +1,26 @@
|
||||
# 自动 REST 数据
|
||||
|
||||
REST 只暴露公开字段,私有备注保持数据库内部值。
|
||||
|
||||
## demo.account.model.profile.Status
|
||||
|
||||
持久化选择项使用稳定名称,显示标签不参与存储。
|
||||
|
||||
分支:
|
||||
- `Active`:启用
|
||||
- `Disabled`:禁用
|
||||
|
||||
## demo.account.model.profile.Profile
|
||||
|
||||
公开名称和可选简介,私有备注不可由请求提交。创建键用请求方法和可信身份构成,仅创建时写入;唯一约束让原生测试验证 PUT 确实保留该值。
|
||||
|
||||
字段:
|
||||
- `private user_id: model.id`:可信记录所有者
|
||||
- `name`:名称
|
||||
- `bio`:简介
|
||||
- `rank`:默认排序
|
||||
- `tag`:允许显式清空的默认标签
|
||||
- `uid`:不可由客户端写入的生成标识
|
||||
- `status`:状态
|
||||
- `private note: Text?`:内部备注
|
||||
- `private creation_key: Text`:仅创建时写入的内部唯一键
|
||||
@@ -0,0 +1,9 @@
|
||||
# 租户身份类型
|
||||
|
||||
本例仅验证非租户身份,返回的 tenant_id 必须为空。
|
||||
|
||||
## demo.account.model.tenant.Tenant
|
||||
|
||||
保留租户 ID 的名义类型。
|
||||
|
||||
字段:`name`:名称
|
||||
@@ -0,0 +1,13 @@
|
||||
# 全局会话账号
|
||||
|
||||
用于原生认证验收;业务 verify 只读取 global Model。
|
||||
|
||||
## demo.account.model.Account
|
||||
|
||||
身份和会话状态由数据库决定。
|
||||
|
||||
字段:
|
||||
- `subject`:账号标识
|
||||
- `session`:会话标识
|
||||
- `active`:是否允许认证
|
||||
- `expires_at`:会话截止时间的 Unix 毫秒数
|
||||
@@ -0,0 +1,5 @@
|
||||
database default
|
||||
|
||||
job perform(input: app.Work) () retry(1) timeout(1000) {
|
||||
app.jobApply(input)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
global type Account {
|
||||
subject: Text unique
|
||||
session: Text
|
||||
active: Bool
|
||||
expires_at: Int
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
type Status {
|
||||
Active = "启用"
|
||||
Disabled = "禁用"
|
||||
}
|
||||
|
||||
type Profile {
|
||||
private owner user_id: model.id = dever.auth.userId()
|
||||
name: Text(1, 32) unique replace = text.lower(input) search = text.trim(input)
|
||||
bio: Text?
|
||||
rank: Int default 7
|
||||
tag: Text? default "automatic"
|
||||
uid: Uuid generated unique
|
||||
status: Status default Status.Active
|
||||
private note: Text? create = dever.api.header("x-source") replace = dever.api.header("x-source")
|
||||
private creation_key: Text unique create = dever.api.method() + ":" + dever.auth.id()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
global type Tenant { name: Text }
|
||||
@@ -0,0 +1,12 @@
|
||||
# document
|
||||
|
||||
本领域的职责与行为见主题说明;函数签名和调用关系从源码读取。
|
||||
|
||||
## 说明
|
||||
|
||||
- [原始 JSON 资源接口](doc/api-admin-content.md)
|
||||
- [原始 JSON 输出入口](doc/api-admin-encode.md)
|
||||
- [原始 JSON 输出对照](doc/app.md)
|
||||
- [REST 原始 JSON 字段](doc/model.md)
|
||||
|
||||
[调用流程](link.md)由 `dever inspect . --links` 生成。
|
||||
@@ -0,0 +1 @@
|
||||
rest model
|
||||
@@ -0,0 +1 @@
|
||||
public post encode = app.encode
|
||||
@@ -0,0 +1,3 @@
|
||||
encode(value: Json) (answer: Text) {
|
||||
answer = dever.json.toText(dever.json.encode(value))
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# 原始 JSON 资源接口
|
||||
|
||||
复用认证后的自动 REST 输入边界。
|
||||
|
||||
### resource
|
||||
|
||||
创建和替换都验证整个请求的 JSON 预算。
|
||||
@@ -0,0 +1,7 @@
|
||||
# 原始 JSON 输出入口
|
||||
|
||||
让输出对照经过应用函数的正式检查与生成。
|
||||
|
||||
### encode
|
||||
|
||||
返回输入 Json 的文本表示。
|
||||
@@ -0,0 +1,12 @@
|
||||
# 原始 JSON 输出对照
|
||||
|
||||
从真实 Dever 函数生成已有 Json 的编码路径。
|
||||
|
||||
## demo.document.encode
|
||||
|
||||
返回已经验证的 Json,不在基准中另写输出实现。
|
||||
|
||||
输入:
|
||||
- `value`:已经验证的内容
|
||||
输出:
|
||||
- `answer`:JSON 原文
|
||||
@@ -0,0 +1,11 @@
|
||||
# REST 原始 JSON 字段
|
||||
|
||||
验证必填与可空 JSON 字段的输入边界。
|
||||
|
||||
## demo.document.model.Document
|
||||
|
||||
JSON 内容保留原始数字和内部空白。
|
||||
|
||||
字段:
|
||||
- `value`:必填内容
|
||||
- `extra`:可空内容
|
||||
@@ -0,0 +1,4 @@
|
||||
global type Document {
|
||||
value: Json
|
||||
extra: Json?
|
||||
}
|
||||
Reference in new issue
Block a user