写点什么

基于 Serverless 架构的社区文章管理小工具

用户头像
刘宇
关注
发布于: 2021 年 08 月 19 日

前言

我是一个非常喜欢写一些东西的人,写完了一些文章什么的,我会考虑把他们发布到一些平台,例如微信公众号,例如知乎,例如我的博客等。


但是实际的情况却有一些尴尬:


  1. 不同平台所能接受的格式内容是不同的,例如我的博客支持 Markdown,但是知乎,微信公众号,貌似只支持富文本的复制粘贴,所以这就涉及到我要在不同平台之间切换不同的格式;

  2. 有的时候,图片真的是一个坑爹的事情,我在 Github 上面截图粘贴了很多图片,复制到公众号,知乎等平台之后,发现所有的图片还需要重新截图粘贴(可能是网络问题,也可能是跨域等其他问题,反正图片是拿不回来)


所以我就一直在想,是否可以有一个非常简单的项目,他只需要帮我做几个事情就可以:


  1. 我可以在这个上面写文章,写博客,并且可以用 Markdown 的语法来写

  2. 写完了之后可以生成富文本的样子,便于我可以快速复制和粘贴

  3. 我可以直接截图粘贴图片,这些图片可以在不同平台直接使用

项目开发

我通过 Python 的 Django 框架,快速搭建起来一个架子。并且根据资料发现,我可以使用django-mdeditor来做 Markdown 的编写、预览;


所以,我将django-mdeditor安装好之后,我编写models.py


from django.db import modelsfrom mdeditor.fields import MDTextField
# Create your models here.
class ArticleModel(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=255, verbose_name="标题") create_time = models.DateTimeField(null=True, blank=True, auto_created=True, auto_now_add=True, verbose_name='创建时间') description = models.TextField(null=True, blank=True, verbose_name="描述") content = MDTextField()
def __unicode__(self): return self.title
def __str__(self): return self.title
class Meta: verbose_name = '文章' verbose_name_plural = '文章'
复制代码


此时,我的文章正文(content字段),就可以使用django-mdeditor的内容了。


完成之后,我在admin.py中配置一下字段等:


from django.contrib import adminfrom article.models import *# Register your models here.
admin.site.site_header = '文章中心'admin.site.site_title = '文章中心'

class ArticleModelAdmin(admin.ModelAdmin): ordering = ('-id',) list_display = ('id', 'title', 'create_time',) list_display_links = ('id', 'title',)

admin.site.register(ArticleModel, ArticleModelAdmin)
复制代码


完成之后,可能还需要配置一下数据库信息,然后同步数据库,常见超级管理员等。完成之后,我们可以打开/admin



登陆之后可以看到:



此时,我们可以新建一个文章:



可以看到整个效果还是非常棒的。

魔改编辑器

但是,这里有一个问题,那就是图片不能粘贴。所以,我们要对刚刚安装的django-mdeditor进行魔改,此处为了便于修改之后在其他平台生效,我们将这个模块安装到当前项目:pip3 install -t . django-mdeditor


此时对 html 文件进行修改:



在第 91 行添加:initPasteDragImg(this); //必须


然后,在这个script标签中,增加:


function initPasteDragImg(Editor){    var doc = document.getElementById(Editor.id)    doc.addEventListener('paste', function (event) {        var items = (event.clipboardData || window.clipboardData).items;        var file = null;        if (items && items.length) {            // 搜索剪切板items            for (var i = 0; i < items.length; i++) {                if (items[i].type.indexOf('image') !== -1) {                    file = items[i].getAsFile();                    break;                }            }        } else {            console.log("当前浏览器不支持");            return;        }        if (!file) {            console.log("粘贴内容非图片");            return;        }        uploadImg(file,Editor);    });    var dashboard = document.getElementById(Editor.id)    dashboard.addEventListener("dragover", function (e) {        e.preventDefault()        e.stopPropagation()    })    dashboard.addEventListener("dragenter", function (e) {        e.preventDefault()        e.stopPropagation()    })    dashboard.addEventListener("drop", function (e) {        e.preventDefault()        e.stopPropagation()     var files = this.files || e.dataTransfer.files;     uploadImg(files[0],Editor);     })}function uploadImg(file,Editor){    var formData = new FormData();    var fileName=new Date().getTime()+"."+file.name.split(".").pop();    formData.append('editormd-image-file', file, fileName);    formData.append('content', '');    $.ajax({        url: Editor.settings.imageUploadURL,        type: 'post',        data: formData,        processData: false,        contentType: false,        dataType: 'json',        success: function (msg) {            var success=msg['success'];            if(success==1){                var url=msg["url"];                if(/\.(png|jpg|jpeg|gif|bmp|ico)$/.test(url)){                    Editor.insertValue("![图片alt]("+msg["url"]+" ''图片title'')");                }else{                    Editor.insertValue("[下载附件]("+msg["url"]+")");                }            }else{                console.log(msg);                alert("上传失败");            }        }    });}
复制代码


完成之后,还有一个问题:我们粘贴之后是会上传到当前项目下,但是在 Serverless 架构下,进行图片持久化是不能放在当前项目的,毕竟实例会被释放掉,所以这里还需要对存储位置进行改变:



import oss2bucketName = os.environ.get('oss_BUCKET', '')endpoint = os.environ.get('oss_ENDPOINT', '')auth = oss2.Auth(os.environ.get('aliyun_KeyId', ''), os.environ.get('aliyun_KeySecret', ''))bucket = oss2.Bucket(auth, endpoint, bucketName)
复制代码


完成之后,还需要对文件存储部分进行额外处理:



  1. 注释掉红色的:不需要检查本地路径和写入到本地

  2. 增加蓝色的部分:将图片上传到对象存储bucket.put_object(file_full_name, upload_image.chunks())

  3. 修改黄色的部分:将结果返回给前端: 'url': 'https://%s.%s/%s'%(bucketName, endpoint, file_full_name)


完成之后,我们再重新运行一下项目,我们可以看到,是可以直接实现图片粘贴的,粘贴后的效果:


部署到线上

为了和函数计算做结合,只需要增加两个文件就可以:


文件 1,函数入口,新建index.py


from articleCenter.wsgi import application
复制代码


文件 2,资源描述文件,新建s.yaml


edition: 1.0.0          #  命令行YAML规范版本,遵循语义化版本(Semantic Versioning)规范name: serverless-article       #  项目名称access: "default"  #  秘钥别名
services: article: # 服务名称 component: devsapp/fc # 组件名称 props: # 组件的属性值 region: cn-hangzhou service: name: serverless-article internetAccess: true function: name: server runtime: python3 codeUri: ./ handler: index.application memorySize: 128 timeout: 60 environmentVariables: aliyun_KeyId: '' aliyun_KeySecret: '' db_HOST: '' db_NAME: '' db_PASSWORD: '' db_PORT: '' db_USER: '' oss_BUCKET: '' oss_ENDPOINT: '' triggers: - name: httpTrigger type: http config: authType: anonymous methods: - GET - POST - PUT - DELETE customDomains: - domainName: auto protocol: HTTP routeConfigs: - path: /* methods: - GET
复制代码

快速使用

我将该项目放在了 Github:https://github.com/anycodes-cn/serverless-article-center



大家只需要 Clone 这个项目,然后编辑s.yaml,添加数据库信息,对象存储信息。


然后进行项目处理和部署处理。

项目处理

  1. 在项目中执行数据库同步makemigrationsmigrate

  2. 创建超级用户,同样是manage.py的指令:createsuperuser

  3. 静态文件处理:collectstatic

部署处理

  1. 执行s build --use-docker进行构建

  2. 执行s deploy进行项目部署

总结

一个非常简单的小工具,希望可以帮助和帮助更多人快速编写一些文章,进行保存和多平台的发布

todo

  1. 自动发布到不同的平台

发布于: 2021 年 08 月 19 日阅读数: 4
用户头像

刘宇

关注

阿里云Serverless云布道师 2020.01.04 加入

阿里云Serverless产品经理,国防科大在读博士,《Serverless架构》、《Serverless实践》、《人人都能学会的Serverless架构》等书籍作者,Serverless Devs发起人,Anycodes在线编程负责人。

评论

发布
暂无评论
基于Serverless架构的社区文章管理小工具