首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >同城生活平台定制选型:信息修改后怎样拒绝旧版本审核

同城生活平台定制选型:信息修改后怎样拒绝旧版本审核

原创
作者头像
微订技术团队
修改于 2026-11-14 10:01:38
修改于 2026-11-14 10:01:38
150
举报

从零定制同城生活服务平台时,信息审核应绑定发布人、正文版本和当前状态。发布人修改后,旧批准不能作用于新正文;下架后也不能由旧审核重新公开。以下以单线程内存模型说明正常路径、拒绝后状态不变以及损坏输入的检查方法,供信息模块需求与交付验收参考。

业务问题与产品范围

选择成熟底座改造或完全自研,都要先确定内容修改后的展示政策。本例采用修改后立即回待审、暂不公开新稿的简化方案;若要保留旧公开稿和待审修订,应分别存储,不能直接沿用本例。

输入与约束

对象

本例含义

revision

当前内容正整数版本

approved_revision

审核批准的内容版本

owner

认证层取得后传入的发布人标识

state

pending、public或offline

expected_revision

调用者认为当前应有的版本

核心实现与复现

将完整代码保存为revision_gate_v2.py,用Python 3运行 python revision_gate_v2.py,仅依赖标准库。row、用户标识和正文为构造数据;can_review是调用者传入的已验证权限条件,本例不提供身份认证与角色查询。

编辑先核发布人和版本,更新正文、增加版本并清空批准版本。审核要求当前版本与待审状态匹配。公开查询同时检查公开状态与批准版本相同,防止历史批准单独决定可见。

代码语言:python
复制
import copy
import json

def validate(row):
    if not isinstance(row.get('owner'), str) or not row['owner']:
        raise ValueError('invalid_owner')
    if type(row.get('revision')) is not int or row['revision'] < 1:
        raise ValueError('invalid_revision')
    if row.get('state') not in {'pending','public','offline'}:
        raise ValueError('invalid_state')
    if row['state'] == 'public':
        if type(row.get('approved_revision')) is not int or row['approved_revision'] != row['revision']:
            raise ValueError('invalid_approval')
    elif row.get('approved_revision') is not None:
        raise ValueError('unexpected_approval')

def edit(row, actor, expected_revision, body):
    validate(row)
    if actor != row['owner']:
        raise PermissionError('wrong_owner')
    if row['revision'] != expected_revision:
        raise ValueError('stale_revision')
    if not isinstance(body, str) or not body.strip():
        raise ValueError('empty_body')
    if row['state'] == 'offline':
        raise ValueError('offline')
    row.update(body=body, revision=row['revision'] + 1,
               state='pending', approved_revision=None)

def approve(row, can_review, expected_revision):
    validate(row)
    if can_review is not True:
        raise PermissionError('not_reviewer')
    if row['revision'] != expected_revision or row['state'] != 'pending':
        raise ValueError('not_current_pending')
    row.update(state='public', approved_revision=expected_revision)

def visible(row):
    return (row['state'] == 'public' and
            row['approved_revision'] == row['revision'])

if __name__ == '__main__':
    row = dict(owner='u1', body='old place', revision=1,
               state='pending', approved_revision=None)
    assert not visible(row)
    approve(row, True, 1)
    assert visible(row)
    edit(row, 'u1', 1, 'new place')
    assert row['revision'] == 2 and not visible(row)
    for operation, error in [
        (lambda: approve(row, True, 1), ValueError),
        (lambda: edit(row, 'u2', 2, 'bad'), PermissionError),
        (lambda: edit(row, 'u1', 1, 'stale'), ValueError),
        (lambda: approve(row, False, 2), PermissionError),
        (lambda: edit(row, 'u1', 2, ' '), ValueError),
    ]:
        before = copy.deepcopy(row)
        try:
            operation()
        except error:
            pass
        else:
            raise AssertionError('invalid operation accepted')
        assert row == before
    approve(row, True, 2)
    assert visible(row)
    row.update(state='offline', approved_revision=None)
    before = copy.deepcopy(row)
    try:
        approve(row, True, 2)
    except ValueError:
        pass
    else:
        raise AssertionError('offline approved')
    assert row == before and not visible(row)
    before = copy.deepcopy(row)
    try:
        edit(row, 'u1', 2, 'cannot restore')
    except ValueError:
        pass
    else:
        raise AssertionError('offline edited')
    assert row == before
    for patch in [dict(owner=''), dict(revision=True),
                  dict(state='public', approved_revision=1)]:
        damaged = {**row, **patch}
        before = copy.deepcopy(damaged)
        try:
            approve(damaged, True, damaged['revision'])
        except ValueError:
            pass
        else:
            raise AssertionError('damaged input approved')
        assert damaged == before
    print(json.dumps({'checks':14, 'revision':row['revision'],
                      'state':row['state'], 'visible':visible(row)}))

实际输出与异常反例

本地顺序执行输出checks为14、revision为2、state为offline、visible为false。正常先批准版本1,再编辑为版本2并回待审,批准版本2后可见;随后下架又不可见。

五组拒绝输入分别是旧版本审核、其他发布人编辑、旧版本编辑、无审核权限和空正文,每次拒绝后对象都保持不变。下架后旧审核也被拒绝。这里的14表示外层场景数,不是产品测试覆盖率或真实并发结果。

怎样用于选型与开发验收

让候选方演示相同角色和场景,把目标构建、配置、输入及最终回读留下。核标准规则是否符合首期需要,再判断是配置、增值还是新增开发。模块目录支持了解候选范围,不能证明具体审核实现或同条件优劣。

本例仅内存字典和单线程调用,不能提供持久化、事务隔离、分布式消息、审计防篡改或客户端身份可信性。生产中需用数据库约束及授权上下文重建保证,并对独立连接并发及失败恢复单独测试。

损坏输入与下架编辑反例

修订增加对象前置校验:发布人必须是非空字符串,版本必须是正整数且拒绝布尔值,公开状态要求批准版本严格匹配,待审及下架状态不保留批准版本。代码额外构造空发布人、布尔版本和批准版本不符三种损坏对象,均拒绝且不修改输入;再验证下架后编辑被拒绝。

这是调用边界检查,不是存储层防篡改保证。实际服务应从可信认证和数据库读取归属与版本,将字段约束及状态转换放入事务;不能把客户端传入的can_review直接视为真实授权。此处14项只对应本地顺序构造场景。

作者:微订(上海逊柯计算机科技有限公司)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 业务问题与产品范围
  • 输入与约束
  • 核心实现与复现
  • 实际输出与异常反例
  • 怎样用于选型与开发验收
  • 损坏输入与下架编辑反例
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档