Skip to content

biohub.forum

hsfzxjy edited this page Sep 24, 2017 · 40 revisions

Data Types and APIs

Data Types

  • * 必填
  • ! 只读
  • ? 部分对象
  • &只写

(其余type参见RESTful API wiki)

type Experience

{
    api_url!: URL,
    content: Article,
    author!: //如果为null则表示作者来自iGEM官网,非空则表示是本站作者
    {
        id: Number,
        username: String,
        avatar_url: URL
    }
    brick!: ShortBrick,
    brick_id*&: Number,
    title: String, //可为空
    author_name!: String, //当author为null时,这个可能有值(iGEM官网上的author信息)
	pub_time!: DateTime,
    votes!: Number,
    voted!: Boolean, // 标识当前已登录用户是否投了此 Experience
    posts_num!: Number
}

type Article

可作为part页面的document,也可作为用户的一篇experience。

{
    file_ids&: [Number], //当需要把上传过的文件关联到这个markdown文档时,需要提供已经上传过的文件的id
    text: String, //markdown文本
    digest: String // 摘要,无换行,无格式,不超过 600 chars
}

type Post

experience下的评论。

{
    id!: Number,
    author!:
    {
        id: Number,
        username: String
    }
    experience_id*&: Number, //只写,不会发送至前端
    experience!: Experience,
    content*: String, //注意这里没有提供 markdown 支持
    update_time!: DateTime,
    pub_time!: DateTime,
}

type Activity

用户动态。

{
    params!:{
        user!: String,
        expLink!?: URL,
        partName!: String,
        intro!?: String,
        score!?: String,
    },
    type!: Enum('Experience', 'Comment', 'Star', 'Rating', 'Watch'),
    acttime!: DateTime
}

API


Post 相关

API<post> /api/forum/posts/

posts(即为之前前端说的comments)

Filters

  • author 值为用户名,将queryset限定为author指定的用户所发出的

Operations

  • list
  • create 需要登录
  • retrieve
  • update 只能对用户自己的post操作
  • patch 只能对用户自己的post操作
  • delete 只能对用户自己的post操作

以下为测试中的list方法返回的response内容供参考:

{
    "count": 3,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 43,
            "experience": "http://testserver/api/forum/experiences/16/",
            "content": "15210",
            "update_time": "2017-08-09T05:13:30.126143Z",
            "pub_time": "2017-08-09T05:13:30.126633Z",
            "author": {
                "id": 31,
                "username": "abc"
            }
        },
        {
            "id": 44,
            "experience": "http://testserver/api/forum/experiences/16/",
            "content": "777777",
            "update_time": "2017-08-09T05:13:30.136942Z",
            "pub_time": "2017-08-09T05:13:30.137420Z",
            "author": {
                "id": 32,
                "username": "fff"
            }
        },
        {
            "id": 45,
            "experience": "http://testserver/api/forum/experiences/16/",
            "content": "test_test_test",
            "update_time": "2017-08-09T05:13:30.737706Z",
            "pub_time": "2017-08-09T05:13:30.737836Z",
            "author": {
                "id": 31,
                "username": "abc"
            }
        }
    ]
}

GET /api/forum/experiences/<experience_id>/posts/

获取id为experience_id的某篇experience下的所有posts。

Filters

  • author 值为用户名,可以只查询某author发布的posts。

Output

Page<Post>


Experience 相关

API<Experience> /api/forum/experiences/

API<Experience> /api/forum/bricks/<brick_name>/experiences/

Filters

  • author 值为用户名,可以只查询某author发布的posts。

Operations

  • list

    Filters

    • short

      true时,只返回每条experience的id, title, author_name, author, api_url, brick(为对应的URL)。

      false时,返回experience的全部内容。

  • create 需要登录

  • retrieve

  • update 只能对用户自己的experience操作

  • patch 只能对用户自己的experience操作

  • delete 只能对用户自己的experience操作

以下为测试中retrieve方法返回的response内容供参考:

{
    "id": 410,
    "api_url": "http://testserver/api/forum/experiences/410/",
    "content": {
        "text": "hahaha"
    },
    "author": {
        "id": 307,
        "username": "abc"
    },
    "brick": "http://testserver/api/forum/bricks/429/",
    "post_set": [],
    "up_vote_users": [
        {
            "id": 33,
            "username": "fff"
        },
        {
            "id": 34,
            "username": "bbb"
        }
    ],
    "title": "f**k",
    "author_name": "abc",
    "pub_time": "2017-08-17",
    "up_vote_num": 0
}

POST /api/forum/experiences/<experience_id>/vote/

POST /api/forum/bricks/<brick_name>/experiences/<experience_id>/vote/

对id为experience_id的experience点赞。需要登录。

Output

  • 200.成功
  • 400.失败(如给自己点赞、当前用户已投票)

POST /api/forum/experiences/<experience_id>/unvote/

POST /api/forum/bricks/<brick_name>/experiences/<experience_id>/unvote/

对id为experience_id的experience取消点赞。需要登录。

Output

  • 200.成功
  • 400.失败(自己之前没有投过)

POST /api/forum/experiences/<experience_id>/voted_users/

POST /api/forum/bricks/<brick_name>/experiences/<experience_id>/voted_users/

获得相关用户的列表,支持分页。

Output

  • 200 -> Page<User>

Article 相关

API <Article> /api/articles/

Filters

Operations

retrieve

Activity 相关

GET /api/forum/activities/timeline/

返回已关注用户与已关注 Brick 相关的 Activity。

Output

  • 200 -> Page<Activity>

API <Activity> /api/forum/activities/

Operations

  • list

    Filters

    • user 筛选获取用户名为user的所有activity。
    • type 筛选 type 为指定类型的 activity,多个 type 用逗号分割,大小写敏感。

    示例 GET /api/forum/activities/?user=user1&type=Rating,Watch

Output

Page<Activity>

以下为测试中list方法返回的包含五种动态类型的列表:

{
    "count": 5,
    "next": null,
    "previous": null,
    "results": [
        {
            "params": {
                "user": "abc",
                "expLink": "/api/forum/experiences/121/",
                "partName": "B0032",
                "intro": ""
            },
            "type": "Experience",
            "acttime": "2017-08-14T04:45:34.727102Z"
        },
        {
            "params": {
                "user": "abc",
                "expLink": "/api/forum/bricks/56/",
                "score": "2.9",
                "partName": "B0032"
            },
            "type": "Rating",
            "acttime": "2017-08-14T04:45:34.984775Z"
        },
        {
            "params": {
                "user": "abc",
                "expLink": "/api/forum/experiences/121/",
                "partName": "B0032",
                "intro": ""
            },
            "type": "Comment",
            "acttime": "2017-08-14T04:45:35.139352Z"
        },
        {
            "params": {
                "user": "another",
                "expLink": "/api/forum/experiences/121/",
                "partName": "B0032",
                "intro": ""
            },
            "type": "Star",
            "acttime": "2017-08-14T04:45:35.657219Z"
        },
        {
            "params": {
                "user": "another",
                "partName": "B0032"
            },
            "type": "Watch",
            "acttime": "2017-08-14T04:45:35.838033Z"
        }
    ]
}

User 友元 API

GET /api/users/(<id>|me|n:<username>)/voted_experiences/


更改

  • 去掉工作室

对Part设计的更改

  • 去掉创建者owner字段,因为Part不再由用户创建,而是本身存在于论坛。

  • 扩充Part表的字段。包括名称,设计者,组名,描述文字,Ruler信息,Assemly Compability,Category,Parameters以及评分。

  • 初始数据库中不含有任何igem官网的Part的描述条目。

  • 前端设计“发起讨论”的按钮,在数据库没有该Part条目时显现。用户点击该按钮时,将该Part的描述以及实验经验(Experiences)从官网爬取至数据库。Experiences由后端从HTML转换为markdown格式。

  • 每篇Part的各种描述信息均无法更改。但每个用户都可以针对每个Part上传自己的Experience,用户可以修改自己上传的Experience,无需版本控制。外来的和本站用户的Experiences一起存于数据库。

  • 多个用户对一个Part的多篇Experience以标题形式附在Part之后。(类似豆瓣影评)

  • 每篇Experience有5星评分。

  • 每篇Experience附有Issue板块,设计类似论坛。

    只有一级评论(Comment对象),评论可以被点赞。

细节更改

Brick

  • 去除owner
  • 若该Brick为Device:其所有subpart合为一字符串("J45993,B0032,J45014,B0010,B0012")。不用再区分内部subpart和外部subpart。因为所有的subpart是否存在于本站,均可以由“发起讨论”这套逻辑来管理。

旧设计

模块间联系

relation_graph

Lab Record, Documents, Commit Object实际上均为class Article,见forum/bio_models.py。

论坛设计

  • 积块(Biobricks)

    • Part/Device

      • 描述

        Public:

        • Bool ispart 标记是Part还是Device
        • text[title] name
        • Foreign Key owner
        • ManytoMany Field followers
        • text short description
        • text/image/file Documents(可被请求更改) (related_name='brick_from_doc')
        • text/image/file: 实验记录(可被请求更改) (related_name='brick_from_record')

        Private to Part:

        • text Part type
        • text Part's sequence A
        • text Part's sequence B
        • Foreign Key(to itself) internal_part_to (related_name='internal_parts')

        Private to Device:

        • text external_Parts(按约定好的格式,如:"BBa_K808013,BBa_K648028")

        external_Parts: 未在本Web系统中登记的Part,可考虑在前端将其parse并计算出其在igem官网的URL。

        internal_part_to: 该part所属于的device,如果有的话。

        internal_part: 已在本Web系统中登记的Part,将直接由后端给出其信息页面的URL。

      • 附属的讨论区

  • 工作室

    • Studio

      • text[title] name 工作室名称,必须不与已有的studio name重复

      • ManytoMany Field users 指向User的ManytoMany Field, related_name='studios_from_user'

      • Foreign Key administrator 管理员,指向User的外键,比普通user多了将接受成员、清理成员的权限(工作室创建者将成为管理员),related_name='studios_from_admin'

        注意:administrator与users应该是不兼容的,加了一个用户到administrator里面就不要再加到users里面了

        注意:创建studio的同时必须指定administrator,否则studio会被认为是没有user的studio而被清理。

      • text[content] description 工作室描述

      • Thread

        • text[title] title Thread的标题
        • text[content] content 内容
        • Foreign Key author 作者,指向User的外键
        • DateTime update_time 更新时间,指作者更新这个主题帖子的时间
        • DateTime pub_time 发布时间
        • Bool is_visible 是否能够被除了作者之外的人看到
        • Bool is_sticky 是否置顶
        • Foreign Key brick 指向Brick的外键
        • Foreign Key studio 所属的工作室,指向Studio的外键

        注意:brick、studio二者必须有一个而且只能有一个有值。因为一个thread可以是隶属工作室在工作室内的,也可以是在brick下的类似issues的讨论。

      • Post

        • Foreign Key thread 指向thread的外键
        • Text content Post内容
        • ForeignKey author 作者,指向User的外键
        • DateTime update_time 更新时间
        • DateTime pub_time 发布时间
        • Bool is_visible 是否能够被除了作者之外的人看到
        • Integer up_vote_num 点赞数
        • Integer down_vote_num 点踩数
        • Bool is_comment 是否是一个评论 (这个field不用管,会由__init__自动处理)
      • Comment

        • Foreign Key thread 指向thread的外键
        • Text content Post内容
        • ForeignKey author 作者,指向User的外键
        • DateTime update_time 更新时间
        • DateTime pub_time 发布时间
        • Bool is_visible 是否能够被除了作者之外的人看到
        • Integer up_vote_num 点赞数
        • Integer down_vote_num 点踩数
        • Bool is_comment 是否是一个评论 (这个field不用管,会由__init__自动处理)
        • Foreign Key reply_to 回复对象,指向Post(comment在Model层次其实也是一个Post)的外键。设置了related_name="comments"

Methods

  • Studio

    • Thread

      • .hide()

        隐藏这个thread以及这个thread下的所有post、comment,使得他们不再对公众开放

      • .show()

        显示这个thread以及这个thread下的所有post、comment,对公众开放

      注意:以下get_post_set_...三个方法是t.post_set.all/filter/get对应的替代方法。因为Comment继承了Post,在Models层面Comment也是Post,如果直接用t.post_set.all/filter/get,会同时获得comment而不只是thread下的post。

      • .get_post_set_all()

        获取这个thread的所有post (不会包含comment)

      • .get_post_set_filter(*args, **kwargs)

        获取这个thread的所有post (不会包含comment),并且能提供参数进行筛选

      • .get_post_set_by(*args, **kwargs)

        获取这个thread的某一个post,提供参数进行选择

    • Post

      • .hide()

        隐藏这个post以及这个post下的所有comment,使得他们不再对公众开放

      • .show()

        显示这个post以及这个post下的所有comment,对公众开放

    • Comment

      • .hide()

        隐藏这个comment,使得他们不再对公众开放

      • .show()

        显示这个comment,对公众开放

Signals

  • hide_attached_posts() signal: pre_delete, sender=Thread

    当thread被删除时触发,隐藏这个thread下对应的所有post和comment。

  • hide_attached_comments() signal: pre_delete, sender=Post

    当post被删除时触发,隐藏这个post下对应的所有comment。

  • hide_attached_threads() signal: pre_delete, sender=Studio; pre_delete, sender=Part

    当part或者studio被删除时触发,隐藏这个part或者studio下对应的所有thread、post和comment。

  • delete_studio_with_no_user__m2m() signal: m2m_changed, sender=Studio.users.through

    当studio与user之间的manytomany关系发生改变时触发,如果是有remove动作,则判断studio的users、administrator是否为空,如果为空,删除掉studio。

    注意:因为signal中无法获取采用clear()方法时移除的studio与user关系,故为了能正常清理没有user和administrator的studio,请不要使用clear()方法。

  • delete_studio_with_no_user__del() signal: pre_delete, sender=User

    当user被删除时触发,判断studio的users、administrator是否为空,如果为空,删除掉studio。

  • delete_studio_with_no_user__save() signal: post_save, sender=Studio

    当studio有save的时候触发,判断studio的users、administrator是否为空,如果为空,删除掉studio。

    注意:admin采用remove方式退出studio的时候,如admin.studios_from_admin.remove(studio),须加上bulk=False参数,确保post_save信号被触发。即改为:admin.studios_from_admin.remove(studio, bulk=False)。如果不是admin,而是普通的user,不用加这个参数。