思源笔记折腾记录 - 简单发布 - 做一点发布交互

本贴最后更新于 719 天前,其中的信息可能已经东海扬尘

一、前情提要

我们之前弄了一个简单的发布服务,它能够在打开思源的时候,让其他人能够通过局域网只读地访问你公开的笔记内容。

但是现在它有一个小问题。

那就是设置起来特别麻烦。

比如说,这个文档我想要发布出去的话, 需要首先打开菜单

image

然后点击属性,然后还要在这个界面里面添加属性:

image

然后才能在浏览器里面看到效果:

image

然后想要复制发布链接也很麻烦,需要自己去手动复制。

所以现在回过头来,我们来解决这个问题。

二、实现发布设置

属性设计

这里先来设计几个自定义属性,用它们来控制发布效果。

publish-access 属性:

用于控制文档和下层文档的访问权限

如果设置为 public,那么就可以直接通过端口访问,没有任何限制。

如果设置为 private,那么就无法通过发布端口访问。

如果设置为 protected,那么需要输入访问控制码才能够访问。

然后这个属性的值应该能够通过路径传播,比如说

如果一个顶级文档没有设置任何发布属性,那么它被视为 private,无法被访问。

如果一个文档自身没有设置发布属性,但是它所在的路径的顶层设置了发布属性,那么它视为以同样的属性发布。

如果一个文档自身设置了发布属性,那么它的所有下层文档除非该下层文档设置了发布属性,否则都视为以同样属性发布。

看起来好复杂的样子啊。。。。。

但是写 sql 实在太麻烦了,所以我们简单粗暴一点,直接获取所有有 publish-access 属性的文档,然后筛选出在目标文档路径上的文档,然后其中路径最长的那个就是了。

//这里获取了所有文档的publish-access属性
export async function 获取所有发布范围文档属性(){
    let sql = `
    select *
        from attributes
        where name = 'custom-publish-access'
        and block_id in (
            select id from blocks where type='d'
        )
        `
    return await noobApi.核心api.sql({stmt:sql})
}
export function 去扩展名(路径){
    return 路径.split('.')[0]
}
export function 是否下级路径(路径1,路径2){
    return 去扩展名(路径1).indexOf(去扩展名(路径2))>-1
}
export async function 根据路径获取文档权限(文档路径){
    let 发布范围属性数组 = await 获取所有发布范围文档属性()
    let 最近上级文档发布范围属性 = 发布范围属性数组.filter(
        文档数据=>{
            return 是否下级路径(文档路径,文档数据.path)
        }
    ).sort(
        (数据1,数据2)=>{
            return 数据2.path.length-数据1.path.length
        }
    )[0]
    console.log(最近上级文档发布范围属性)
    if(最近上级文档发布范围属性){
        return 最近上级文档发布范围属性.value
    }
    else{
        return null
    }
}

其中用到了两个 Array 类型上的工具函数,一个是 filter,用于对数据进行筛选;一个是 sort,用于对数组进行排序。

发布范围属性数组.filter(
        文档数据=>{
            return 是否下级路径(文档路径,文档数据.path)
        }
    )

这里表示的是从所有文档的发布范围属性中筛选出那些是待检查的文档路径的上级的。

sort(
        (数据1,数据2)=>{
            return 数据2.path.length-数据1.path.length
        }
    )[0]

这里是根据文档路径路径长度排序之后选择路径最长的那个。

通过这两步就可以获取最近的上级文档路径了。

现在我们可以把之前用来判定附件和文档是否可访问的函数改一改:

发布应用.use('/:blockID',async(req,res,next)=>{
    if(await 判定文档权限(req.params.blockID)){
        next()
    }else{
        res.status('403')
        res.setHeader('Content-Type',"text/html;charset=utf-8" );
        res.end('不可访问此文档')

    }
},默认渲染管线)
发布应用.use('/assets',async (req,res,next)=>{
    if(await 判定附件权限(req)){
        next()
    }
    else {
        res.status('403')
        res.setHeader('Content-Type',"text/html;charset=utf-8" );
        res.end('不可访问此附件')
    }
},思源代理)
async function 判定文档权限(块id){
    let 文档路径 = (await 获取文档内容(块id)).path
    let 文档权限 = await 根据路径获取文档权限(文档路径)
    console.log(文档权限)
    return (await 根据路径获取文档权限(文档路径))=='public'
}
export async function 根据名称获取附件权限(附件名称){
    let 附件引用属性数组 = await 根据名称获取附件属性(附件名称)
    let 附件权限
    for await (let 附件属性 of 附件引用属性数组){
	//只要有一篇文档引用了附件并且公开,那就认为这个附件是可以公开的
        if(await 根据路径获取文档权限(附件属性.docpath)=='public'){
            附件权限 = 'public'
        }
    }  
    return 附件权限
}

这样之后,文档和附件就可以根据所在路径确定是否公开了。

实现发布设置菜单

这个比较简单,就是几个设置属性的菜单项而已,注册一下就行了

noob-service-syPublishServer\ui\index.js

import noobApi from "../../noobApi/index.js";
noobApi.自定义菜单.编辑器菜单.注册自定义菜单项(
    {
        id: '文档发布设置',
        文字: '文档发布设置',
        图标: '#iconInbox',
        子菜单配置: [
            {
                id: '设置为公开发布',
                文字: '设置当前文档为公开发布',
                事件配置: {
                    click: () => 设置当前文档发布属性('public')
                }
            },
            {
                id: '设置当前文档为私密',
                文字: '设置当前文档为私密',
                事件配置: {
                    click: () => 设置当前文档发布属性('private')
                }
            },
            {
                id: '继承上级文档',
                文字: '继承上级文档设置',
                事件配置: {
                    click: () => 设置当前文档发布属性('')
                }
            }
        ]
    }
)
noobApi.自定义菜单.编辑器菜单.注册自定义菜单项(
    {
        id:"复制发布链接",
        文字:'复制发布链接',
        图标: '#iconInbox',
        事件配置:{
            click:写入发布链接到剪贴板
        }
    }
)
async function 写入发布链接到剪贴板(e){
    let 块id = noobApi.自定义菜单.当前菜单.菜单状态.当前块id
    let 文档id = (await 获取所在文档数据(块id)).id
    let 发布链接 =window.location.protocol+'//'+ window.location.hostname+'/'+文档id
    navigator.clipboard.writeText(发布链接)
    if(window.siyuan.ctrlIsPressed){
    window.open(发布链接)
    }
    siyuan.menus.menu.remove()

}
async function 设置当前文档发布属性(属性值) {
    let 块id = noobApi.自定义菜单.当前菜单.菜单状态.当前块id
    let 文档id = (await 获取所在文档数据(块id)).id
    await noobApi.核心api.setBlockAttrs(
        {
            id: 文档id,
            attrs: {
                'custom-publish-access': 属性值
            }
        }
    )
    siyuan.menus.menu.remove()
}
async function 获取所在文档数据(块id) {
    let stmt = `select * from blocks where id in (select root_id from blocks  where id = "${块id}" )`
    let 文档数据 = (await noobApi.核心api.sql({ stmt: stmt }))[0]
    return 文档数据
}

navigator.clipboard.writeText 可以向剪贴板写入数据。

然后 window.siyuan.ctrlIsPressed 储存了 ctrl 键有没有被按下去,所以就不用自己判断功能键了。

siyuan.menus.menu.remove() 可以把菜单隐藏掉,放心不会真的移除的.

其实也可以在文档树上也加上这几项,不过这里就不发了, 反正代码基本一样.

冷不丁看到这篇东西的同学可能不知道这个代码片段仓库在哪里,再放一下:

leolee9086/snippets (github.com)

访问码保护的实现下次再说,下次再说.

现在的效果就像这样:

发布菜单交互

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    22338 引用 • 89384 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...