# PingCAP University API 文档

- [API说明](#API-说明)
- [名词解释](#名词解释)
- [获取对所有人的推荐课程](#获取对所有人的推荐课程)
- [获取特定方向的推荐课程](#获取特定方向的推荐课程)
- [获取 Category 列表](#获取-Category-列表)
- [获取 Course 列表](#获取-Course-列表)
- [获取 Course 详情](#获取-Course-详情)
- [获取 Course 目录](#获取-Course-目录)
- [获取 Course 的 Chapter 列表](#获取-Course-的-Chapter-列表)
- [获取 Chapter 的 Lesson 列表](#获取-Chapter-的-Lesson-列表)
- [获取 Lesson 具体内容](#获取-Lesson-具体内容)
- [Lesson quiz 提交答案](#Lesson-quiz-提交答案)
- [Lesson quiz 获取提示](#Lesson-quiz-获取提示)
- [获取在线考试 Entry](#获取在线考试-Entry)
- [获取在线考试试题](#获取在线考试试题)
- [在线考试交卷](#在线考试交卷)
- [获取用户信息](#获取用户信息)
- [更新用户信息](#更新用户信息)
- [获取所有考试列表](#获取所有考试列表)
- [获取考试详细信息](#获取考试详细信息)
- [获取我报名的考试列表](#获取我报名的考试列表)
- [考试报名权限检查](#考试报名权限检查)
- [考试报名](#考试报名)
- [Video 事件打点上报](#Video-事件打点上报)
- [获取学习进度](#获取学习进度)
- [获取 Course 学习进度](#获取-Course-学习进度)

### API 说明

- 所有的 API 调用都有频率限制，未认证用户 60 次/分钟, 认证用户 100 次/分钟
- i18n支持(zh-hans/en-us), 在请求 Header 中声明： Accept-Language: zh-hans
- 当 cookie 中有 csrftoken 时, put|post|delete|patch 等请求需在 header 中声明: X-CSRFTOKEN
- 权限说明
    - Anyone
    - ... (TODO)
- 开发模式的登录方式: 登录 dev-accounts.pingcap.com 后, 将该域名的 `dev_sid` cookie 拷贝到本地, 再刷新页面即可
- 线上登录方式: 需要登录时重定向到该链接即可 http://accounts.pingcap.com/login?redirect_to=https%3A//university.pingcap.com/{!!my_path!!}


### 名词解释

- 课程设计
```
                                                      | -> PPT / PDF Lesson
Course(课程方向) -> Chapter(章节) -> Lesson(具体课程) -- | -> Video Lesson
                                                      | —> Offline
                                                      | -> complex Lesson (复杂课程, 上面 3 种的任意组合)
```

- 关于 URL slug: https://prettylinks.com/2018/03/url-slugs/


### 获取对所有人的推荐课程

#### Request

- Method: **GET**
- URL: `/api/lessons/recommend`
- Content-Type: application/json
- Permission: Anyone


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": [
            {
                "title": "分布式数据库历史和发展趋势",
                "description": "本课程简要介绍了数据库自上世纪中旬出现后....",
                "speaker": "黄东旭",
                "periods": 1.5, // 课时
                "cover_url": "https://img.example.com/cover.png",
                "types": ["offline"],  // 课程类型支持: offline, video
                "course": {
                    "slug": "PCTA", // 可以出现在 URL 中的唯一标识
                    "title": "PingCAP Certificated TiDB Associate 基础课程",
                    "description": "",
                    "cover_url": "https://img.example.com/cover.png",
                    "license": 0, // 0: free  1: vip
                },
                "chapter": {
                    "title": "概述",
                    "slug": "概述",
                    "description": "",
                },
            },
            {
                "title": "TiDB 架构原理",
                "description": "TiDB 是分布式数据库，具备水平扩展/高可用/ACID事务/SQL等特性",
                "speaker": "申砾",
                "periods": 1, // 课时
                "cover_url": "https://img.example.com/cover.png",
                "types": ["offline"],  // 课程类型支持: offline, video
                "course": {
                    "slug": "PCTA",
                    "title": "PingCAP Certificated TiDB Associate 基础课程",
                    "description": "",
                    "cover_url": "https://img.example.com/cover.png",
                    "license": 0, // 0: free  1: vip
                },
                "chapter": {
                    "title": "概述",
                    "slug": "概述",
                    "description": "",
                },
            }
        ]
    }
    ```

- Failed

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### 获取特定方向的推荐课程

#### Request

- Method: **GET**
- URL: `/api/courses/{course_slug}/lessons/recommend`
- Content-Type: application/json
- Permission: Anyone


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": [
            {
                "title": "分布式数据库历史和发展趋势",
                "short_title": "PCTA - 1.1",
                "description": "本课程简要介绍了数据库自上世纪中旬出现后....",
                "speaker": "黄东旭",
                "periods": 1.5, // 课时
                "cover_url": "https://img.example.com/cover.png",
                "types": ["offline"],  // 课程类型支持: offline, video
                "course": {
                    "slug": "PCTA",
                    "title": "PingCAP Certificated TiDB Associate 基础课程",
                    "description": "",
                    "cover_url": "https://img.example.com/cover.png",
                    "license": 0, // 0: free  1: vip
                },
                "chapter": {
                    "title": "概述",
                    "slug": "概述",
                    "description": "",
                },
            },
            {
                "title": "TiDB 架构原理",
                "short_title": "PCTA - 1.2",
                "description": "TiDB 是分布式数据库，具备水平扩展/高可用/ACID事务/SQL等特性",
                "speaker": "申砾",
                "periods": 1, // 课时
                "cover_url": "https://img.example.com/cover.png",
                "types": ["offline"],  // 课程类型支持: offline, video
                "course": {
                    "slug": "PCTA",
                    "title": "PingCAP Certificated TiDB Associate 基础课程",
                    "description": "",
                    "cover_url": "https://img.example.com/cover.png",
                    "license": 0, // 0: free  1: vip
                },
                "chapter": {
                    "title": "概述",
                    "slug": "概述",
                    "description": "",
                },
            }
        ]
    }
    ```

- Failed

 - HTTP/1.1 404

    ```json
    { "detail": "not found" }  // 未找到对应 Course
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取 Category 列表

#### Request

- Method: **GET**
- URL: `/api/categories`
- Content-Type: application/json
- Permission: Anyone

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "成功",
        "datas": [
            {
                "name": "DBA",
                "slug": "DBA",
                "description": "分类描述",
            },
            {
                "name": "Talent Plan",
                "slug": "Talent-Plan",
                "description": "分类描述",
            }
        ]
    }
    ```

- Failed

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取 Course 列表

#### Request

- Method: **GET**
- URL: `/api/courses`
- Params: categories  (e.g.  /api/courses?categories=DBA,Talent-Plan) 空值时默认返回全部
- Content-Type: application/json
- Permission: Anyone

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "成功",
        "datas": [
            {
                "title": "PingCAP Certified TiDB Associate 基础课程",
                "slug": "PCTA",
                "cover_url": "/uploads/b0/2c0/490173611eab6e3acde48001122.png",
                "license": 0,
                "category": null
            },
            {
                "title": "PingCAP Certified TiDB Professional 进阶课程",
                "slug": "PCTP",
                "cover_url": "/uploads/b0/2c0/490173611eab6e3acde48001122.png",
                "license": 0,
                "category": [{
                    "name": "DBA",
                    "slug": "DBA"
                }]
            }
        ]
    }
    ```

- Failed

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取 Course 详情

#### Request

- Method: **GET**
- URL: `/api/courses/{slug}`
- Content-Type: application/json
- Permission: Anyone

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "slug": "PCTA",
            "title": "PingCAP Certificated TiDB Associate 基础课程",
            "description": "Course 描述",
            "objectives": "教学目标",
            "propaedeutics": "预备知识",
            "references": "参考资料",
            "cover_url": "https://img.example.com/cover.png",
            "license": 0,
            "catalog_url": "/api/courses/PCTA/catalog"
        }
    }
    ```

- Failed

 - HTTP/1.1 404

    ```json
    { "detail": "not found" }  // 未找到对应 Course
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取 Course 目录

#### Request

- Method: **GET**
- URL: `/api/courses/{slug}/catalog`
- Content-Type: application/json
- Permission: Anyone

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "slug": "PCTA",
            "title": "PingCAP Certificated TiDB Associate 基础课程",
            "number_of_students": 10,  // 10 个人已学习该课程
            "speakers": "黄东旭,申砾,王军...",  // 课程部分讲师
            "description": "Course 描述",
            "objectives": "教学目标",
            "propaedeutics": "预备知识",
            "references": "参考资料",
            "cover_url": "https://img.example.com/cover.png",
            "license": 0,
            "chapters": [{
                "title": "一、概述",
                "slug": "概述",
                "description": "章节描述",
                "number_of_lessons": 2,
                "periods": 2,
                "lessons": [{
                    "title": "分布式数据库历史和发展趋势",
                    "speaker": "黄东旭",
                    "slug": "分布式数据库历史和发展趋势",
                    "periods": 1.5,
                    "cover_url": "https://img.example.com/cover.png",
                    "has_permission": true,
                    "quiz": {
                        "is_passed": true
                    },
                    //  "quiz": null,  没有 quiz
                    "types": [
                        "video"
                    ]
                }]
            }],
            "has_online_exam": false
        }
    }
    ```

- Failed

 - HTTP/1.1 404

    ```json
    { "detail": "not found" }  // 未找到对应 Course
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取 Course 的 Chapter 列表

#### Request

- Method: **GET**
- URL: `/api/courses/{slug}/chapters`
- Content-Type: application/json
- Permission: Anyone


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": [{
            "title": "概述",
            "description": "",
            "slug": "概述",
            "periods": 4
        }, {
            "title": "概述",
            "description": "",
            "slug": "概述",
            "periods": 5
        }]
    }
    ```

- Failed

 - HTTP/1.1 404

    ```json
    { "detail": "not found" }  // 未找到对应 Course
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### 获取 Chapter 的 Lesson 列表

#### Request

- Method: **GET**
- URL: `/api/courses/{course_slug}/chapters/{chapter_slug}/lessons`
- Content-Type: application/json
- Permission: Anyone


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": [{
            "title": "分布式数据库历史和发展趋势",
            "slug": "分布式数据库历史和发展趋势",
            "short_title": "PCTA - 1.1",
            "description": "本课程简要介绍了数据库自上世纪中旬出现后....",
            "speaker": "黄东旭",
            "periods": 1.5,
            "cover_url": "/uploads/cover.png",
            "types": ["offline", "video"],  // 课程类型支持: offline, video
            "has_permission": false,   // 用户是否有权限学习该课程
        }, {
            "title": "TiDB 架构原理",
            "slug": "分布式数据库历史和发展趋势",
            "short_title": "PCTA - 1.1",
            "description": "TiDB 是分布式数据库，具备水平扩展/高可用/ACID事务/SQL等特性",
            "speaker": "申砾",
            "periods": 1,
            "cover_url": "https://img.example.com/cover.png",
            "types": ["offline"],  // 课程类型支持: offline, video
            "has_permission": true,   // 用户是否有权限学习该课程
        }]
    }
    ```

- Failed

 - HTTP/1.1 404

    ```json
    { "detail": "not found" }  // 未找到对应 Chapter
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### 获取 Lesson 具体内容

#### Request

- Method: **GET**
- URL: `/api/courses/{course_slug}/chapters/{chapter_slug}/lessons/{lesson_slug}`
- Content-Type: application/json


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "title": "分布式数据库历史和发展趋势",
            "slug": "分布式数据库历史和发展趋势",
            "short_title": "PCTA - 1.1",
            "description": "本课程简要介绍了数据库自上世纪中旬出现后....",
            "key_points": "数据库历史；关系型数据库；NoSQL 和 中间件；分布式数据库；新技术",
            "objectives": "对数据库特别是分布式数据库本身有一定的了解",
            "speaker": "黄东旭",
            "periods": 1.5,
            "cover_url": "/uploads/cover.png",
            "types": ["offline", "video", "markdown", "pdf"],  // 课程类型支持: offline, video, markdown, pdf
            "is_authenticated": true,  // 已登录
            "has_permission": true,    // 有权限
            "syllabus": {
                "offline": "For details, please refer to the official documentation or participate in offline training",
                "markdown": {
                    "raw": "## markdown content"
                },
                "pdf": {
                    "link": "/lessons_lectures/1/pdf/detail",   // 访问该链接获取 pdf 文件
                },
                "video": {
                    "video_id": "01dc2a5a23ef4c3a8098702eb9dcdf59",
                    "trace_id": "6b928ba2-2789-11ea-b51d-acde48001122", // 视频事件追踪 ID
                    "duration": 5502.386, // 视频时长, 单位: 秒
                    "cover_image_url": "https://pu-img.pingcap.com/cover.png",
                    "log_url": "/lessons_lectures/1/video/log/01dc2a5a23ef4c3a8098702eb9dcdf59", // 打点上报地址
                    "played_at": 23.121, // 上次观看到(单位: 秒), 可能为 null
                    "last_definition": "FD",  // 上次的观看清晰度, 可能为 null
                    "play_details": [{
                        "play_url": "/videos/play/01dc2a5a/4d4353952c0981-da96edf37-fd.m3u8?trace_id=6b928ba2-2789-11ea-b51d-acde48001122", // 视频文件
                        "play_id": "4d4353952c0981-da96edf37-fd",
                        "bit_rate": 528.239,  // 码率, 单位: kb/s
                        "definition": "FD",   // 清晰度, FD -> 流畅, LD -> 标清, SD -> 高清
                        "width": 640,     // 视频宽度
                        "height": 360,     // 视频高度
                    }, {
                        "play_url": "/videos/play/01dc2a5a/4d4353952c0981-912dad7-ld.m3u8?trace_id=6b928ba2-2789-11ea-b51d-acde48001122",
                        "play_id": "4d4353952c0981-912dad7-ld",
                        "bit_rate": 1102.375,
                        "definition": "LD",
                        "width": 960,
                        "height": 540
                    }, {
                        "play_url": "/videos/play/01dc2a5a/4d4353952c0981-912dad7-sd.m3u8?trace_id=6b928ba2-2789-11ea-b51d-acde48001122",
                        "play_id": "4d4353952c0981-912dad7-sd",
                        "bit_rate": 1782.786,
                        "definition": "SD",
                        "width": 1280,
                        "height": 720
                    }]
                }
            },
            "quiz": {
                "is_passed": true,  // 是否完成了测验
                "questions": [{
                    "id": 1,     // 问题 ID
                    "question_type": 0,     // 问题类型 0:单选  1:多选  2:判断
                    "problem": "关于TiDB 的索引 Key 编码，下列哪一项是对的？",
                    "options": [
                        "需要 Mem compareble 的编码算法",
                        "索引 Key 中一定包含 RowID",
                        "索引 Key 编码后会和对应的数据的 RowKey 相邻",
                        "TiDB 支持对索引 Key 进行逆序编码，以支持逆序索引"
                    ],
                    "answer": "0100",   // 答案，选择题，1为答案,  0(A)1(B)0(C)0(D) 为 B
                    // is_passed == true: 正确答案
                    // is_passed == false: 用户历史答案，可能为空字符串
                }, {
                    "id": 2,     // 问题 ID
                    "question_type": 2,     // 问题类型 0:单选  1:多选  2:判断
                    "problem": "这个题是一个判断题？",
                    "options": [],
                    "answer": "1",   //  0:错误  1:正确,
                }]
            }
        }
    }
    ```

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "title": "分布式数据库历史和发展趋势",
            "slug": "分布式数据库历史和发展趋势",
            "short_title": "PCTA - 1.1",
            "description": "本课程简要介绍了数据库自上世纪中旬出现后....",
            "key_points": "数据库历史；关系型数据库；NoSQL 和 中间件；分布式数据库；新技术",
            "objectives": "对数据库特别是分布式数据库本身有一定的了解",
            "speaker": "黄东旭",
            "periods": 1.5,
            "cover_url": "/uploads/cover.png",
            "types": ["offline", "video"],  // 课程类型支持: offline, video
            "is_authenticated": true,  // 已登录
            "has_permission": false,    // 没有权限
            "syllabus": null,
            "quiz": null
        }
    }
    ```

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "title": "分布式数据库历史和发展趋势",
            "slug": "分布式数据库历史和发展趋势",
            "short_title": "PCTA - 1.1",
            "description": "本课程简要介绍了数据库自上世纪中旬出现后....",
            "key_points": "数据库历史；关系型数据库；NoSQL 和 中间件；分布式数据库；新技术",
            "objectives": "对数据库特别是分布式数据库本身有一定的了解",
            "speaker": "黄东旭",
            "periods": 1.5,
            "cover_url": "/uploads/cover.png",
            "types": ["offline", "video"],  // 课程类型支持: offline, video
            "is_authenticated": false,  // 未登录
            "has_permission": false,    // 没有权限
            "syllabus": null
        }
    }
    ```

- Failed

  - HTTP/1.1 404

    ```json
    { "detail": "not found" }  // 未找到对应 Lesson
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### Lesson quiz 提交答案

#### Request

- Method: **POST**
- URL: `/api/courses/{course_slug}/chapters/{chapter_slug}/lessons/{lesson_slug}/quiz`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)
- Body:

  ```json
    {
      "answers": {
        "question_id": "100",
        "question_id2": "0001"
      }
    }
    ```


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "question_id": true,   // 是否通过
            "question_id2": false
        }
    }
    ```

- Failed

 - HTTP/1.1 400

    ```json
    { "detail": "params error." }
    ```

 - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

 - HTTP/1.1 403

    ```json
    { "detail": "request is forbidden due to lack of permissions." }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### Lesson quiz 获取提示

#### Request

- Method: **GET**
- URL: `/api/courses/{course_slug}/chapters/{chapter_slug}/lessons/{lesson_slug}/quiz/{question_id}/hint`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "hint": "参考文档.....解释..."
        }
    }
    ```

- Failed

  - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取在线考试 Entry

#### Request

- Method: **GET**
- URL: `/api/courses/{course_slug}/online-exam/entry`
- Content-Type: application/json
- Permission: Anyone


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "exam_details": {
                "duration": 3600,  // 考试时长, 单位: 秒
                "total_score": 100,  // 总分
                "passing_score": 60,  // 及格线
                "allowed_number_of_times": 1,  // 允许参加的次数,  None 为不限次数
                "number_of_questions": 10,  // 题目数量
            },
            "has_permission": true,  // 是否可以参加考试
            "permission_details": {
                "is_authenticated": true,
                "has_course": true,
                "is_passed_quiz": true
            },
            "my_exam": {      // 为 null 时代表还未参加考试
                "status": 1,  // 1:正在考试   2:已结束
                "my_score": 10,    // 我的分数
                "is_passed": true,   // 是否通过了考试
                "remain_number_of_times": 1,  // 剩余多少次考试机会, 为 0 时不展示重新考试的按钮
            }
        }
    }
    ```

- Failed

 - HTTP/1.1 404

    ```json
    { "detail": "not found" }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取在线考试试题

#### Request

- Method: **GET**
- URL: `/api/courses/{course_slug}/online-exam`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)


#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "time_left": 3600,  // 距离交卷还剩多久, 单位:秒
            "duration": 3600,  // 考试时间, 单位:秒
            "total_score": 100,  // 总分
            "passing_score": 80,  // 及格线
            "number_of_questions": 30,  // 试题数量
            "questions": [{
                "question_type": 0,     // 问题类型 0:单选  1:多选  2:判断
                "problem": "关于TiDB 的索引 Key 编码，下列哪一项是对的？",
                "options": [
                    "需要 Mem compareble 的编码算法",
                    "索引 Key 中一定包含 RowID",
                    "索引 Key 编码后会和对应的数据的 RowKey 相邻",
                    "TiDB 支持对索引 Key 进行逆序编码，以支持逆序索引"
                ]
            }]
        }
    }
    ```

- Failed

  - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 403

    ```json
    { "detail": "forbidden" }
    ```

  - HTTP/1.1 404

    ```json
    { "detail": "not found" }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 在线考试交卷

#### Request

- Method: **POST**
- URL: `/api/courses/{course_slug}/online-exam`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)
- Body: 
   ```json
    {
      "answers": ["1001", "1", "0"]
    }
    ```

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "is_passed": true,  // 是否通过了考试
            "my_score": 20,   // 试卷得分
            "result_detail": [
                true,   // 对应的答案是否正确
                false,
                true
            ]
        }
    }
    ```

- Failed

  - HTTP/1.1 400

    ```json
    {
        "detail": "参数错误."
    }
    ```

  - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 403

    ```json
    { "detail": "forbidden" }
    ```

  - HTTP/1.1 404

    ```json
    { "detail": "not found" }
    ```

  - HTTP/1.1 409

    ```json
    { "detail": "没有正在进行中的考试" }
    ```


  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```



### 获取用户信息

#### Request

- Method: **GET**
- URL: `/api/users/me`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)



#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "成功",
        "datas": {
            "username": "wd051712322",
            "avatar_url": null,
            "industry": "industry",
            "job_title": "job_title",
            "tidb_relation": "tidb_relation",
            "newsql_usage_stage": "newsql_usage_stage",
            "want_try_tidb_version": "want_try_tidb_version",
            "tried_tidb_version": "tried_tidb_version",
            "accept_edm": true
        }
    }
    ```

- Failed

 - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### 更新用户信息

#### Request

- Method: **POST**
- URL: `/api/users/me`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)
- Body:

  ```json
    {
        "industry": "industry", // 所在行业
        "job_title": "job_title",  // 职位
        "tidb_relation": "tidb_relation",  // 与 TiDB 的关系
        "newsql_usage_stage": "newsql_usage_stage",  // 分布式数据库的使用阶段
        "want_try_tidb_version": "want_try_tidb_version",  // 想试用的 TiDB 版本
        "tried_tidb_version": "v4.0,v3.0",  // 使用过的 TiDB 版本，多个选项以逗号分隔
        "accept_edm": true, // 是够接受电子邮件营销，true / false
    }
    ```

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success"
    }
    ```

- Failed
  - HTTP/1.1 400

    ```json
    {
      "detail": "params wrong",
      "errors": {
        "industry": ["最多不能超过64个字符"],
        "job_title": ["最多不能超过64个字符"],
        "tidb_relation": ["最多不能超过64个字符"],
        "newsql_usage_stage": ["最多不能超过64个字符"],
        "want_try_tidb_version": ["最多不能超过64个字符"],
        "tried_tidb_version": ["最多不能超过64个字符"],  // 多个选项以逗号分隔
      }
    }
    ```

 - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### 获取所有考试列表

#### Request

- Method: **GET**
- URL: `/api/exams`
- Content-Type: application/json
- Permission: AllowAny

#### Response Example

- Success
  - HTTP 200

    ```json
    {
        "detail": "success",
        "datas": {
            "notice": "**日期:**  2020 年 2 月 15 日（周六）  \n**城市:** 北京、上海、深圳，具体考点 2 月 7 日前通知",  // Markdown 格式
            "exams": [{
                "id": 1,
                "name": "PCTA 考试",
                "description": "描述, 考试安排",  // Markdown 格式
                "price": 699.00,
                "registration_start": "2019-02-01 00:00:00",
                "registration_deadline": "2019-02-10 00:00:00",
                "venues": ["北京", "上海"],
                "exam_times": ["2019年02月01日", "2019年02月01日"],
                "required": [
                    "学完 PCTA 课程"
                ]
            }, {
                "id": 2,
                "name": "PCTP 考试",
                "description": "描述, 考试安排",  // Markdown 格式
                "price": 1299.00,
                "registration_start": "2019-02-01 00:00:00",
                "registration_deadline": "2019-02-10 00:00:00",
                "venues": ["北京", "上海"],
                "exam_times": ["2019年02月01日", "2019年02月01日"],
                "required": [
                    "学完 PCTP 课程",
                    "通过 PCTA 考试"
                ]
            }]
        }
    }
    ```

- Failed

  - HTTP 429

    ```json
    { "detail": "rate limit" }
    ```


### 获取考试详细信息

#### Request

- Method: **GET**
- URL: `/api/exams/<exam_id>`
- Content-Type: application/json
- Permission: AllowAny

#### Response Example

- Success
  - HTTP 200

    ```json
    {
        "detail": "success",
        "datas": {
            "id": 1,
            "name": "PCTA 考试",
            "description": "描述, 考试安排",  // Markdown 格式
            "price": 699.00,
            "registration_start": "2019-02-01 00:00:00",
            "registration_deadline": "2019-02-10 00:00:00",
            "venues": ["北京", "上海"],
            "exam_times": ["2019年02月01日", "2019年02月01日"],
            "required": [
                "学完 PCTA 课程"
            ]
        }
    }
    ```

- Failed

  - HTTP 429

    ```json
    { "detail": "rate limit" }
    ```


## 考试报名权限检查

#### Request

- Method: **GET**
- URL: `/api/exams/<exam_id>/registration-check`
- Content-Type: application/json
- Permission: IsAuthenticated

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": {
            "is_registrated": true,
            "is_permitted": false,
            "required": [    // 缺少哪些权限
                "通过 PCTA 考试",
                "学完 PCTP 课程"
            ]
        }
    }
    ```

- Failed

  - HTTP 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP 404

    ```json
    { "detail": "Not found" }
    ```

  - HTTP 429

    ```json
    { "detail": "rate limit" }
    ```


## 考试报名

#### Request

- Method: **POST**
- URL: `/api/exams/<exam_id>/registrate`
- Content-Type: application/json
- Permission: IsAuthenticated
- Body:

  ```json
    {
      "exam_time": "2020-02-15",  // 从考试详情 exam_times 中取
      "exam_venue": "北京",  // 从考试详情 venues 中取
    }
    ```

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success"
    }
    ```

- Failed

  - HTTP 400

    ```json
    {
        "detail": "wrong params",
        "errors": {
            "__all__": [
                "already registrated",
                "incomplete user information"
            ],
            "exam_time": [
                "invalid exam time"
            ],
            "exam_venue": [
                "invalid exam venue"
            ]
        },
        "is_permitted": false,
        "required": [
            "通过 PTCP 考试"
        ]
    }
    ```

  - HTTP 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP 404

    ```json
    { "detail": "Not found" }
    ```

  - HTTP 429

    ```json
    { "detail": "rate limit" }
    ```


## 获取我报名的考试列表

#### Request

- Method: **GET**
- URL: `/api/my-exams`
- Content-Type: application/json
- Permission: IsAuthenticated

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "success",
        "datas": [{
            "exam_time": "2020-02-15",  // 考试时间
            "exam_venue": "北京",  // 考试地点
            "status": 0,  // 0: 已报名, 待管理员确认; 1: 报名成功;  2: 已结束
            "status_display": "已报名, 待管理员确认",
            "created_at": "2019-02-01 12:44:00",  // 报名时间
            "exam": {
                "id": 1,
                "name": "PCTA 考试",
                "price": 699,
                "description": "考试安排"
            }
        }]
    }
    ```

- Failed

  - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### Video 事件打点上报

#### Request

- Method: **GET**
- URL: `/lessons_lectures/{lesson_id}/video/log/{video_id}`  // 直接从 [lesson-detail](#获取-Lesson-具体内容) 的返回结果中取即可
- Content-Type: application/json
- Permission: 有观看视频权限的用户
- Param:

    |  参数名  | 含义 | 示例  |
    |  ----| ----  | ----  |
    |  event | 事件类型 | playing/end/stop/start |
    | play_at  | 当前播放到, 单位秒, 精确到毫秒 | 60.123 |
    | referrer | 视频播放页面路径 | https://university.pingcap.com/dba-lesson/?course_slug=PCTE&chapter_slug=TiDB-for-OLAP&lesson_slug=TiSpark-%E5%8E%9F%E7%90%86 |
    | definition | 清晰度 | FD/LD/SD |
    | speed | 播放倍速 | 1/2/3 |
    | ts | 当前时间戳, 精确到毫秒 | 1577262745.123 |
    | sequence | 当前播放到第几段, 从m3u8文件中取 | 3 |
    | range | 仅playing事件上报该字段, 当前播放完的ts区间段 | 114.312,124.433|
    | trace_id | 播放id, 从 api:[lesson_detail](#获取-Lesson-具体内容) 中取 | 6b928ba2-2789-11ea-b51d-acde48001122 |
    | version | 事件版本号, 固定为1 | 1 |

- PS: start/stop/end 事件在触发时上报, playing 事件在每次播放完一个 ts 后上报一次
- Example:
    ```
    https://university.pingcap.com/lessons_lectures/1/video/log/01dc2a5a23ef4c3a8098702eb9dcdf59?event=playing&play_at=60.123&referrer=https%3a%2f%2funiversity.pingcap.com%2fdba-lesson%2f%3fcourse_slug%3dPCTE%26chapter_slug%3dTiDB-for-OLAP%26lesson_slug%3dTiSpark-%25E5%258E%259F%25E7%2590%2586&definition=FD&speed=1&ts=1577262745.123&sequence=3&range=114.312,124.433&trace_id=6b928ba2-2789-11ea-b51d-acde48001122&version=1
    ```

#### Response Example

- Success
  - HTTP 200

- Failed

  - HTTP 401

  - HTTP 404

  - HTTP 403


### 获取学习进度

#### Request

- Method: **GET**
- URL: `/api/learning-progress`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "成功",
        "data": [
            {
                "slug": "PCTA",
                "title": "PingCAP Certified TiDB Associate 基础课程",
                "number_of_lessons": 14,
                "last_visited": {
                    "course_slug": "PCTA",
                    "chapter_slug": "概述",
                    "lesson_slug": "分布式数据库历史和发展趋势",
                    "lesson_title": "1.1 分布式数据库历史和发展趋势",
                    "progress": 0.9086966999407166
                },
                "visited": {
                    "visited_count": 1,
                    "progress": 0.06490690713862261
                },
                "quiz": {   // 若该 Course 没有 quiz, 则该字段为 null
                    "number_of_quiz": 1,
                    "passed_count": 0
                },
                "exam": {  // 若该 Course 没有 exam, 则该字段为 null
                    "number_of_exam": 1,
                    "passed_count": 0
                }
            }
        ]
    }
    ```

- Failed

 - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


### 获取 Course 学习进度

#### Request

- Method: **GET**
- URL: `/api/learning-progress/<course_slug>`
- Content-Type: application/json
- Permission: IsAuthenticate (要求已登录)

#### Response Example

- Success
  - HTTP/1.1 200

    ```json
    {
        "detail": "成功",
        "data": {
            "slug": "PCTA",
            "title": "PingCAP Certified TiDB Associate 基础课程",
            "progress": 0.06490690713862261,
            "chapters": [
                {
                    "slug": "概述",
                    "title": "一、概述",
                    "sequence": 1,
                    "lessons": [
                        {
                            "slug": "分布式数据库历史和发展趋势",
                            "title": "1.1 分布式数据库历史和发展趋势",
                            "progress": 0.9086966999407166,
                            "sequence": 1
                        },
                        {
                            "slug": "分布式数据库历史和发展趋势",
                            "title": "1.2 分布式数据库历史和发展趋势",
                            "progress": 0.88,
                            "sequence": 2
                        },
                    ]
                },
                // ...
            ]
        }
    }
    ```

- Failed

 - HTTP/1.1 401

    ```json
    { "detail": "Authentication credentials were not provided." }
    ```

  - HTTP/1.1 429

    ```json
    { "detail": "rate limit" }
    ```


