我爱编程

(十一)日志创建页

2018-05-23  本文已影响13人  顽强的猫尾草

首先安装markdown2库来支持markdown语言:

$ sudo pip install markdown2
$ sudo pip install pygments

注意要把安装后的markdown2.py和pygments文件夹放到www文件夹下,因为我们想支持代码块以及表格等额外的markdown语言,而默认这些特性是关闭的,因此需要稍微修改一下markdown2.py

...
def markdown_path(path, encoding="utf-8", html4tags=False, tab_width=DEFAULT_TAB_WIDTH,
                  safe_mode=None, extras=["fenced-code-blocks", "tables"], 
                  link_patterns=None, use_file_vars=False):
...

需要什么就在这里找到然后填在extras后面。
还需要下载至少一种pygments-css来支持代码颜色:

$ git clone https://github.com/richleland/pygments-css.git
$ cd pygments-css

把makefile文件里的.highlight替换成.codehilite,接着:

$ make cssfiles

当然还要在base.html里面添加这个css文件,不然也是显示不出来的:

<link rel="stylesheet" href="/static/css/pygments-css/murphy.css">

随便选了一个,好像不太好看,有空再换一换。另外需要在三个反引号后指出用的是什么语言,不然还是不能显示出颜色...(这是后话):

然后修改handlers.py,添加如下内容:

import markdown2
def text2html(text):
    # 先将text去除空行,再写成html格式
    lines = map(lambda s: '<p>%s</p>' % s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;'), filter(lambda s: s.strip() != '', text.split('\n')))
    return ''.join(lines)

def check_admin(request):
    if request.__user__ is None or not request.__user__.admin:
        raise APIPermissionError()

def get_page_index(page_str):
    p = 1
    try:
        p = int(page_str)
    except ValueError as e:
        pass
    if p < 1:
        p = 1
    return p

@get('/blog/{id}')
async def get_blog(id):
    blog = await Blog.find(id)    # 根据id查询到blog对象
    comments = await Comment.findAll('blog_id=?', [id], orderBy='created_at desc')
    for c in comments:
        c.html_content = text2html(c.content)
    blog.html_content = markdown2.markdown(blog.content)
    return {
        '__template__': 'blog.html',
        'blog': blog,
        'comments': comments
    }

@get('/manage/blogs/create')
def manage_create_blogs():
    return {
        '__template__': 'manage_blog_edit.html',
        'id': '',
        'action': '/api/blogs'
    }

@get('/api/blogs/{id}')
async def api_get_blog(*, id):
    blog = await Blog.find(id)
    # 返回到manage_blog_edit.html中, 当需要编辑旧博客时
    return blog

@post('/api/blogs')
async def api_create_blog(request, *, name, summary, content):
    check_admin(request)    # 只有管理员才可以发布博客
    if not name or not name.strip():
        raise APIValueError('name', 'name cannot be empty.')
    if not summary or not summary.strip():
        raise APIValueError('summary', 'summary cannot be empty.')
    if not content or not content.strip():
        raise APIValueError('content', 'content cannot be empty.')
    blog = Blog(
        user_id=request.__user__.id,    # app.py中把cookie2user获取到的用户赋给了request.__user__
        user_name=request.__user__.name, 
        user_image=request.__user__.image, 
        name=name.strip(), 
        summary=summary.strip(), 
        content=content.strip()
    )
    await blog.save()
    return blog

然后使用MVVM模式写一个创建博客的页面templates/manage_blog_edit.html,这种模式的好处是前后端分离,逻辑清晰:

{% extends '__base__.html' %}

{% block title %}编辑日志{% endblock %}

{% block beforehead %}
<script>
    var
        ID = '{{ id }}',    // 写博客时id还未被创建
        action = '{{ action }}';
    function initVM(blog) {
        var vm = new Vue({
            el: '#vm',    // 绑定的View, 这里是#vm, 即id为vm的DOM, 对应的是一个<div>标签
            data: blog,    // JS对象表示的Model, 在下面初始化为{name:'',summary:'',content:''}
            methods: {    // View可以触发的JS函数, submit就是提交表单时触发的函数
                submit: function (event) {
                    event.preventDefault();
                    var $form = $('#vm').find('form');
                    $form.postJSON(action, this.$data, function (err, r) {
                        if (err) {
                            $form.showFormError(err);
                        }
                        else {
                            // 提交后跳转到的地址
                            return location.assign('/blog/' + r.id);    # 跳转到日志内容页
                        }
                    });
                }
            }
        });
        $('#vm').show();
    }
    $(function () {
        if (ID) {    //旧博客, 调出来继续编辑
            getJSON('/api/blogs/' + ID, function (err, blog) {
                if (err) {
                    return fatal(err);    // fatal函数?
                }
                $('#loading').hide();
                initVM(blog);
            });
        }
        else {    // 新博客
            $('#loading').hide();
            initVM({
                name: '',
                summary: '',
                content: ''
            });
        }
    });
</script>
{% endblock %}

{% block content %}
    <div class="uk-width-1-1 uk-margin-bottom">
        <div class="uk-panel uk-panel-box">
            <ul class="uk-breadcrumb">
                <li><a href="/manage/comments">评论</a></li>
                <li><a href="/manage/blogs">日志</a></li>
                <li><a href="/manage/users">用户</a></li>
            </ul>
        </div>
    </div>
    <div id="error" class="uk-width-1-1"></div>
    <div id="loading" class="uk-width-1-1 uk-text-center">
        <span><i class="uk-icon-spinner uk-icon-medium uk-icon-spin"></i> 正在加载...</span>
    </div>
    <div id="vm" class="uk-width-2-3">
        <!-- 把提交表单的事件关联到submit方法 -->
        <form v-on="submit: submit" class="uk-form uk-form-stacked">
            <div class="uk-alert uk-alert-danger uk-hidden"></div>
            <div class="uk-form-row">
                <label class="uk-form-label">标题:</label>
                <div class="uk-form-controls">
                    <input v-model="name" name="name" type="text" placeholder="标题" class="uk-width-1-1">
                </div>
            </div>
            <div class="uk-form-row">
                <label class="uk-form-label">摘要:</label>
                <div class="uk-form-controls">
                    <textarea v-model="summary" rows="4" name="summary" type="text" placeholder="摘要" class="uk-width-1-1" style="resize:none;"></textarea>
                </div>
            </div>
            <div class="uk-form-row">
                <label class="uk-form-label">内容:</label>
                <div class="uk-form-controls">
                    <textarea v-model="content" rows="16" name="content" type="text" placeholder="内容" class="uk-width-1-1" style="resize:none;"></textarea>
                </div>
            </div>
            <div class="uk-form-row">
                <button type="submit" class="uk-button uk-button-primary"><i class="uk-icon-save"></i> 保存</button>
                <a href="/manage/blogs" class="uk-button"><i class="uk-icon-times"></i> 取消</a>
            </div>
        </form>
    </div>
{% endblock %}

注意我们默认注册的时候都不是admin账户,需要在数据库中修改权限:



之所以admin两边要加反引号是因为admin是数据库的关键字,要避免冲突,不然会报“Error 1064”错误。
然后登陆这个账户才是管理员权限,可以写博客。

上一篇下一篇

猜你喜欢

热点阅读