diff --git a/install/data/defaults.json b/install/data/defaults.json index a6f53f49c0..86fc1075c4 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -109,6 +109,7 @@ "email:sendmail:rateLimit": 2, "email:sendmail:rateDelta": 1000, "hideFullname": 0, + "hideEmail": 0, "allowGuestHandles": 0, "disableRecentCategoryFilter": 0, "maximumRelatedTopics": 0, diff --git a/install/package.json b/install/package.json index d3d5c3bc89..e31280ec24 100644 --- a/install/package.json +++ b/install/package.json @@ -104,6 +104,7 @@ "prompt": "^1.0.0", "redis": "3.0.2", "request": "2.88.2", + "request-promise-native": "^1.0.8", "rimraf": "3.0.2", "rss": "^1.2.2", "sanitize-html": "^1.23.0", diff --git a/public/openapi/components/schemas/Breadcrumbs.yaml b/public/openapi/components/schemas/Breadcrumbs.yaml index ab37c6f297..986e3544cb 100644 --- a/public/openapi/components/schemas/Breadcrumbs.yaml +++ b/public/openapi/components/schemas/Breadcrumbs.yaml @@ -9,4 +9,8 @@ Breadcrumbs: text: type: string url: - type: string \ No newline at end of file + type: string + cid: + type: number + required: + - text \ No newline at end of file diff --git a/public/openapi/components/schemas/CommonProps.yaml b/public/openapi/components/schemas/CommonProps.yaml index aef0eb8a0e..1ba5a30599 100644 --- a/public/openapi/components/schemas/CommonProps.yaml +++ b/public/openapi/components/schemas/CommonProps.yaml @@ -47,10 +47,7 @@ CommonProps: property: type: string required: - - name - content - - noEscape - - property link: type: array items: @@ -69,30 +66,14 @@ CommonProps: required: - rel - href - - type - - sizes widgets: type: object - description: Rendered widgets - properties: - header: - type: array - items: - type: object - properties: - html: - type: string - sidebar: - type: array - items: - type: object - properties: - html: - type: string - footer: - type: array - items: - type: object - properties: - html: - type: string \ No newline at end of file + description: Each widget area will have its own property in this object + additionalProperties: + type: array + description: A collection of HTML snippets that are appended to each widget area + items: + type: object + properties: + html: + type: string \ No newline at end of file diff --git a/public/openapi/components/schemas/GroupObject.yaml b/public/openapi/components/schemas/GroupObject.yaml index a383a9a3da..89b4cf9a4a 100644 --- a/public/openapi/components/schemas/GroupObject.yaml +++ b/public/openapi/components/schemas/GroupObject.yaml @@ -1,5 +1,6 @@ -GroupObject: +GroupFullObject: type: object + description: The response from an internal call to `Groups.get()` properties: name: type: string @@ -14,7 +15,7 @@ GroupObject: type: number description: Label text for the user badge userTitleEnabled: - type: boolean + type: number description: type: string description: The group description @@ -73,3 +74,60 @@ GroupObject: type: boolean isOwner: type: boolean + nullable: true +GroupDataObject: + type: object + description: The response from an internal call to `Groups.getGroupData(, [])` with **explicitly** no fields passed in + properties: + name: + type: string + description: The group name + slug: + type: string + description: URL-safe slug of the group name + createtime: + type: number + description: UNIX timestamp of the group's creation + userTitle: + type: number + description: Label text for the user badge + userTitleEnabled: + type: number + description: + type: string + description: The group description + memberCount: + type: number + hidden: + type: number + system: + type: number + private: + type: number + disableJoinRequests: + type: number + disableLeave: + type: number + cover:url: + type: string + cover:thumb:url: + type: string + nameEncoded: + type: string + displayName: + type: string + description: A custom override of the group's name, a friendly name + labelColor: + type: string + description: A six-character hexadecimal colour code + textColor: + type: string + description: A six-character hexadecimal colour code + icon: + type: string + description: A FontAwesome icon string + createtimeISO: + type: string + description: "`createtime` rendered as an ISO 8601 format" + cover:position: + type: string \ No newline at end of file diff --git a/public/openapi/components/schemas/Pagination.yaml b/public/openapi/components/schemas/Pagination.yaml index 2b284015ae..290eb95971 100644 --- a/public/openapi/components/schemas/Pagination.yaml +++ b/public/openapi/components/schemas/Pagination.yaml @@ -34,10 +34,30 @@ Pagination: type: boolean rel: type: array - items: {} + description: A collection of objects used to build the link tags pointing to adjacent pages, if any. + items: + type: object + properties: + rel: + type: string + enum: [prev, next] + href: + type: string + description: A query string that points to the previous or next page pages: type: array - items: {} + items: + type: object + properties: + page: + type: number + description: The current page + active: + type: boolean + description: If the page noted in this array is the current page + qs: + type: string + description: A query string that points to the page noted in this array currentPage: type: number pageCount: diff --git a/public/openapi/components/schemas/PostsObject.yaml b/public/openapi/components/schemas/PostsObject.yaml index 9a6e0eaee3..1962a9a71f 100644 --- a/public/openapi/components/schemas/PostsObject.yaml +++ b/public/openapi/components/schemas/PostsObject.yaml @@ -41,6 +41,7 @@ PostsObject: removed, etc.) picture: type: string + nullable: true status: type: string icon:text: @@ -79,6 +80,10 @@ PostsObject: type: number description: The post id of the first post in this topic (also called the "original post") + teaserPid: + type: number + description: The post id of the teaser (the most recent post, depending on settings) + nullable: true titleRaw: type: string category: diff --git a/public/openapi/components/schemas/TopicObject.yaml b/public/openapi/components/schemas/TopicObject.yaml new file mode 100644 index 0000000000..9521050915 --- /dev/null +++ b/public/openapi/components/schemas/TopicObject.yaml @@ -0,0 +1,253 @@ +TopicObject: + type: object + properties: + tid: + type: number + description: A topic identifier + uid: + type: number + description: A user identifier + cid: + type: number + description: A category identifier + mainPid: + type: number + description: The post id of the first post in this topic (also called the + "original post") + title: + type: string + slug: + type: string + timestamp: + type: number + lastposttime: + type: number + postcount: + type: number + viewcount: + type: number + teaserPid: + oneOf: + - type: number + - type: string + nullable: true + upvotes: + type: number + downvotes: + type: number + deleted: + type: number + locked: + type: number + pinned: + type: number + description: Whether or not this particular topic is pinned to the top of the + category + deleterUid: + type: number + titleRaw: + type: string + timestampISO: + type: string + description: An ISO 8601 formatted date string (complementing `timestamp`) + lastposttimeISO: + type: string + votes: + type: number + category: + type: object + properties: + cid: + type: number + description: A category identifier + name: + type: string + slug: + type: string + icon: + type: string + image: + nullable: true + type: string + imageClass: + nullable: true + type: string + bgColor: + type: string + color: + type: string + disabled: + type: number + user: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + fullname: + type: string + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + reputation: + type: number + postcount: + type: number + picture: + type: string + nullable: true + signature: + type: string + nullable: true + banned: + type: number + status: + type: string + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + banned_until_readable: + type: string + required: + - uid + - username + - userslug + - reputation + - postcount + - picture + - signature + - banned + - status + - icon:text + - icon:bgColor + - banned_until_readable + teaser: + type: object + properties: + pid: + type: number + uid: + type: number + description: A user identifier + timestamp: + type: number + tid: + type: number + description: A topic identifier + content: + type: string + timestampISO: + type: string + description: An ISO 8601 formatted date string (complementing `timestamp`) + user: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + type: string + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users + without an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's + auto-generated icon + example: "#f44336" + index: + type: number + nullable: true + tags: + type: array + items: + type: object + properties: + value: + type: string + valueEscaped: + type: string + color: + type: string + bgColor: + type: string + score: + type: number + isOwner: + type: boolean + ignored: + type: boolean + unread: + type: boolean + bookmark: + nullable: true + type: number + unreplied: + type: boolean + icons: + type: array + items: + type: string + description: HTML injected into the theme + index: + type: number + thumb: + type: string + required: + - tid + - uid + - cid + - mainPid + - title + - slug + - timestamp + - lastposttime + - postcount + - viewcount + - teaserPid + - upvotes + - downvotes + - deleted + - locked + - pinned + - deleterUid + - titleRaw + - timestampISO + - lastposttimeISO + - votes + - category + - user + - teaser + - tags + - isOwner + - ignored + - unread + - bookmark + - unreplied + - icons + - index \ No newline at end of file diff --git a/public/openapi/components/schemas/UserObject.yaml b/public/openapi/components/schemas/UserObject.yaml index 518212515f..1509a8ef54 100644 --- a/public/openapi/components/schemas/UserObject.yaml +++ b/public/openapi/components/schemas/UserObject.yaml @@ -33,34 +33,41 @@ UserObject: type: string description: A URL pointing to a picture to be used as the user's avatar example: 'https://images.unsplash.com/photo-1560070094-e1f2ddec4337?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&h=256&q=80' + nullable: true fullname: type: string example: Mr. Dragon Fruit Jr. location: type: string example: 'Toronto, Canada' + nullable: true birthday: type: string description: A birthdate given in an ISO format parseable by the Date object example: 03/27/2020 + nullable: true website: type: string example: 'https://example.org' + nullable: true aboutme: type: string example: | This is a paragraph all about how my life got twist-turned upside-down and I'd like to take a minute and sit right here, - to tell you all about how I because the administrator of NodeBB + to tell you all about how I became the administrator of NodeBB + nullable: true signature: type: string example: | This is an example signature It can span multiple lines. + nullable: true uploadedpicture: type: string example: /assets/profile/1-profileimg.png description: 'In almost all cases, defer to "picture" instead. Use this if you need to specifically reference the picture uploaded to the forum.' + nullable: true profileviews: type: number description: The number of times this user's profile has been viewed @@ -98,18 +105,21 @@ UserObject: flags: type: number example: 0 - followercount: + nullable: true + followerCount: type: number example: 2 - followingcount: + followingCount: type: number example: 5 'cover:url': type: string example: /assets/profile/1-cover.png + nullable: true 'cover:position': type: string example: 50.0301% 19.2464% + nullable: true groupTitle: type: string example: '["administrators","Staff"]' @@ -140,7 +150,45 @@ UserObject: type: string description: An ISO 8601 formatted date string representing the moment a ban will be lifted, or the words "Not Banned" example: Not Banned + required: + - uid + - username + - userslug + - 'email:confirmed' + - joindate + - lastonline + - picture + - location + - birthday + - website + - aboutme + - signature + - uploadedpicture + - profileviews + - reputation + - postcount + - topiccount + - lastposttime + - banned + - 'banned:expire' + - status + - enum + - flags + - followerCount + - followingCount + - 'cover:url' + - 'cover:position' + - groupTitle + - groupTitleArray + - example + - 'icon:text' + - 'icon:bgColor' + - joindateISO + - lastonlineISO + - banned_until + - banned_until_readable UserObjectFull: + # accountHelpers.getUserDataByUserSlug type: object properties: uid: @@ -175,6 +223,7 @@ UserObjectFull: type: string description: A URL pointing to a picture to be used as the user's avatar example: 'https://images.unsplash.com/photo-1560070094-e1f2ddec4337?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&h=256&q=80' + nullable: true fullname: type: string example: Mr. Dragon Fruit Jr. @@ -193,7 +242,7 @@ UserObjectFull: example: | This is a paragraph all about how my life got twist-turned upside-down and I'd like to take a minute and sit right here, - to tell you all about how I because the administrator of NodeBB + to tell you all about how I became the administrator of NodeBB signature: type: string example: | @@ -203,6 +252,7 @@ UserObjectFull: type: string example: /assets/profile/1-profileimg.png description: 'In almost all cases, defer to "picture" instead. Use this if you need to specifically reference the picture uploaded to the forum.' + nullable: true profileviews: type: number description: The number of times this user's profile has been viewed @@ -240,18 +290,21 @@ UserObjectFull: flags: type: number example: 0 - followercount: + nullable: true + followerCount: type: number example: 2 - followingcount: + followingCount: type: number example: 5 'cover:url': type: string example: /assets/profile/1-cover.png + nullable: true 'cover:position': type: string example: 50.0301% 19.2464% + nullable: true groupTitle: type: string example: '["administrators","Staff"]' @@ -332,7 +385,8 @@ UserObjectFull: type: boolean groups: type: array - items: {} + items: + $ref: ./GroupObject.yaml#/GroupFullObject disableSignatures: type: boolean reputation:disabled: @@ -369,6 +423,12 @@ UserObjectFull: type: boolean icon: type: string + required: + - id + - route + - name + - visibility + - public sso: type: array items: @@ -411,6 +471,7 @@ UserObjectSlim: type: string description: A URL pointing to a picture to be used as the user's avatar example: 'https://images.unsplash.com/photo-1560070094-e1f2ddec4337?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&h=256&q=80' + nullable: true status: type: string enum: @@ -437,6 +498,7 @@ UserObjectSlim: flags: type: number example: 0 + nullable: true banned: type: number description: A Boolean representing whether a user is banned or not @@ -473,3 +535,74 @@ UserObjectSlim: example: Not Banned administrator: type: boolean +UserObjectACP: + type: object + properties: + uid: + type: number + description: A user identifier + example: 1 + username: + type: string + description: A friendly name for a given user account + example: Dragon Fruit + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces removed, etc.) + example: dragon-fruit + email: + type: string + description: Email address associated with the user account + example: dragonfruit@example.org + postcount: + type: number + example: 1000 + joindate: + type: number + description: A UNIX timestamp representing the moment the user's account was created + example: 1585337827953 + banned: + type: number + description: A Boolean representing whether a user is banned or not + example: 0 + reputation: + type: number + description: The user's reputation score on the forum. Out-of-the-box, users gain/lose reputation points based on upvotes/downvotes, though plugins can alter the logic and criterion for awarding reputation points + example: 100 + picture: + type: string + description: A URL pointing to a picture to be used as the user's avatar + example: 'https://images.unsplash.com/photo-1560070094-e1f2ddec4337?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&h=256&q=80' + nullable: true + flags: + type: number + example: 0 + nullable: true + lastonline: + type: number + description: A UNIX timestamp representing the moment the user was last recorded online on this site + example: 1585337827953 + 'email:confirmed': + type: number + description: Whether the user has confirmed their email address or not + example: 1 + 'icon:text': + type: string + description: A single-letter representation of a username. This is used in the auto-generated icon given to users without an avatar + example: D + 'icon:bgColor': + type: string + description: A six-character hexadecimal colour code assigned to the user. This value is used in conjunction with `icon:text` for the user's auto-generated icon + example: '#9c27b0' + joindateISO: + type: string + example: '2020-03-27T20:30:36.590Z' + lastonlineISO: + type: string + example: '2020-03-27T20:30:36.590Z' + banned_until_readable: + type: string + description: An ISO 8601 formatted date string representing the moment a ban will be lifted, or the words "Not Banned" + example: Not Banned + administrator: + type: boolean diff --git a/public/openapi/read.yaml b/public/openapi/read.yaml index 8a6088e6b7..023e1623be 100644 --- a/public/openapi/read.yaml +++ b/public/openapi/read.yaml @@ -75,13 +75,21 @@ paths: properties: title: type: string + description: The page title categories: + description: A collection of category data objects type: array items: allOf: - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - type: object properties: + tagWhitelist: + type: array + items: + type: string + unread-class: + type: string children: type: array items: @@ -91,14 +99,25 @@ paths: properties: tagWhitelist: type: array - items: {} + items: + type: string unread-class: type: string children: type: array - items: {} + items: + $ref: components/schemas/CategoryObject.yaml#/CategoryObject parent: - $ref: components/schemas/CategoryObject.yaml#/CategoryObject + allOf: + - $ref: components/schemas/CategoryObject.yaml#/CategoryObject + - type: object + properties: + tagWhitelist: + type: array + items: + type: string + unread-class: + type: string posts: type: array items: @@ -236,240 +255,9 @@ paths: type: string title: type: string - topics: - type: array - items: - type: object - properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - deleted: - type: number - locked: - type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - upvotes: - type: number - downvotes: - type: number - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: - type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true imageClass: - nullable: true - type: string - bgColor: - type: string - color: - type: string - disabled: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - picture: - nullable: true - type: string - signature: - nullable: true - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - banned_until_readable: - type: string - oldUid: - type: number - groupTitle: - type: string - groupTitleArray: - type: array - items: {} - fullname: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - thumb: - type: string - teaserPid: - type: number - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/post/{pid}/raw": - get: - tags: - - posts - summary: Get a post's raw text - description: >- - This route returns the raw content of a post, without running it through any installed parsers. It it useful if you wish to populate a user control on the client-side with the raw input for editing purposes. - - If you are using this on the client side DOM, be careful that appropriate sanitization measures are taken, as raw content will faithfully reproduce any script injections embedded in the post content. - parameters: - - name: pid - in: path - required: true - schema: - type: number - responses: - "200": - description: "" - content: - application/json: - schema: - type: object - properties: - pid: - type: number - content: - type: string /api/admin: get: tags: @@ -498,8 +286,10 @@ paths: type: boolean latestVersion: type: string + nullable: true upgradeAvailable: type: boolean + nullable: true currentPrerelease: type: boolean notices: @@ -517,6 +307,8 @@ paths: type: string link: type: string + required: + - done stats: type: array items: @@ -553,6 +345,7 @@ paths: canRestart: type: boolean lastrestart: + nullable: true type: object properties: uid: @@ -731,6 +524,9 @@ paths: items: type: object properties: + id: + type: string + description: Unique ID that will be added to the navigation element's `id` property in the DOM route: type: string description: Relative URL to the page the navigation item goes to @@ -756,12 +552,17 @@ paths: items: type: object properties: + name: + type: string displayName: type: string - selected: - type: boolean - groups: - type: array + properties: + type: object + properties: + targetBlank: + type: boolean + groups: + type: array items: type: object properties: @@ -849,6 +650,7 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "" @@ -865,7 +667,8 @@ paths: properties: tagWhitelist: type: array - items: {} + items: + type: string unread-class: type: string parent: @@ -883,7 +686,8 @@ paths: type: boolean customClasses: type: array - items: {} + items: + type: string - $ref: components/schemas/CommonProps.yaml#/CommonProps "/api/admin/manage/categories/{category_id}/analytics": get: @@ -896,6 +700,7 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "" @@ -927,17 +732,18 @@ paths: items: type: number - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/admin/manage/privileges/{cid?}": + "/api/admin/manage/privileges/{cid}": get: tags: - admin - summary: /api/admin/manage/privileges/{cid?} + summary: Get category privileges parameters: - - name: cid? + - name: cid in: path required: true schema: type: string + example: 1 responses: "200": description: "" @@ -969,7 +775,18 @@ paths: type: string users: type: array - items: {} + items: + type: object + properties: + name: + type: string + nameEscaped: + type: string + privileges: + type: object + additionalProperties: + type: boolean + description: Each privilege will have a key in this object groups: type: array items: @@ -981,37 +798,9 @@ paths: type: string privileges: type: object - properties: - groups:find: - type: boolean - groups:read: - type: boolean - groups:topics:read: - type: boolean - groups:topics:create: - type: boolean - groups:topics:reply: - type: boolean - groups:topics:tag: - type: boolean - groups:posts:edit: - type: boolean - groups:posts:history: - type: boolean - groups:posts:delete: - type: boolean - groups:posts:upvote: - type: boolean - groups:posts:downvote: - type: boolean - groups:topics:delete: - type: boolean - groups:posts:view_deleted: - type: boolean - groups:purge: - type: boolean - groups:moderate: - type: boolean + additionalProperties: + type: boolean + description: Each privilege will have a key in this object isPrivate: type: boolean columnCountUser: @@ -1048,6 +837,11 @@ paths: type: string imageClass: type: string + required: + - cid + - name + - icon + - selected selectedCategory: type: object properties: @@ -1068,6 +862,8 @@ paths: type: string bgColor: type: string + imageClass: + type: string selected: type: boolean cid: @@ -1208,16 +1004,28 @@ paths: properties: username: type: string + description: A friendly name for a given user account userslug: type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) picture: type: string uid: type: number + description: A user identifier icon:text: type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar icon:bgColor: type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" topic: type: object properties: @@ -1227,6 +1035,8 @@ paths: type: number category: $ref: components/schemas/CategoryObject.yaml#/CategoryObject + title: + type: string - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/CommonProps.yaml#/CommonProps /api/admin/manage/ip-blacklist: @@ -1248,6 +1058,7 @@ paths: rules: type: string description: A plain text string containing blocked IPs or IP ranges. Separate entries are separated by a newline (`\n`) + nullable: true analytics: type: object properties: @@ -1281,7 +1092,7 @@ paths: users: type: array items: - $ref: components/schemas/UserObject.yaml#/UserObject + $ref: components/schemas/UserObject.yaml#/UserObjectACP page: type: number pageCount: @@ -1318,7 +1129,8 @@ paths: type: string users: type: array - items: {} + items: + $ref: components/schemas/UserObject.yaml#/UserObjectACP - $ref: components/schemas/CommonProps.yaml#/CommonProps /api/admin/manage/users/latest: get: @@ -1326,36 +1138,8 @@ paths: - admin summary: /api/admin/manage/users/latest responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - users: - type: array - items: - $ref: components/schemas/UserObject.yaml#/UserObject - page: - type: number - pageCount: - type: number - resultsPerPage: - type: number - latest: - type: boolean - search_display: - type: string - requireEmailConfirmation: - type: number - inviteOnly: - type: boolean - adminInviteOnly: - type: boolean - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/CommonProps.yaml#/CommonProps + "418": + description: "TODO: A proper response needs to be added. It is not really a teapot | Replace this responses block with the block from /manage/users/latest" /api/admin/manage/users/not-validated: get: tags: @@ -1448,16 +1232,30 @@ paths: items: type: object properties: - uid: - type: number username: type: string + description: A friendly name for a given user account + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) picture: type: string + uid: + type: number + description: A user identifier icon:text: type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar icon:bgColor: type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" customActions: type: array items: @@ -1504,9 +1302,9 @@ paths: - type: object properties: admins: - $ref: components/schemas/GroupObject.yaml#/GroupObject + $ref: components/schemas/GroupObject.yaml#/GroupFullObject globalMods: - $ref: components/schemas/GroupObject.yaml#/GroupObject + $ref: components/schemas/GroupObject.yaml#/GroupFullObject categories: type: array items: @@ -1540,6 +1338,11 @@ paths: type: array items: $ref: components/schemas/UserObject.yaml#/UserObjectSlim + allPrivileges: + type: array + items: + type: string + description: A simple array containing user privilege names (used client-side when giving mod privilege) - $ref: components/schemas/CommonProps.yaml#/CommonProps /api/admin/manage/groups: get: @@ -1608,6 +1411,28 @@ paths: type: string ownerUid: type: number + required: + - name + - description + - hidden + - system + - userTitle + - icon + - labelColor + - slug + - createtime + - memberCount + - private + - cover:url + - cover:position + - userTitleEnabled + - disableJoinRequests + - disableLeave + - nameEncoded + - displayName + - textColor + - createtimeISO + - cover:thumb:url yourid: type: number - $ref: components/schemas/Pagination.yaml#/Pagination @@ -1623,6 +1448,7 @@ paths: required: true schema: type: string + example: administrators responses: "200": description: "" @@ -1633,77 +1459,7 @@ paths: - type: object properties: group: - type: object - properties: - name: - type: string - slug: - type: string - createtime: - type: number - userTitle: - type: string - userTitleEnabled: - type: number - description: - type: string - memberCount: - type: number - hidden: - type: number - system: - type: number - private: - type: number - disableJoinRequests: - type: number - disableLeave: - type: number - icon: - type: string - labelColor: - type: string - textColor: - type: string - nameEncoded: - type: string - displayName: - type: string - createtimeISO: - type: string - cover:thumb:url: - type: string - cover:url: - type: string - cover:position: - type: string - descriptionParsed: - type: string - members: - type: array - items: - allOf: - - $ref: components/schemas/UserObject.yaml#/UserObject - - type: object - properties: - isOwner: - type: boolean - membersNextStart: - type: number - pending: - type: array - items: {} - invited: - type: array - items: {} - isMember: - type: boolean - isPending: - type: boolean - isInvited: - type: boolean - isOwner: - type: boolean + $ref: components/schemas/GroupObject.yaml#/GroupFullObject groupNames: type: array items: @@ -1733,6 +1489,7 @@ paths: schema: type: string description: Path of the folder, relative to `public/uploads/` + example: / responses: "200": description: "A JSON object containing uploaded files" @@ -1783,10 +1540,10 @@ paths: get: tags: - admin - summary: /api/admin/manage/digest + summary: Get system digest info/settings responses: "200": - description: "" + description: "A JSON object containing recent digest sends and settings" content: application/json: schema: @@ -1826,19 +1583,23 @@ paths: type: boolean default: type: string + required: + - title + - delivery - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/admin/settings/{term?}": + "/api/admin/settings/{term}": get: tags: - admin - summary: /api/admin/settings/{term?} + summary: Get system settings parameters: - - name: term? + - name: term in: path required: true schema: type: string + example: general responses: "200": description: "" @@ -1847,28 +1608,23 @@ paths: schema: allOf: - type: object - properties: - notificationSettings: - type: array - items: - type: object - properties: - name: - type: string - label: - type: string + properties: {} + additionalProperties: + type: object + description: Most of the settings pages have their values loaded on the client-side, so the settings are not exposed server-side. - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/admin/appearance/{term?}": + "/api/admin/appearance/{term}": get: tags: - admin - summary: /api/admin/appearance/{term?} + summary: Get appearance settings parameters: - - name: term? + - name: term in: path required: true schema: type: string + example: themes responses: "200": description: "" @@ -1928,10 +1684,23 @@ paths: type: string text: type: string + nullable: true outdated: type: boolean settingsRoute: type: string + required: + - latest + - description + - name + - id + - installed + - active + - isTheme + - error + - version + - license + - outdated installedCount: type: number activeCount: @@ -1965,6 +1734,16 @@ paths: type: boolean active: type: boolean + required: + - name + - updated + - latest + - url + - numInstalls + - isCompatible + - id + - installed + - active incompatible: type: array items: @@ -1990,6 +1769,16 @@ paths: type: boolean active: type: boolean + required: + - name + - updated + - latest + - url + - numInstalls + - isCompatible + - id + - installed + - active submitPluginUsage: type: number version: @@ -2176,293 +1965,50 @@ paths: get: tags: - admin - summary: /api/admin/advanced/database + summary: Get database information responses: "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - redis: - type: object - properties: - aof_current_rewrite_time_sec: - type: string - aof_enabled: - type: string - aof_last_bgrewrite_status: - type: string - aof_last_rewrite_time_sec: - type: string - aof_rewrite_in_progress: - type: string - aof_rewrite_scheduled: - type: string - arch_bits: - type: string - blocked_clients: - type: string - client_biggest_input_buf: - type: string - client_longest_output_list: - type: string - config_file: - type: string - connected_clients: - type: string - connected_slaves: - type: string - db0: - type: string - evicted_keys: - type: string - expired_keys: - type: string - gcc_version: - type: string - hz: - type: string - instantaneous_ops_per_sec: - type: string - keyspace_hits: - type: string - keyspace_misses: - type: string - latest_fork_usec: - type: string - loading: - type: string - lru_clock: - type: string - master_repl_offset: - type: string - mem_allocator: - type: string - mem_fragmentation_ratio: - type: string - multiplexing_api: - type: string - os: - type: string - process_id: - type: string - pubsub_channels: - type: string - pubsub_patterns: - type: string - rdb_bgsave_in_progress: - type: string - rdb_changes_since_last_save: - type: string - rdb_current_bgsave_time_sec: - type: string - rdb_last_bgsave_status: - type: string - rdb_last_bgsave_time_sec: - type: string - rdb_last_save_time: - type: string - redis_build_id: - type: string - redis_git_dirty: - type: string - redis_git_sha1: - type: string - redis_mode: - type: string - redis_version: - type: string - rejected_connections: - type: string - repl_backlog_active: - type: string - repl_backlog_first_byte_offset: - type: string - repl_backlog_histlen: - type: string - repl_backlog_size: - type: string - role: - type: string - run_id: - type: string - sync_full: - type: string - sync_partial_err: - type: string - sync_partial_ok: - type: string - tcp_port: - type: string - total_commands_processed: - type: string - total_connections_received: - type: string - uptime_in_days: - type: string - uptime_in_seconds: - type: string - used_cpu_sys: - type: string - used_cpu_sys_children: - type: string - used_cpu_user: - type: string - used_cpu_user_children: - type: string - used_memory: - type: string - used_memory_human: - type: string - used_memory_lua: - type: string - used_memory_peak: - type: string - used_memory_peak_human: - type: string - used_memory_rss: - type: string - keys: - type: string - expires: - type: string - avg_ttl: - type: string - instantaneous_input: - type: string - instantaneous_output: - type: string - total_net_input: - type: string - total_net_output: - type: string - raw: - type: string - redis: - type: boolean - mongo: - type: object - properties: - db: - type: string - collections: - type: number - objects: - type: number - avgObjSize: - type: string - dataSize: - type: string - storageSize: - type: string - numExtents: - type: number - indexes: - type: number - indexSize: - type: string - ok: - type: number - mem: - type: object - properties: - bits: - type: number - resident: - type: string - virtual: - type: string - supported: - type: boolean - mapped: - type: string - mappedWithJournal: - type: number - collectionData: - type: array - items: - type: object - properties: - name: - type: string - count: - type: number - size: - type: number - avgObjSize: - type: number - storageSize: - type: number - totalIndexSize: - type: number - indexSizes: - type: object - properties: - _id_: - type: number - expireAt_1: - type: number - _key_1_score_-1: - type: number - _key_1_value_-1: - type: number - content_text_uid_1_cid_1: - type: number - network: - type: object - properties: - bytesIn: - type: string - bytesOut: - type: string - numRequests: - type: string - raw: - type: string - fileSize: - type: number - storageEngine: - type: string - host: - type: string - version: - type: string - uptime: - type: number - mongo: - type: boolean - /api/admin/advanced/events: - get: - tags: - - admin - summary: Get event log - parameters: - - in: query - name: type - schema: - type: string - description: Event name to filter by - - in: query - name: start - schema: - type: string - description: Start date to filter by - - in: query - name: end - schema: - type: string - description: End date to filter by - - in: query - name: perPage - schema: - type: string - description: Limit the number of events returned per page - responses: - "200": - description: "A JSON object containing " + description: "A JSON object with database status information" + content: + application/json: + schema: + properties: {} + additionalProperties: + type: object + description: Each database configured will have an entry here with information about its runtime status + /api/admin/advanced/events: + get: + tags: + - admin + summary: Get event log + parameters: + - in: query + name: type + schema: + type: string + description: Event name to filter by + example: config-change + - in: query + name: start + schema: + type: string + description: Start date to filter by + example: '' + - in: query + name: end + schema: + type: string + description: End date to filter by + example: '' + - in: query + name: perPage + schema: + type: string + description: Limit the number of events returned per page + example: 20 + responses: + "200": + description: "A JSON object containing " content: application/json: schema: @@ -2476,8 +2022,8 @@ paths: properties: type: type: string - additionalProperties: - description: Each individual event as added by core/plugins can append their own metadata related to the event + additionalProperties: + description: Each individual event as added by core/plugins can append their own metadata related to the event - $ref: components/schemas/Pagination.yaml#/Pagination - type: object properties: @@ -2633,10 +2179,11 @@ paths: type: number max: type: number + nullable: true itemCount: type: number percentFull: - type: string + type: number avgPostSize: type: number hits: @@ -2655,7 +2202,7 @@ paths: itemCount: type: number percentFull: - type: string + type: number hits: type: string misses: @@ -2672,7 +2219,7 @@ paths: itemCount: type: number percentFull: - type: string + type: number dump: type: boolean hits: @@ -2691,13 +2238,17 @@ paths: itemCount: type: number percentFull: - type: string + type: number hits: type: string misses: type: string hitRatio: type: string + required: + - postCache + - groupCache + - localCache - $ref: components/schemas/CommonProps.yaml#/CommonProps /api/admin/development/logger: get: @@ -2734,9 +2285,15 @@ paths: type: object properties: port: - type: array - items: - type: number + description: An array containing the port numbers configured to be used by NodeBB processes + oneOf: + - type: array + items: + oneOf: + - type: string + - type: number + - type: string + - type: number pid: type: number description: Process id @@ -2820,11 +2377,19 @@ paths: infoJSON: type: string description: "`info`, but stringified" + host: + type: string + description: Server hostname port: - type: array description: An array containing the port numbers configured to be used by NodeBB processes - items: - type: number + oneOf: + - type: array + items: + oneOf: + - type: string + - type: number + - type: string + - type: number nodeCount: type: number description: The number of NodeBB application processes currently running @@ -2842,6 +2407,13 @@ paths: tags: - admin summary: Get users export (.csv) + parameters: + - in: header + name: referer + schema: + type: string + required: true + example: /admin/manage/users responses: "200": description: "A CSV file containing all registered users" @@ -2862,16 +2434,19 @@ paths: type: string enum: [hours, days] description: Whether to display dashboard data segmented daily or hourly + example: days - in: query name: until schema: type: number description: A UNIX timestamp denoting the end of the analytics reporting period + example: '' - in: query name: count schema: type: number description: The number of entries to return (e.g. if `units` is `hourly`, and `count` is `24`, the result set will contain 24 hours' worth of analytics) + example: 20 responses: "200": description: "A JSON object containing analytics data" @@ -3299,6 +2874,8 @@ paths: type: string acpLang: type: string + openOutgoingLinksInNewTab: + type: boolean topicSearchEnabled: type: boolean hideSubCategories: @@ -3307,69 +2884,6 @@ paths: type: boolean enableQuickReply: type: boolean - markdown: - type: object - properties: - highlight: - type: number - highlightLinesLanguageList: - type: array - items: {} - theme: - type: string - question-and-answer: - type: object - properties: - defaultCid_13: - type: string - defaultCid_1: - type: string - defaultCid_5: - type: string - forceQuestions: - type: string - defaultCid_2: - type: string - defaultCid_6: - type: string - defaultCid_3: - type: string - defaultCid_15: - type: string - defaultCid_7: - type: string - defaultCid_10: - type: string - defaultCid_16: - type: string - defaultCid_21: - type: string - defaultCid_8: - type: string - defaultCid_4: - type: string - defaultCid_14: - type: string - defaultCid_17: - type: string - defaultCid_18: - type: string - defaultCid_19: - type: string - defaultCid_20: - type: string - defaultCid_22: - type: string - defaultCid_26: - type: string - composer-default: - type: object - properties: {} - sso-google: - type: object - properties: - style: - type: string /api/me: get: tags: @@ -3393,6 +2907,7 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "" @@ -3411,6 +2926,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -3429,6 +2945,7 @@ paths: required: true schema: type: string + example: 'test@example.org' responses: "200": description: "" @@ -3447,6 +2964,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "A CSV file containing a user's posts" @@ -3466,6 +2984,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: Successful export of user uploads @@ -3485,6 +3004,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "A CSV file containing the user profile" @@ -3504,6 +3024,7 @@ paths: required: true schema: type: number + example: 1 responses: "200": description: "A JSON object containing post data" @@ -3553,6 +3074,7 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "A JSON object containing topic data" @@ -3569,6 +3091,9 @@ paths: type: number mainPid: type: number + teaserPid: + type: number + nullable: true title: type: string slug: @@ -3612,6 +3137,7 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "A JSON object containing topic data" @@ -3684,7 +3210,7 @@ paths: - type: object properties: title: - description: The category title + description: The page title type: string categories: description: A collection of category data objects @@ -3696,7 +3222,8 @@ paths: properties: tagWhitelist: type: array - items: {} + items: + type: string unread-class: type: string children: @@ -3708,7 +3235,8 @@ paths: properties: tagWhitelist: type: array - items: {} + items: + type: string unread-class: type: string children: @@ -3722,7 +3250,8 @@ paths: properties: tagWhitelist: type: array - items: {} + items: + type: string unread-class: type: string posts: @@ -3864,207 +3393,6 @@ paths: type: string imageClass: type: string - topics: - type: array - items: - type: object - properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - teaserPid: - type: number - upvotes: - type: number - downvotes: - type: number - deleted: - type: number - locked: - type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: - type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true - imageClass: - nullable: true - type: string - bgColor: - type: string - color: - type: string - disabled: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - fullname: - type: string - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - picture: - nullable: true - type: string - signature: - nullable: true - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - banned_until_readable: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - thumb: - type: string - isQuestion: - nullable: true - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps "/api/categories/{cid}/moderators": @@ -4082,6 +3410,7 @@ paths: required: true schema: type: number + example: 1 responses: "200": description: An array of moderators for the requested category @@ -4108,6 +3437,7 @@ paths: required: true schema: type: string + example: day responses: "200": description: "" @@ -4138,6 +3468,7 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "A JSON object containing the teaser post for a topic" @@ -4156,74 +3487,14 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "" content: application/json: schema: - type: object - properties: - rel: - type: array - items: - type: object - properties: - rel: - type: string - href: - type: string - pages: - type: array - items: - type: object - properties: - page: - type: number - active: - type: boolean - qs: - type: string - currentPage: - type: number - pageCount: - type: number - prev: - type: object - properties: - page: - type: number - active: - type: boolean - qs: - type: string - next: - type: object - properties: - page: - type: number - active: - type: boolean - qs: - type: string - first: - type: object - properties: - page: - type: number - active: - type: boolean - qs: - type: string - last: - type: object - properties: - page: - type: number - active: - type: boolean - qs: - type: string + $ref: components/schemas/Pagination.yaml#/Pagination /api/post/upload: post: tags: @@ -4335,7 +3606,18 @@ paths: properties: loginFormEntry: type: array - items: {} + items: + type: object + properties: + label: + type: string + description: A label for the added block + html: + type: string + description: HTML to render on the login page + styleName: + type: string + description: Custom identifier (value is added to `input[id]` and `label[for]`) alternate_logins: type: boolean authentication: @@ -4425,30 +3707,30 @@ paths: type: string - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/register/complete: - get: - tags: - - authentication - summary: /api/register/complete - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - title: - type: string - errors: - type: array - items: {} - sections: - type: array - items: - type: string - - $ref: components/schemas/CommonProps.yaml#/CommonProps + # /api/register/complete: + # get: + # tags: + # - authentication + # summary: /api/register/complete + # responses: + # "200": + # description: "" + # content: + # application/json: + # schema: + # allOf: + # - type: object + # properties: + # title: + # type: string + # errors: + # type: array + # items: {} + # sections: + # type: array + # items: + # type: string + # - $ref: components/schemas/CommonProps.yaml#/CommonProps /api/search: get: tags: @@ -4500,6 +3782,20 @@ paths: type: string searchDefaultSortBy: type: string + required: + - posts + - matchCount + - pageCount + - time + - multiplePages + - search_query + - categories + - categoriesCount + - expandSearch + - showAsPosts + - showAsTopics + - title + - searchDefaultSortBy - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps @@ -4519,6 +3815,9 @@ paths: properties: code: type: string + nullable: true + title: + type: string - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps "/api/reset/{code}": @@ -4532,6 +3831,7 @@ paths: required: true schema: type: string + example: testCode responses: "200": description: "A JSON object containing the 2nd step of the user password reset flow" @@ -4549,10 +3849,13 @@ paths: type: number minimumPasswordStrength: type: number + title: + type: string - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps "/api/email/unsubscribe/{token}": - get: + # TODO: Need GET route here as well + post: tags: - emails summary: /api/email/unsubscribe/{token} @@ -4562,32 +3865,36 @@ paths: required: true schema: type: string + example: testToken responses: "200": description: "Successfully unsubscribed" "500": description: "Server-side error (likely token verification failure)" - "/api/topic/{topic_id}/{slug}/{post_index?}": + "/api/topic/{topic_id}/{slug}/{post_index}": get: tags: - topics - summary: /api/topic/{topic_id}/{slug}/{post_index?} + summary: /api/topic/{topic_id}/{slug}/{post_index} parameters: - name: topic_id in: path required: true schema: type: string + example: 1 - name: slug in: path required: true schema: type: string - - name: post_index? + example: test-topic + - name: post_index in: path required: true schema: type: string + example: 1 responses: "200": description: "" @@ -4595,7 +3902,6 @@ paths: application/json: schema: allOf: - - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - type: object properties: tid: @@ -4607,10 +3913,6 @@ paths: cid: type: number description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") title: type: string slug: @@ -4623,8 +3925,13 @@ paths: type: number viewcount: type: number + mainPid: + type: number + description: The post id of the first post in this topic (also called the + "original post") teaserPid: type: number + nullable: true upvotes: type: number downvotes: @@ -4637,6 +3944,8 @@ paths: type: number description: Whether or not this particular topic is pinned to the top of the category + deleterUid: + type: number titleRaw: type: string timestampISO: @@ -4718,6 +4027,7 @@ paths: type: number picture: type: string + nullable: true signature: type: string banned: @@ -4772,7 +4082,12 @@ paths: type: string custom_profile_info: type: array - items: {} + items: + type: object + properties: + content: + type: string + description: HTML that is injected into `topic.tpl` of themes that support custom profile info editor: nullable: true bookmarked: @@ -4788,7 +4103,35 @@ paths: type: boolean users: type: array - items: {} + items: + type: object + properties: + username: + type: string + description: A friendly name for a given user account + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + type: string + uid: + type: number + description: A user identifier + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + administrator: + type: boolean text: type: string count: @@ -4805,9 +4148,12 @@ paths: type: boolean display_post_menu: type: boolean + category: + $ref: components/schemas/CategoryObject.yaml#/CategoryObject tagWhitelist: type: array - items: {} + items: + type: string thread_tools: type: array items: @@ -4846,12 +4192,15 @@ paths: nullable: true related: type: array - items: {} + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject unreplied: type: boolean icons: type: array - items: {} + items: + type: string + description: HTML that is rendered by the theme privileges: type: object properties: @@ -4902,6 +4251,8 @@ paths: type: number bookmarkThreshold: type: number + necroThreshold: + type: number postEditDuration: type: number postDeleteDuration: @@ -4916,1636 +4267,97 @@ paths: type: string postIndex: type: number + loggedInUser: + $ref: components/schemas/UserObject.yaml#/UserObject - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/topic/{topic_id}/{slug?}": + "/api/topic/{topic_id}/{slug}": get: tags: - topics - summary: /api/topic/{topic_id}/{slug?} + summary: /api/topic/{topic_id}/{slug} parameters: - name: topic_id in: path required: true schema: type: string - - name: slug? + example: 1 + - name: slug + in: path + required: true + schema: + type: string + example: '' + responses: + "418": + description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from the route w/o post_index" + "/api/post/{pid}": + get: + tags: + - shorthand + summary: Access a specific post + description: This route comes in handy when all you have is the `pid`, and you want to redirect users to the canonical URL for the topic, with the appropriate topic slug and post index. + parameters: + - name: pid in: path required: true schema: type: string + example: 1 responses: "200": - description: "" - content: - application/json: - schema: - allOf: - - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - - type: object - properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - teaserPid: - type: number - upvotes: - type: number - downvotes: - type: number - deleted: - type: number - locked: - type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - posts: - type: array - items: - type: object - properties: - editor: - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - nullable: true - type: object - votes: - type: number - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - pid: - type: number - edited: - type: number - uid: - type: number - description: A user identifier - upvotes: - type: number - bookmarks: - type: number - replies: - type: object - properties: - hasMore: - type: boolean - users: - type: array - items: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - administrator: - type: boolean - text: - type: string - count: - type: number - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - deleted: - type: number - downvotes: - type: number - deleterUid: - type: number - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - editedISO: - type: string - index: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - fullname: - type: string - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - topiccount: - type: number - picture: - nullable: true - type: string - signature: - type: string - banned: - type: number - banned:expire: - type: number - status: - type: string - lastonline: - type: number - groupTitle: - nullable: true - type: string - groupTitleArray: - type: array - items: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - lastonlineISO: - type: string - banned_until: - type: number - banned_until_readable: - type: string - selectedGroups: - type: array - items: - type: object - properties: - name: - type: string - slug: - type: string - labelColor: - type: string - textColor: - type: string - icon: - type: string - userTitle: - type: string - custom_profile_info: - type: array - items: {} - bookmarked: - type: boolean - upvoted: - type: boolean - downvoted: - type: boolean - selfPost: - type: boolean - display_edit_tools: - type: boolean - display_delete_tools: - type: boolean - display_moderator_tools: - type: boolean - display_move_tools: - type: boolean - display_post_menu: - type: boolean - toPid: - type: number - parent: - type: object - properties: - username: - type: string - description: A friendly name for a given user account - tagWhitelist: - type: array - items: {} - thread_tools: - type: array - items: - type: object - properties: - class: - type: string - title: - type: string - icon: - type: string - isFollowing: - type: boolean - isNotFollowing: - type: boolean - isIgnoring: - type: boolean - bookmark: - nullable: true - postSharing: - type: array - items: - type: object - properties: - id: - type: string - name: - type: string - class: - type: string - activated: - type: boolean - deleter: - nullable: true - merger: - nullable: true - related: - type: array - items: {} - unreplied: - type: boolean - icons: - type: array - items: {} - privileges: - type: object - properties: - topics:reply: - type: boolean - topics:read: - type: boolean - topics:tag: - type: boolean - topics:delete: - type: boolean - posts:edit: - type: boolean - posts:history: - type: boolean - posts:delete: - type: boolean - posts:view_deleted: - type: boolean - read: - type: boolean - purge: - type: boolean - view_thread_tools: - type: boolean - editable: - type: boolean - deletable: - type: boolean - view_deleted: - type: boolean - isAdminOrMod: - type: boolean - disabled: - type: number - tid: - type: string - uid: - type: number - description: A user identifier - topicStaleDays: - type: number - reputation:disabled: - type: number - downvote:disabled: - type: number - feeds:disableRSS: - type: number - bookmarkThreshold: - type: number - postEditDuration: - type: number - postDeleteDuration: - type: number - scrollToMyPost: - type: boolean - allowMultipleBadges: - type: boolean - privateUploads: - type: boolean - rssFeedUrl: - type: string - postIndex: - type: number - loggedInUser: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - picture: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without an - avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with `icon:text` for - the user's auto-generated icon - example: "#f44336" - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/post/{pid}": - get: - tags: - - shorthand - summary: Access a specific post - description: This route comes in handy when all you have is the `pid`, and you want to redirect users to the canonical URL for the topic, with the appropriate topic slug and post index. - parameters: - - name: pid - in: path - required: true - schema: - type: string - responses: - "200": - description: "Canonical URL of topic" - content: - text/plain: - schema: - type: string - /api/flags: - get: - tags: - - flags - summary: /api/flags - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - flags: - type: array - items: - type: object - properties: - state: - type: string - flagId: - type: number - type: - type: string - targetId: - oneOf: - - type: string - - type: number - description: - type: string - uid: - type: number - description: A user identifier - datetime: - type: number - reporter: - type: object - properties: - username: - type: string - description: A friendly name for a given user account - picture: - nullable: true - type: string - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - labelClass: - type: string - target_readable: - type: string - datetimeISO: - type: string - assignee: - type: string - analytics: - type: array - items: - type: number - categories: - type: object - properties: - "1": - type: string - "2": - type: string - "3": - type: string - "4": - type: string - "5": - type: string - "6": - type: string - "7": - type: string - "10": - type: string - "13": - type: string - "14": - type: string - "15": - type: string - "16": - type: string - "17": - type: string - "18": - type: string - "19": - type: string - "21": - type: string - "22": - type: string - "26": - type: string - hasFilter: - type: boolean - filters: - type: object - properties: - page: - type: number - perPage: - type: number - title: - type: string - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/flags/{flagId}": - get: - tags: - - flags - summary: /api/flags/{flagId} - parameters: - - name: flagId - in: path - required: true - schema: - type: string - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - state: - type: string - flagId: - type: number - type: - type: string - targetId: - type: string - description: - type: string - uid: - type: number - description: A user identifier - datetime: - type: number - datetimeISO: - type: string - target_readable: - type: string - target: - type: object - properties: {} - history: - type: array - items: - type: object - properties: - uid: - type: number - description: A user identifier - fields: - type: object - properties: - state: - type: string - datetime: - type: number - datetimeISO: - type: string - user: - type: object - properties: - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - uid: - type: number - description: A user identifier - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - notes: - type: array - items: {} - reporter: - type: object - properties: - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - reputation: - type: number - uid: - type: number - description: A user identifier - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without an - avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with `icon:text` for - the user's auto-generated icon - example: "#f44336" - type_path: - type: string - assignees: - type: array - items: - $ref: components/schemas/UserObject.yaml#/UserObject - type_bool: - type: object - properties: - post: - type: boolean - user: - type: boolean - empty: - type: boolean - title: - type: string - categories: - type: object - additionalProperties: - type: string - - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/post-queue: - get: - tags: - - admin - summary: /api/post-queue - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - title: - type: string - posts: - type: array - items: - allOf: - - type: object - properties: - id: - type: string - uid: - type: number - description: A user identifier - type: - type: string - data: - type: object - properties: - title: - type: string - content: - type: string - thumb: - type: string - cid: - oneOf: - - type: number - - type: string - tags: - type: array - items: {} - uid: - type: number - description: A user identifier - req: - type: object - properties: - uid: - type: number - description: A user identifier - ip: - type: string - host: - type: string - protocol: - type: string - secure: - type: boolean - url: - type: string - path: - type: string - headers: - type: object - properties: - x-real-ip: - type: string - x-forwarded-for: - type: string - x-forwarded-proto: - type: string - host: - type: string - x-nginx-proxy: - type: string - connection: - type: string - accept: - type: string - user-agent: - type: string - sec-fetch-site: - type: string - sec-fetch-mode: - type: string - referer: - type: string - accept-encoding: - type: string - accept-language: - type: string - cookie: - type: string - timestamp: - type: number - fromQueue: - type: boolean - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - rawContent: - type: string - tid: - type: number - description: A topic identifier - toPid: - nullable: true - user: - type: object - properties: - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - uid: - type: number - description: A user identifier - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - topic: - type: object - properties: - cid: - type: number - title: - type: string - titleRaw: - type: string - - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/ip-blacklist: - get: - tags: - - admin - summary: /api/ip-blacklist - responses: - "418": - description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route" - /api/registration-queue: - get: - tags: - - admin - summary: /api/registration-queue - responses: - "418": - description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route" - "/api/tags/{tag}": - get: - tags: - - tags - summary: /api/tags/{tag} - description: Returns a list of topics that are tagged with {tag} - parameters: - - name: tag - description: The tag used to retrieve the topics - in: path - required: true - schema: - type: string - - name: page - description: Page number used in pagination - in: query - required: false - schema: - type: number - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - topics: - type: array - description: An array of topics that are all tagged with {tag} - items: - type: object - properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - teaserPid: - oneOf: - - type: number - - type: string - deleted: - type: number - locked: - type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - upvotes: - type: number - downvotes: - type: number - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: - type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true - imageClass: - nullable: true - type: string - bgColor: - type: string - color: - type: string - disabled: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - picture: - nullable: true - type: string - signature: - nullable: true - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - banned_until_readable: - type: string - fullname: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - thumb: - type: string - isQuestion: - nullable: true - type: number - isSolved: - type: number - tag: - type: string - title: - type: string - categories: - type: array - items: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - level: - type: string - icon: - type: string - parentCid: - type: number - description: The category identifier for the category that is the immediate - ancestor of the current category - color: - type: string - bgColor: - type: string - selected: - type: boolean - imageClass: - type: string - rssFeedUrl: - type: string - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/tags: - get: - tags: - - tags - summary: /api/tags - description: Returns a list of tags sorted by the most topics - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - type: object - properties: - tags: - type: array - description: An array of tags sorted by the most topics - items: - type: object - properties: - value: - type: string - description: The raw tag - score: - type: number - description: Number of topics tagged by this tag - valueEscaped: - type: string - description: This is the escaped tag value, equal to validator.escape(value) - color: - type: string - bgColor: - type: string - displayTagSearch: - type: boolean - nextStart: - type: number - title: - type: string - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/popular: - get: - tags: - - topics - summary: Popular Topics - description: Returns a list of topics sorted by most replies. In an event of a - tie breaker, the topic with the most views. Can be filtered by All Time, - Day, Week, or Month. - responses: - "200": - description: An array of topic objects sorted by most replies and views. - content: - application/json: - schema: - allOf: - - type: object - properties: - nextStart: - type: number - topicCount: - type: number - topics: - type: array - items: - type: object - properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - thumb: - type: string - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - teaserPid: - oneOf: - - type: number - - type: string - upvotes: - type: number - downvotes: - type: number - deleted: - type: number - locked: - type: number - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: - type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true - imageClass: - nullable: true - bgColor: - type: string - color: - type: string - disabled: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - fullname: - type: string - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - picture: - nullable: true - type: string - signature: - nullable: true - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - banned_until_readable: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - tids: - type: array - items: - type: number - canPost: - type: boolean - categories: - type: array - items: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - level: - type: string - icon: - type: string - parentCid: - type: number - description: The category identifier for the category that is the immediate - ancestor of the current category - color: - type: string - bgColor: - type: string - selected: - type: boolean - imageClass: - type: string - allCategoriesUrl: - type: string - selectedCids: - type: array - items: {} - feeds:disableRSS: - type: number - rssFeedUrl: - type: string - title: - type: string - filters: - type: array - items: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - filter: - type: string - selectedFilter: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - filter: - type: string - terms: - type: array - items: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - term: - type: string - selectedTerm: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - term: - type: string - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/recent: + description: "Canonical URL of topic" + content: + text/plain: + schema: + type: string + /api/flags: get: tags: - - topics - summary: Recent Topics - description: Returns a list of topics sorted by timestamp. + - flags + summary: /api/flags responses: "200": - description: An array of topic objects sorted by timestamp. + description: "" content: application/json: schema: allOf: - type: object properties: - nextStart: - type: number - topicCount: - type: number - topics: + flags: type: array items: type: object properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - title: - type: string - slug: + state: type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - teaserPid: - type: number - upvotes: - type: number - downvotes: - type: number - deleted: - type: number - locked: - type: number - pinned: + flagId: type: number - description: Whether or not this particular topic is pinned to the top of the - category - titleRaw: - type: string - timestampISO: + type: type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: + targetId: + oneOf: + - type: string + - type: number + description: type: string - votes: + uid: type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true - imageClass: - nullable: true - type: string - bgColor: - type: string - color: - type: string - disabled: - type: number - user: + description: A user identifier + datetime: + type: number + reporter: type: object properties: - uid: - type: number - description: A user identifier username: type: string description: A friendly name for a given user account - fullname: - type: string - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number picture: nullable: true type: string - signature: - nullable: true - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar icon:bgColor: type: string description: A six-character hexadecimal colour code assigned to the user. This @@ -6553,284 +4365,151 @@ paths: `icon:text` for the user's auto-generated icon example: "#f44336" - banned_until_readable: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: + icon:text: type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - thumb: - type: string - isQuestion: - nullable: true - tids: - type: array - items: - type: number - canPost: - type: boolean - categories: - type: array - items: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - level: - type: string - icon: + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + labelClass: type: string - parentCid: - type: number - description: The category identifier for the category that is the immediate - ancestor of the current category - color: + target_readable: type: string - bgColor: + datetimeISO: type: string - selected: - type: boolean - imageClass: + assignee: type: string - allCategoriesUrl: - type: string - selectedCids: - type: array - items: {} - feeds:disableRSS: - type: number - rssFeedUrl: - type: string - title: - type: string - filters: + nullable: true + analytics: type: array items: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - filter: - type: string - selectedFilter: + type: number + categories: type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - filter: - type: string - terms: - type: array - items: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - term: - type: string - selectedTerm: + properties: {} + additionalProperties: + type: string + description: All categories will be listed here, with the `cid` as the key, and the category name as the value + hasFilter: + type: boolean + filters: type: object properties: - name: - type: string - url: - type: string - selected: - type: boolean - term: - type: string + page: + type: number + perPage: + type: number + title: + type: string - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/top: + "/api/flags/{flagId}": get: tags: - - topics - summary: Top Topics - description: Returns a list of topics sorted by most upvotes. + - flags + summary: /api/flags/{flagId} + parameters: + - name: flagId + in: path + required: true + schema: + type: string + example: 1 responses: "200": - description: An array of topic objects sorted by most upvotes. + description: "" content: application/json: schema: allOf: - type: object properties: - nextStart: + state: + type: string + flagId: type: number - topicCount: + type: + type: string + targetId: type: number - topics: + description: + type: string + uid: + type: number + description: A user identifier + datetime: + type: number + datetimeISO: + type: string + target_readable: + type: string + target: + type: object + properties: {} + additionalProperties: + description: Properties change depending on the target type (user, post, etc.) + assignee: + type: number + nullable: true + history: type: array items: type: object properties: - tid: - type: number - description: A topic identifier uid: type: number description: A user identifier - cid: - type: number - description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - teaserPid: - type: string - upvotes: - type: number - downvotes: - type: number - deleted: - type: number - locked: - type: number - pinned: + fields: + type: object + properties: + state: + type: string + datetime: type: number - description: Whether or not this particular topic is pinned to the top of the - category - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: + datetimeISO: type: string - votes: - type: number - category: + user: type: object properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: + username: type: string - icon: + description: A friendly name for a given user account + userslug: type: string - image: - nullable: true - imageClass: + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: nullable: true - bgColor: + uid: + type: number + description: A user identifier + icon:text: type: string - color: + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: type: string - disabled: - type: number + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + notes: + type: array + items: + type: object + properties: + uid: + type: number + content: + type: string + datetime: + type: number + datetimeISO: + type: string user: type: object properties: - uid: - type: number - description: A user identifier username: type: string description: A friendly name for a given user account @@ -6838,20 +4517,11 @@ paths: type: string description: An URL-safe variant of the username (i.e. lower-cased, spaces removed, etc.) - reputation: - type: number - postcount: - type: number picture: - nullable: true - type: string - signature: - nullable: true type: string - banned: + uid: type: number - status: - type: string + description: A user identifier icon:text: type: string description: A single-letter representation of a username. This is used in the @@ -6864,34 +4534,170 @@ paths: `icon:text` for the user's auto-generated icon example: "#f44336" - banned_until_readable: - type: string - fullname: - type: string - teaser: - type: object + reporter: + type: object + properties: + username: + type: string + description: A friendly name for a given user account + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + reputation: + type: number + uid: + type: number + description: A user identifier + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without an + avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with `icon:text` for + the user's auto-generated icon + example: "#f44336" + type_path: + type: string + assignees: + type: array + items: + $ref: components/schemas/UserObject.yaml#/UserObject + type_bool: + type: object + properties: + post: + type: boolean + user: + type: boolean + empty: + type: boolean + title: + type: string + categories: + type: object + additionalProperties: + type: string + - $ref: components/schemas/CommonProps.yaml#/CommonProps + /api/post-queue: + get: + tags: + - admin + summary: /api/post-queue + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + title: + type: string + posts: + type: array + items: + allOf: + - type: object properties: - pid: - type: number + id: + type: string uid: type: number description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: + type: type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) + data: + type: object + properties: + title: + type: string + content: + type: string + thumb: + type: string + cid: + oneOf: + - type: number + - type: string + tags: + type: array + items: {} + uid: + type: number + description: A user identifier + req: + type: object + properties: + uid: + type: number + description: A user identifier + ip: + type: string + host: + type: string + protocol: + type: string + secure: + type: boolean + url: + type: string + path: + type: string + headers: + type: object + properties: + x-real-ip: + type: string + x-forwarded-for: + type: string + x-forwarded-proto: + type: string + host: + type: string + x-nginx-proxy: + type: string + connection: + type: string + accept: + type: string + user-agent: + type: string + sec-fetch-site: + type: string + sec-fetch-mode: + type: string + referer: + type: string + accept-encoding: + type: string + accept-language: + type: string + cookie: + type: string + timestamp: + type: number + fromQueue: + type: boolean + timestampISO: + type: string + description: An ISO 8601 formatted date string (complementing `timestamp`) + rawContent: + type: string + tid: + type: number + description: A topic identifier + toPid: + nullable: true user: type: object properties: - uid: - type: number - description: A user identifier username: type: string description: A friendly name for a given user account @@ -6902,191 +4708,82 @@ paths: picture: nullable: true type: string + uid: + type: number + description: A user identifier icon:text: type: string description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar + auto-generated icon given to users without + an avatar icon:bgColor: type: string description: A six-character hexadecimal colour code assigned to the user. This value is used in conjunction with - `icon:text` for the user's - auto-generated icon + `icon:text` for the user's auto-generated + icon example: "#f44336" - index: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - thumb: - type: string - tids: - type: array - items: - type: number - canPost: - type: boolean - categories: - type: array - items: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - level: - type: string - icon: - type: string - parentCid: - type: number - description: The category identifier for the category that is the immediate - ancestor of the current category - color: - type: string - bgColor: - type: string - selected: - type: boolean - imageClass: - type: string - allCategoriesUrl: - type: string - selectedCategory: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - level: - type: string - icon: - type: string - parentCid: - type: number - description: The category identifier for the category that is the immediate - ancestor of the current category - color: - type: string - bgColor: - type: string - selected: - type: boolean - selectedCids: - type: array - items: - type: number - feeds:disableRSS: - type: number - rssFeedUrl: - type: string - title: - type: string - filters: - type: array - items: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - filter: - type: string - selectedFilter: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - filter: - type: string - terms: - type: array - items: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - term: - type: string - selectedTerm: - type: object - properties: - name: - type: string - url: - type: string - selected: - type: boolean - term: - type: string + topic: + type: object + properties: + cid: + type: number + title: + type: string + titleRaw: + type: string + - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - /api/unread: + /api/ip-blacklist: get: tags: - - topics - summary: Unread Topics - description: Returns a list of the current user's unread topics, sorted by the - last post's timestamp. + - admin + summary: /api/ip-blacklist + responses: + "418": + description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route" + /api/registration-queue: + get: + tags: + - admin + summary: /api/registration-queue + responses: + "418": + description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from corresponding admin route" + "/api/tags/{tag}": + get: + tags: + - tags + summary: /api/tags/{tag} + description: Returns a list of topics that are tagged with {tag} + parameters: + - name: tag + description: The tag used to retrieve the topics + in: path + required: true + schema: + type: string + example: test + - name: page + description: Page number used in pagination + in: query + required: false + schema: + type: number + example: '' responses: "200": - description: An array of unread topic objects sorted by the last post's timestamp. + description: "" content: application/json: schema: allOf: - type: object properties: - showSelect: - type: boolean - nextStart: - type: number topics: type: array + description: An array of topics that are all tagged with {tag} items: type: object properties: @@ -7111,16 +4808,14 @@ paths: type: number lastposttime: type: number - postcount: - type: number - viewcount: - type: number - teaserPid: - type: number - upvotes: + postcount: type: number - downvotes: + viewcount: type: number + teaserPid: + oneOf: + - type: number + - type: string deleted: type: number locked: @@ -7129,6 +4824,10 @@ paths: type: number description: Whether or not this particular topic is pinned to the top of the category + upvotes: + type: number + downvotes: + type: number titleRaw: type: string timestampISO: @@ -7170,8 +4869,6 @@ paths: username: type: string description: A friendly name for a given user account - fullname: - type: string userslug: type: string description: An URL-safe variant of the username (i.e. lower-cased, spaces @@ -7204,6 +4901,8 @@ paths: example: "#f44336" banned_until_readable: type: string + fullname: + type: string teaser: type: object properties: @@ -7282,14 +4981,254 @@ paths: items: {} index: type: number + thumb: + type: string isQuestion: nullable: true + type: number + isSolved: + type: number + tag: + type: string + title: + type: string + categories: + type: array + items: + type: object + properties: + cid: + type: number + description: A category identifier + name: + type: string + level: + type: string + icon: + type: string + parentCid: + type: number + description: The category identifier for the category that is the immediate + ancestor of the current category + color: + type: string + bgColor: + type: string + selected: + type: boolean + imageClass: + type: string + rssFeedUrl: + type: string + required: + - topics + - tag + - title + - categories + - $ref: components/schemas/Pagination.yaml#/Pagination + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + /api/tags: + get: + tags: + - tags + summary: /api/tags + description: Returns a list of tags sorted by the most topics + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - type: object + properties: + tags: + type: array + description: An array of tags sorted by the most topics + items: + type: object + properties: + value: + type: string + description: The raw tag + score: + type: number + description: Number of topics tagged by this tag + valueEscaped: + type: string + description: This is the escaped tag value, equal to validator.escape(value) + color: + type: string + bgColor: + type: string + displayTagSearch: + type: boolean + nextStart: + type: number + title: + type: string + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + /api/popular: + get: + tags: + - topics + summary: Get Popular Topics + description: Returns a list of topics sorted by most replies. In an event of a + tie breaker, the topic with the most views. Can be filtered by All Time, + Day, Week, or Month. + responses: + "200": + description: An array of topic objects sorted by most replies and views. + content: + application/json: + schema: + allOf: + - type: object + properties: + nextStart: + type: number topicCount: type: number + topics: + type: array + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject + tids: + type: array + items: + type: number + canPost: + type: boolean + categories: + type: array + items: + type: object + properties: + cid: + type: number + description: A category identifier + name: + type: string + level: + type: string + icon: + type: string + parentCid: + type: number + description: The category identifier for the category that is the immediate + ancestor of the current category + color: + type: string + bgColor: + type: string + selected: + type: boolean + imageClass: + type: string + allCategoriesUrl: + type: string + selectedCategory: + type: object + properties: + icon: + type: string + name: + type: string + bgColor: + type: string + nullable: true + selectedCids: + type: array + items: + type: number + feeds:disableRSS: + type: number + rssFeedUrl: + type: string title: type: string - pageCount: + filters: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + filter: + type: string + selectedFilter: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + filter: + type: string + terms: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + term: + type: string + selectedTerm: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + term: + type: string + - $ref: components/schemas/Pagination.yaml#/Pagination + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + /api/recent: + get: + tags: + - topics + summary: Recent Topics + description: Returns a list of topics sorted by timestamp. + responses: + "200": + description: An array of topic objects sorted by timestamp. + content: + application/json: + schema: + allOf: + - type: object + properties: + nextStart: + type: number + topicCount: type: number + topics: + type: array + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject + tids: + type: array + items: + type: number + canPost: + type: boolean categories: type: array items: @@ -7318,9 +5257,26 @@ paths: type: string allCategoriesUrl: type: string + selectedCategory: + type: object + properties: + icon: + type: string + name: + type: string + bgColor: + type: string + nullable: true selectedCids: type: array - items: {} + items: + type: number + feeds:disableRSS: + type: number + rssFeedUrl: + type: string + title: + type: string filters: type: array items: @@ -7345,313 +5301,194 @@ paths: type: boolean filter: type: string + terms: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + term: + type: string + selectedTerm: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + term: + type: string - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/category/{category_id}/{slug}/{topic_index}": + /api/top: get: tags: - - categories - summary: /api/category/{category_id}/{slug}/{topic_index} - parameters: - - name: category_id - in: path - required: true - schema: - type: string - - name: slug - in: path - required: true - schema: - type: string - - name: topic_index - in: path - required: true - schema: - type: string + - topics + summary: Top Topics + description: Returns a list of topics sorted by most upvotes. responses: "200": - description: "" + description: An array of topic objects sorted by most upvotes. content: application/json: schema: allOf: - - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - type: object properties: - tagWhitelist: - type: array - items: {} - unread-class: - type: string - children: - type: array - items: - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - topics: - type: array - items: - type: object - properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - thumb: - type: string - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - upvotes: - type: number - downvotes: - type: number - deleted: - type: number - locked: - type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: - type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true - imageClass: - nullable: true - bgColor: - type: string - color: - type: string - disabled: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - picture: - nullable: true - type: string - signature: - nullable: true - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - banned_until_readable: - type: string - fullname: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: {} - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - teaserPid: - type: number nextStart: type: number - isWatched: - type: boolean - isNotWatched: - type: boolean - isIgnored: + topicCount: + type: number + topics: + type: array + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject + tids: + type: array + items: + type: number + canPost: type: boolean - title: + categories: + type: array + items: + type: object + properties: + cid: + type: number + description: A category identifier + name: + type: string + level: + type: string + icon: + type: string + parentCid: + type: number + description: The category identifier for the category that is the immediate + ancestor of the current category + color: + type: string + bgColor: + type: string + selected: + type: boolean + imageClass: + type: string + allCategoriesUrl: type: string - privileges: + selectedCategory: type: object properties: - topics:create: - type: boolean - topics:read: - type: boolean - topics:tag: - type: boolean - read: - type: boolean cid: + type: number + description: A category identifier + name: type: string - uid: + level: + type: string + icon: + type: string + parentCid: type: number - description: A user identifier - editable: - type: boolean - view_deleted: - type: boolean - isAdminOrMod: + description: The category identifier for the category that is the immediate + ancestor of the current category + color: + type: string + bgColor: + type: string + selected: type: boolean - showSelect: - type: boolean - rssFeedUrl: - type: string + nullable: true + selectedCids: + type: array + items: + type: number feeds:disableRSS: type: number - reputation:disabled: - type: number + rssFeedUrl: + type: string + title: + type: string + filters: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + filter: + type: string + selectedFilter: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + filter: + type: string + terms: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + term: + type: string + selectedTerm: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + term: + type: string - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/category/{category_id}/{slug?}": + /api/unread: get: tags: - - categories - summary: /api/category/{category_id}/{slug?} - parameters: - - name: category_id - in: path - required: true - schema: - type: string - - name: slug? - in: path - required: true - schema: - type: string + - topics + summary: Unread Topics + description: Returns a list of the current user's unread topics, sorted by the + last post's timestamp. responses: "200": - description: "" + description: An array of unread topic objects sorted by the last post's timestamp. content: application/json: schema: allOf: - - $ref: components/schemas/CategoryObject.yaml#/CategoryObject - type: object properties: - tagWhitelist: - type: array - items: {} - unread-class: - type: string - children: - type: array - items: - $ref: components/schemas/CategoryObject.yaml#/CategoryObject + showSelect: + type: boolean + nextStart: + type: number topics: type: array items: @@ -7666,6 +5503,10 @@ paths: cid: type: number description: A category identifier + mainPid: + type: number + description: The post id of the first post in this topic (also called the + "original post") title: type: string slug: @@ -7678,16 +5519,6 @@ paths: type: number viewcount: type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - thumb: - type: string - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") teaserPid: type: number upvotes: @@ -7698,6 +5529,10 @@ paths: type: number locked: type: number + pinned: + type: number + description: Whether or not this particular topic is pinned to the top of the + category titleRaw: type: string timestampISO: @@ -7723,6 +5558,7 @@ paths: nullable: true imageClass: nullable: true + type: string bgColor: type: string color: @@ -7847,13 +5683,125 @@ paths: type: boolean icons: type: array - items: {} + items: + type: string index: type: number isQuestion: + nullable: true + topicCount: + type: number + title: + type: string + pageCount: + type: number + categories: + type: array + items: + type: object + properties: + cid: type: number - isSolved: + description: A category identifier + name: + type: string + level: + type: string + icon: + type: string + parentCid: type: number + description: The category identifier for the category that is the immediate + ancestor of the current category + color: + type: string + bgColor: + type: string + selected: + type: boolean + imageClass: + type: string + allCategoriesUrl: + type: string + selectedCids: + type: array + items: + type: number + filters: + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + filter: + type: string + selectedFilter: + type: object + properties: + name: + type: string + url: + type: string + selected: + type: boolean + filter: + type: string + - $ref: components/schemas/Pagination.yaml#/Pagination + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + "/api/category/{category_id}/{slug}/{topic_index}": + get: + tags: + - categories + summary: /api/category/{category_id}/{slug}/{topic_index} + parameters: + - name: category_id + in: path + required: true + schema: + type: string + example: 1 + - name: slug + in: path + required: true + schema: + type: string + example: test + - name: topic_index + in: path + required: true + schema: + type: string + example: 1 + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - $ref: components/schemas/CategoryObject.yaml#/CategoryObject + - type: object + properties: + tagWhitelist: + type: array + items: + type: string + unread-class: + type: string + children: + type: array + items: + $ref: components/schemas/CategoryObject.yaml#/CategoryObject + topics: + type: array + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject nextStart: type: number isWatched: @@ -7897,6 +5845,27 @@ paths: - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps + "/api/category/{category_id}/{slug?}": + get: + tags: + - categories + summary: /api/category/{category_id}/{slug} + parameters: + - name: category_id + in: path + required: true + schema: + type: string + example: 1 + - name: slug + in: path + required: true + schema: + type: string + example: test + responses: + "418": + description: "TODO: A proper response needs to be added. It is not really a teapot | Copy response from indexed variant" /api/me/*: get: tags: @@ -7924,6 +5893,7 @@ paths: required: true schema: type: string + example: 1 responses: "200": description: "Canonical URL of user profile page" @@ -7938,6 +5908,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -8024,10 +5995,12 @@ paths: required: true schema: type: string + example: admin - name: page in: query schema: type: number + example: '' responses: "200": description: "" @@ -8101,215 +6074,25 @@ paths: administrator: type: boolean - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/user/{userslug}/followers": - get: - tags: - - users - summary: Get followers - parameters: - - name: userslug - in: path - required: true - schema: - type: string - - name: page - in: query - schema: - type: number - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - $ref: components/schemas/UserObject.yaml#/UserObjectFull - - type: object - properties: - title: - type: string - users: - type: array - items: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - status: - type: string - postcount: - type: number - reputation: - type: number - email:confirmed: - type: number - description: Whether the user has confirmed their email address or not - lastonline: - type: number - flags: - nullable: true - banned: - type: number - banned:expire: - type: number - joindate: - type: number - description: A UNIX timestamp representing the moment the user's account was - created - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without an - avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with `icon:text` - for the user's auto-generated icon - example: "#f44336" - joindateISO: - type: string - lastonlineISO: - type: string - banned_until: - type: number - banned_until_readable: - type: string - administrator: - type: boolean - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/user/{userslug}/categories": - get: - tags: - - users - summary: /api/user/{userslug}/categories - parameters: - - name: userslug - in: path - required: true - schema: - type: string - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - $ref: components/schemas/UserObject.yaml#/UserObjectFull - - type: object - properties: - categories: - type: array - items: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - level: - type: string - icon: - type: string - parentCid: - type: number - description: The category identifier for the category that is the immediate - ancestor of the current category - color: - type: string - bgColor: - type: string - descriptionParsed: - type: string - depth: - type: number - slug: - type: string - isIgnored: - type: boolean - isWatched: - type: boolean - isNotWatched: - type: boolean - imageClass: - type: string - title: - type: string - - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/user/{userslug}/posts": - get: - tags: - - users - summary: /api/user/{userslug}/posts - parameters: - - name: userslug - in: path - required: true - schema: - type: string - responses: - "200": - description: "" - content: - application/json: - schema: - allOf: - - $ref: components/schemas/UserObject.yaml#/UserObjectFull - - type: object - properties: - posts: - type: array - items: {} - nextStart: - type: number - noItemsFoundKey: - type: string - title: - type: string - showSort: - type: boolean - sortOptions: - type: array - items: - type: object - properties: - url: - type: string - name: - type: string - selected: - type: boolean - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/user/{userslug}/topics": + "/api/user/{userslug}/followers": get: tags: - users - summary: /api/user/{userslug}/topics + summary: Get followers parameters: - name: userslug in: path required: true schema: type: string + example: admin + - name: page + in: query + schema: + type: number + example: '' responses: "200": description: "" @@ -8317,295 +6100,147 @@ paths: application/json: schema: allOf: - - $ref: components/schemas/UserObject.yaml#/UserObject + - $ref: components/schemas/UserObject.yaml#/UserObjectFull - type: object properties: - age: - type: number - emailClass: - type: string - moderationNote: - type: string - isBlocked: - type: boolean - yourid: - type: number - theirid: - type: number - isTargetAdmin: - type: boolean - isAdmin: - type: boolean - isGlobalModerator: - type: boolean - isModerator: - type: boolean - isAdminOrGlobalModerator: - type: boolean - isAdminOrGlobalModeratorOrModerator: - type: boolean - isSelfOrAdminOrGlobalModerator: - type: boolean - canEdit: - type: boolean - canBan: - type: boolean - canChangePassword: - type: boolean - isSelf: - type: boolean - isFollowing: - type: boolean - showHidden: - type: boolean - groups: - type: array - items: {} - disableSignatures: - type: boolean - reputation:disabled: - type: boolean - downvote:disabled: - type: boolean - profile_links: - type: array - items: {} - sso: - type: array - items: - type: object - properties: - associated: - type: boolean - url: - type: string - name: - type: string - icon: - type: string - websiteLink: - type: string - websiteName: + title: type: string - username:disableEdit: - type: number - email:disableEdit: - type: number - topics: + users: type: array items: type: object properties: - tid: - type: number - description: A topic identifier uid: type: number description: A user identifier - cid: - type: number - description: A category identifier - title: + username: type: string - slug: + description: A friendly name for a given user account + userslug: type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - thumb: + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true type: string - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - teaserPid: - type: number - upvotes: - type: number - downvotes: - type: number - deleted: + status: + type: string + postcount: type: number - locked: + reputation: type: number - pinned: + email:confirmed: type: number - description: Whether or not this particular topic is pinned to the top of the - category - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: + description: Whether the user has confirmed their email address or not + lastonline: type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true - imageClass: - nullable: true - bgColor: - type: string - color: - type: string - disabled: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - picture: - nullable: true - signature: - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - banned_until_readable: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: {} - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: + flags: nullable: true - unreplied: - type: boolean - icons: - type: array - items: {} - index: + banned: type: number - nextStart: - type: number - noItemsFoundKey: - type: string - title: - type: string - showSort: - type: boolean - sortOptions: + banned:expire: + type: number + joindate: + type: number + description: A UNIX timestamp representing the moment the user's account was + created + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without an + avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with `icon:text` + for the user's auto-generated icon + example: "#f44336" + joindateISO: + type: string + lastonlineISO: + type: string + banned_until: + type: number + banned_until_readable: + type: string + administrator: + type: boolean + - $ref: components/schemas/Pagination.yaml#/Pagination + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + "/api/user/{userslug}/categories": + get: + tags: + - users + summary: /api/user/{userslug}/categories + parameters: + - name: userslug + in: path + required: true + schema: + type: string + example: admin + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - $ref: components/schemas/UserObject.yaml#/UserObjectFull + - type: object + properties: + categories: type: array items: type: object properties: - url: - type: string + cid: + type: number + description: A category identifier name: type: string - selected: + level: + type: string + icon: + type: string + parentCid: + type: number + description: The category identifier for the category that is the immediate + ancestor of the current category + color: + type: string + bgColor: + type: string + descriptionParsed: + type: string + depth: + type: number + slug: + type: string + isIgnored: type: boolean - - $ref: components/schemas/Pagination.yaml#/Pagination - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + isWatched: + type: boolean + isNotWatched: + type: boolean + imageClass: + type: string + title: + type: string - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/user/{userslug}/best": + "/api/user/{userslug}/posts": get: tags: - users - summary: /api/user/{userslug}/best + summary: /api/user/{userslug}/posts parameters: - name: userslug in: path required: true schema: type: string + example: admin responses: "200": description: "" @@ -8640,17 +6275,18 @@ paths: - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/user/{userslug}/groups": + "/api/user/{userslug}/topics": get: tags: - users - summary: /api/user/{userslug}/groups + summary: /api/user/{userslug}/topics parameters: - name: userslug in: path required: true schema: type: string + example: admin responses: "200": description: "" @@ -8661,28 +6297,44 @@ paths: - $ref: components/schemas/UserObject.yaml#/UserObjectFull - type: object properties: + topics: + type: array + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject + nextStart: + type: number + noItemsFoundKey: + type: string title: type: string - template: - type: object - properties: - name: - type: string - account/groups: - type: boolean - "304": - description: "" - "/api/user/{userslug}/bookmarks": + showSort: + type: boolean + sortOptions: + type: array + items: + type: object + properties: + url: + type: string + name: + type: string + selected: + type: boolean + - $ref: components/schemas/Pagination.yaml#/Pagination + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + "/api/user/{userslug}/best": get: tags: - users - summary: /api/user/{userslug}/bookmarks + summary: /api/user/{userslug}/best parameters: - name: userslug in: path required: true schema: type: string + example: admin responses: "200": description: "" @@ -8690,116 +6342,90 @@ paths: application/json: schema: allOf: - - $ref: components/schemas/UserObject.yaml#/UserObject + - $ref: components/schemas/UserObject.yaml#/UserObjectFull - type: object properties: - age: + posts: + $ref: components/schemas/PostsObject.yaml#/PostsObject + nextStart: type: number - emailClass: + noItemsFoundKey: type: string - ips: - type: array - items: - type: string - moderationNote: + title: type: string - isBlocked: - type: boolean - blocksCount: - type: number - yourid: - type: number - theirid: - type: number - isTargetAdmin: - type: boolean - isAdmin: - type: boolean - isGlobalModerator: - type: boolean - isModerator: - type: boolean - isAdminOrGlobalModerator: - type: boolean - isAdminOrGlobalModeratorOrModerator: - type: boolean - isSelfOrAdminOrGlobalModerator: - type: boolean - canEdit: - type: boolean - canBan: - type: boolean - canChangePassword: - type: boolean - isSelf: - type: boolean - isFollowing: - type: boolean - showHidden: - type: boolean - groups: - type: array - items: {} - disableSignatures: - type: boolean - reputation:disabled: - type: boolean - downvote:disabled: + showSort: type: boolean - profile_links: - type: array - items: - type: object - properties: - id: - type: string - route: - type: string - name: - type: string - visibility: - type: object - properties: - self: - type: boolean - other: - type: boolean - moderator: - type: boolean - globalMod: - type: boolean - admin: - type: boolean - canViewInfo: - type: boolean - public: - type: boolean - icon: - type: string - sso: + sortOptions: type: array items: type: object properties: - associated: - type: boolean url: type: string name: type: string - icon: - type: string - websiteLink: - type: string - websiteName: + selected: + type: boolean + - $ref: components/schemas/Pagination.yaml#/Pagination + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + "/api/user/{userslug}/groups": + get: + tags: + - users + summary: /api/user/{userslug}/groups + parameters: + - name: userslug + in: path + required: true + schema: + type: string + example: admin + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - $ref: components/schemas/UserObject.yaml#/UserObjectFull + - type: object + properties: + title: type: string - username:disableEdit: - type: number - email:disableEdit: - type: number + template: + type: object + properties: + name: + type: string + account/groups: + type: boolean + - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs + - $ref: components/schemas/CommonProps.yaml#/CommonProps + "/api/user/{userslug}/bookmarks": + get: + tags: + - users + summary: /api/user/{userslug}/bookmarks + parameters: + - name: userslug + in: path + required: true + schema: + type: string + example: admin + responses: + "200": + description: "" + content: + application/json: + schema: + allOf: + - $ref: components/schemas/UserObject.yaml#/UserObjectFull + - type: object + properties: posts: - type: array - items: {} + $ref: components/schemas/PostsObject.yaml#/PostsObject nextStart: type: number noItemsFoundKey: @@ -8833,6 +6459,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9004,213 +6631,9 @@ paths: email:disableEdit: type: boolean topics: - type: array - items: - type: object - properties: - tid: - type: number - description: A topic identifier - uid: - type: number - description: A user identifier - cid: - type: number - description: A category identifier - mainPid: - type: number - description: The post id of the first post in this topic (also called the - "original post") - title: - type: string - slug: - type: string - timestamp: - type: number - lastposttime: - type: number - postcount: - type: number - viewcount: - type: number - teaserPid: - oneOf: - - type: number - - type: string - upvotes: - type: number - downvotes: - type: number - deleted: - type: number - locked: - type: number - pinned: - type: number - description: Whether or not this particular topic is pinned to the top of the - category - deleterUid: - type: number - titleRaw: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - lastposttimeISO: - type: string - votes: - type: number - category: - type: object - properties: - cid: - type: number - description: A category identifier - name: - type: string - slug: - type: string - icon: - type: string - image: - nullable: true - type: string - imageClass: - nullable: true - type: string - bgColor: - type: string - color: - type: string - disabled: - type: number - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - reputation: - type: number - postcount: - type: number - picture: - type: string - signature: - nullable: true - type: string - banned: - type: number - status: - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - banned_until_readable: - type: string - fullname: - type: string - teaser: - type: object - properties: - pid: - type: number - uid: - type: number - description: A user identifier - timestamp: - type: number - tid: - type: number - description: A topic identifier - content: - type: string - timestampISO: - type: string - description: An ISO 8601 formatted date string (complementing `timestamp`) - user: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - nullable: true - type: string - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users - without an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's - auto-generated icon - example: "#f44336" - index: - type: number - tags: - type: array - items: - type: object - properties: - value: - type: string - valueEscaped: - type: string - color: - type: string - bgColor: - type: string - score: - type: number - isOwner: - type: boolean - ignored: - type: boolean - unread: - type: boolean - bookmark: - nullable: true - type: number - unreplied: - type: boolean - icons: - type: array - items: {} - index: - type: number - thumb: - type: string - isQuestion: - type: number - isSolved: - type: number + type: array + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject nextStart: type: number noItemsFoundKey: @@ -9230,7 +6653,6 @@ paths: type: string selected: type: boolean - - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps @@ -9245,6 +6667,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9257,7 +6680,8 @@ paths: properties: topics: type: array - items: {} + items: + $ref: components/schemas/TopicObject.yaml#/TopicObject nextStart: type: number noItemsFoundKey: @@ -9291,6 +6715,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9310,6 +6735,24 @@ paths: description: Translation key for message notifying user that there were no posts found title: type: string + showSort: + type: boolean + sortOptions: + type: array + items: + type: object + properties: + url: + type: string + name: + type: string + selected: + type: boolean + required: + - posts + - nextStart + - noItemsFoundKey + - title - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps @@ -9324,6 +6767,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9343,6 +6787,24 @@ paths: description: Translation key for message notifying user that there were no posts found title: type: string + showSort: + type: boolean + sortOptions: + type: array + items: + type: object + properties: + url: + type: string + name: + type: string + selected: + type: boolean + required: + - posts + - nextStart + - noItemsFoundKey + - title - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps @@ -9357,6 +6819,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9401,7 +6864,15 @@ paths: type: string editButtons: type: array - items: {} + items: + type: object + properties: + link: + type: string + description: A relative path to the page linked to + text: + type: string + description: Button label - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps "/api/user/{userslug}/edit/username": @@ -9415,6 +6886,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9442,6 +6914,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9469,6 +6942,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9500,6 +6974,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9527,13 +7002,58 @@ paths: description: An ISO 8601 formatted date string (complementing `timestamp`) timestampReadable: type: string - title: - type: string - titleRaw: - type: string + additionalProperties: + description: Contextual data is added to this object (such as topic data, etc.) bans: type: array - items: {} + items: + type: object + properties: + uid: + type: number + timestamp: + type: number + expire: + type: number + fromUid: + type: number + user: + type: object + properties: + username: + type: string + description: A friendly name for a given user account + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + type: string + uid: + type: number + description: A user identifier + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + until: + type: number + untilReadable: + type: string + timestampReadable: + type: string + timestampISO: + type: string + reason: + type: string sessions: type: array items: @@ -9581,7 +7101,44 @@ paths: description: An ISO 8601 formatted date string (complementing `timestamp`) moderationNotes: type: array - items: {} + items: + type: object + properties: + uid: + type: number + note: + type: string + timestamp: + type: number + timestampISO: + type: string + user: + type: object + properties: + username: + type: string + description: A friendly name for a given user account + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + type: string + uid: + type: number + description: A user identifier + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" title: type: string - $ref: components/schemas/Pagination.yaml#/Pagination @@ -9598,6 +7155,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9619,16 +7177,12 @@ paths: type: number postsPerPage: type: number - notificationSounds: - type: number topicPostSort: type: string openOutgoingLinksInNewTab: type: boolean dailyDigestFreq: type: string - language: - type: string showfullname: type: boolean followTopicsOnCreate: @@ -9643,20 +7197,12 @@ paths: type: string userLang: type: string - groupTitle: - nullable: true - pushbullet:enabled: - type: number - pushbullet:target: - type: string bootswatchSkin: type: string homePageRoute: type: string scrollToMyPost: type: boolean - delayImageLoading: - type: number notificationSound: type: string incomingChatSound: @@ -9700,6 +7246,39 @@ paths: uid: type: number description: A user identifier + required: + - showemail + - usePagination + - topicsPerPage + - postsPerPage + - topicPostSort + - openOutgoingLinksInNewTab + - dailyDigestFreq + - showfullname + - followTopicsOnCreate + - followTopicsOnReply + - restrictChat + - topicSearchEnabled + - categoryTopicSort + - userLang + - bootswatchSkin + - homePageRoute + - scrollToMyPost + - notificationType_new-chat + - notificationType_new-reply + - notificationType_upvote + - notificationType_new-topic + - notificationType_follow + - notificationType_group-invite + - upvoteNotifFreq + - acpLang + - notificationType_new-register + - notificationType_post-queue + - notificationType_new-post-flag + - notificationType_new-user-flag + - categoryWatchState + - notificationType_group-request-membership + - uid languages: type: array items: @@ -9809,7 +7388,10 @@ paths: type: boolean customSettings: type: array - items: {} + items: + type: object + properties: {} + additionalProperties: {} homePageRoutes: type: array items: @@ -9905,6 +7487,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9917,7 +7500,13 @@ paths: properties: uploads: type: array - items: {} + items: + type: object + properties: + name: + type: string + url: + type: string privateUploads: type: boolean title: @@ -9936,6 +7525,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9970,6 +7560,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -9982,7 +7573,8 @@ paths: properties: users: type: array - items: {} + items: + $ref: components/schemas/UserObject.yaml#/UserObjectSlim title: type: string - $ref: components/schemas/Pagination.yaml#/Pagination @@ -9999,6 +7591,7 @@ paths: required: true schema: type: string + example: admin responses: "200": description: "" @@ -10011,7 +7604,25 @@ paths: properties: sessions: type: array - items: {} + items: + type: object + properties: + ip: + type: string + uuid: + type: string + datetime: + type: number + platform: + type: string + browser: + type: string + version: + type: string + current: + type: boolean + datetimeISO: + type: string title: type: string - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs @@ -10027,11 +7638,13 @@ paths: required: true schema: type: string + example: admin - name: uuid in: path required: true schema: type: string + example: testuuid responses: "200": description: User session revoked @@ -10122,13 +7735,7 @@ paths: type: array items: type: object - properties: - name: - type: string - filter: - type: string - selected: - type: boolean + additionalProperties: {} regularFilters: type: array items: @@ -10140,6 +7747,9 @@ paths: type: string selected: type: boolean + required: + - name + - filter moderatorFilters: type: array items: @@ -10163,22 +7773,24 @@ paths: - $ref: components/schemas/Pagination.yaml#/Pagination - $ref: components/schemas/Breadcrumbs.yaml#/Breadcrumbs - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/user/{userslug}/chats/{roomid?}": + "/api/user/{userslug}/chats/{roomid}": get: tags: - users - summary: /api/user/{userslug}/chats/{roomid?} + summary: Get chat room parameters: - name: userslug in: path required: true schema: type: string - - name: roomid? + example: admin + - name: roomid in: path required: true schema: type: string + example: 1 responses: "200": description: "" @@ -10235,6 +7847,7 @@ paths: removed, etc.) picture: type: string + nullable: true status: type: string banned: @@ -10263,6 +7876,8 @@ paths: type: number cleanedContent: type: string + isOwner: + type: boolean isOwner: type: boolean users: @@ -10278,6 +7893,7 @@ paths: description: A friendly name for a given user account picture: type: string + nullable: true status: type: string icon:text: @@ -10406,6 +8022,7 @@ paths: example: "#f44336" lastonlineISO: type: string + nullable: true lastUser: type: object properties: @@ -10456,17 +8073,18 @@ paths: canViewInfo: type: boolean - $ref: components/schemas/CommonProps.yaml#/CommonProps - "/api/chats/{roomid?}": + "/api/chats/{roomid}": get: tags: - shorthand - summary: /api/chats/{roomid?} + summary: /api/chats/{roomid} parameters: - - name: roomid? + - name: roomid in: path required: true schema: type: string + example: 1 responses: "200": description: "Chat identifier resolved" @@ -10696,6 +8314,7 @@ paths: required: true schema: type: string + example: administrators responses: "200": description: "" @@ -10708,133 +8327,7 @@ paths: title: type: string group: - type: object - properties: - name: - type: string - description: - type: string - deleted: - type: number - hidden: - type: number - system: - type: number - userTitle: - type: string - icon: - type: string - labelColor: - type: string - slug: - type: string - createtime: - type: number - memberCount: - type: number - private: - type: number - cover:url: - type: string - cover:position: - type: string - userTitleEnabled: - type: number - disableJoinRequests: - type: number - disableLeave: - type: number - nameEncoded: - type: string - displayName: - type: string - textColor: - type: string - createtimeISO: - type: string - cover:thumb:url: - type: string - descriptionParsed: - type: string - members: - type: array - items: - type: object - properties: - uid: - type: number - description: A user identifier - username: - type: string - description: A friendly name for a given user account - userslug: - type: string - description: An URL-safe variant of the username (i.e. lower-cased, spaces - removed, etc.) - picture: - type: string - status: - type: string - postcount: - type: number - reputation: - type: number - email:confirmed: - type: number - description: Whether the user has confirmed their email address or not - lastonline: - type: number - flags: - nullable: true - type: number - banned: - type: number - banned:expire: - type: number - joindate: - type: number - description: A UNIX timestamp representing the moment the user's account was - created - icon:text: - type: string - description: A single-letter representation of a username. This is used in the - auto-generated icon given to users without - an avatar - icon:bgColor: - type: string - description: A six-character hexadecimal colour code assigned to the user. This - value is used in conjunction with - `icon:text` for the user's auto-generated - icon - example: "#f44336" - joindateISO: - type: string - lastonlineISO: - type: string - banned_until: - type: number - banned_until_readable: - type: string - administrator: - type: boolean - isOwner: - type: boolean - membersNextStart: - type: number - pending: - type: array - items: {} - invited: - type: array - items: {} - isMember: - type: boolean - isPending: - type: boolean - isInvited: - type: boolean - isOwner: - type: boolean + $ref: components/schemas/GroupObject.yaml#/GroupFullObject posts: $ref: components/schemas/PostsObject.yaml#/PostsObject isAdmin: @@ -10851,11 +8344,12 @@ paths: - groups summary: Get user group members parameters: - - name: userslug + - name: slug in: path required: true schema: type: string + example: administrators responses: "200": description: "" diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 29af0ec383..de94534384 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -100,7 +100,7 @@ define('forum/topic/posts', [ function updatePagination() { $.get(config.relative_path + '/api/topic/pagination/' + ajaxify.data.tid, { page: ajaxify.data.pagination.currentPage }, function (paginationData) { - app.parseAndTranslate('partials/paginator', { pagination: paginationData }, function (html) { + app.parseAndTranslate('partials/paginator', paginationData, function (html) { $('[component="pagination"]').after(html).remove(); }); }); diff --git a/src/controllers/accounts/consent.js b/src/controllers/accounts/consent.js index 9038b2905a..a4989ff31f 100644 --- a/src/controllers/accounts/consent.js +++ b/src/controllers/accounts/consent.js @@ -19,7 +19,7 @@ consentController.get = async function (req, res, next) { const consented = await db.getObjectField('user:' + userData.uid, 'gdpr_consent'); userData.gdpr_consent = parseInt(consented, 10) === 1; userData.digest = { - frequency: meta.config.dailyDigestFreq, + frequency: meta.config.dailyDigestFreq || 'off', enabled: meta.config.dailyDigestFreq !== 'off', }; diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index d253ed41a5..6686f17cfd 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -143,6 +143,7 @@ async function getProfileMenu(uid, callerUID) { id: 'info', route: 'info', name: '[[user:account_info]]', + icon: 'fa-info', visibility: { self: false, other: false, @@ -155,6 +156,7 @@ async function getProfileMenu(uid, callerUID) { id: 'sessions', route: 'sessions', name: '[[pages:account/sessions]]', + icon: 'fa-group', visibility: { self: true, other: false, @@ -170,6 +172,7 @@ async function getProfileMenu(uid, callerUID) { id: 'consent', route: 'consent', name: '[[user:consent.title]]', + icon: 'fa-thumbs-o-up', visibility: { self: true, other: false, @@ -190,6 +193,8 @@ async function getProfileMenu(uid, callerUID) { async function parseAboutMe(userData) { if (!userData.aboutme) { + userData.aboutme = ''; + userData.aboutmeParsed = ''; return; } userData.aboutme = validator.escape(String(userData.aboutme || '')); diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index e0d7d2fc2c..34ba4cd7cc 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -106,12 +106,12 @@ settingsController.get = async function (req, res, next) { userData.categoryWatchState = { [userData.settings.categoryWatchState]: true }; - userData.disableCustomUserSkins = meta.config.disableCustomUserSkins; + userData.disableCustomUserSkins = meta.config.disableCustomUserSkins || 0; - userData.allowUserHomePage = meta.config.allowUserHomePage; + userData.allowUserHomePage = meta.config.allowUserHomePage || 1; - userData.hideFullname = meta.config.hideFullname; - userData.hideEmail = meta.config.hideEmail; + userData.hideFullname = meta.config.hideFullname || 0; + userData.hideEmail = meta.config.hideEmail || 0; userData.inTopicSearchAvailable = plugins.hasListeners('filter:topic.search'); diff --git a/src/controllers/admin/info.js b/src/controllers/admin/info.js index 6a22d52160..4c1182e6f7 100644 --- a/src/controllers/admin/info.js +++ b/src/controllers/admin/info.js @@ -28,11 +28,17 @@ infoController.get = function (req, res) { } return 0; }); + + let port = nconf.get('port'); + if (!Array.isArray(port) && !isNaN(parseInt(port, 10))) { + port = [port]; + } + res.render('admin/development/info', { info: data, infoJSON: JSON.stringify(data, null, 4), host: os.hostname(), - port: nconf.get('port'), + port: port, nodeCount: data.length, timeout: timeoutMS, ip: req.ip, diff --git a/src/controllers/category.js b/src/controllers/category.js index d6c4e5edf6..4edc7324d6 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -103,7 +103,7 @@ categoryController.get = async function (req, res, next) { addTags(categoryData, res); - categoryData['feeds:disableRSS'] = meta.config['feeds:disableRSS']; + categoryData['feeds:disableRSS'] = meta.config['feeds:disableRSS'] || 0; categoryData['reputation:disabled'] = meta.config['reputation:disabled']; pageCount = Math.max(1, Math.ceil(categoryData.topic_count / userSettings.topicsPerPage)); categoryData.pagination = pagination.create(currentPage, pageCount, req.query); diff --git a/src/controllers/recent.js b/src/controllers/recent.js index 78e98b4d0e..13ee9b956c 100644 --- a/src/controllers/recent.js +++ b/src/controllers/recent.js @@ -62,9 +62,9 @@ recentController.getData = async function (req, url, sort) { data.canPost = canPost; data.categories = categoryData.categories; data.allCategoriesUrl = url + helpers.buildQueryString('', filter, ''); - data.selectedCategory = categoryData.selectedCategory; + data.selectedCategory = categoryData.selectedCategory || null; data.selectedCids = categoryData.selectedCids; - data['feeds:disableRSS'] = meta.config['feeds:disableRSS']; + data['feeds:disableRSS'] = meta.config['feeds:disableRSS'] || 0; data.rssFeedUrl = nconf.get('relative_path') + '/' + url + '.rss'; if (req.loggedIn) { data.rssFeedUrl += '?uid=' + req.uid + '&token=' + rssToken; diff --git a/src/controllers/tags.js b/src/controllers/tags.js index 4360d562c2..da9c8122b9 100644 --- a/src/controllers/tags.js +++ b/src/controllers/tags.js @@ -32,10 +32,6 @@ tagsController.getTag = async function (req, res) { helpers.getCategoriesByStates(req.uid, '', states), ]); - if (Array.isArray(tids) && !tids.length) { - return res.render('tag', templateData); - } - templateData.categories = categoriesData.categories; templateData.topics = await topics.getTopics(tids, req.uid); diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 6d2656771e..71c1f03ae4 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -70,16 +70,12 @@ topicsController.get = async function getTopic(req, res, callback) { topics.modifyPostsByPrivilege(topicData, userPrivileges); const hookData = await plugins.fireHook('filter:controllers.topic.get', { topicData: topicData, uid: req.uid }); - await Promise.all([ - buildBreadcrumbs(hookData.topicData), - addTags(topicData, req, res), - ]); topicData.privileges = userPrivileges; topicData.topicStaleDays = meta.config.topicStaleDays; topicData['reputation:disabled'] = meta.config['reputation:disabled']; topicData['downvote:disabled'] = meta.config['downvote:disabled']; - topicData['feeds:disableRSS'] = meta.config['feeds:disableRSS']; + topicData['feeds:disableRSS'] = meta.config['feeds:disableRSS'] || 0; topicData.bookmarkThreshold = meta.config.bookmarkThreshold; topicData.necroThreshold = meta.config.necroThreshold; topicData.postEditDuration = meta.config.postEditDuration; @@ -99,6 +95,11 @@ topicsController.get = async function getTopic(req, res, callback) { res.locals.linkTags.push(rel); }); + await Promise.all([ + buildBreadcrumbs(hookData.topicData), + addTags(topicData, req, res), + ]); + incrementViewCount(req, tid); markAsRead(req, tid); @@ -338,5 +339,5 @@ topicsController.pagination = async function (req, res, callback) { rel.href = nconf.get('url') + '/topic/' + topic.slug + rel.href; }); - res.json(paginationData); + res.json({ pagination: paginationData }); }; diff --git a/src/controllers/user.js b/src/controllers/user.js index 69d52ffddf..861a88485a 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -178,7 +178,7 @@ userController.exportUploads = function (req, res, next) { }); archive.pipe(output); - winston.info('[user/export/uploads] Collating uploads for uid ' + targetUid); + winston.verbose('[user/export/uploads] Collating uploads for uid ' + targetUid); user.collateUploads(targetUid, archive, function (err) { if (err) { return next(err); diff --git a/src/database/redis.js b/src/database/redis.js index 67ccc8088d..c235712ef0 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -43,7 +43,6 @@ redisModule.init = function (callback) { winston.error('NodeBB could not connect to your Redis database. Redis returned the following error', err); return callback(err); } - require('./redis/promisify')(redisModule.client); callback(); diff --git a/src/flags.js b/src/flags.js index 6f698f6511..5b42a6447e 100644 --- a/src/flags.js +++ b/src/flags.js @@ -100,6 +100,7 @@ Flags.get = async function (flagId) { const flagObj = { state: 'open', + assignee: null, ...base, description: validator.escape(base.description), datetimeISO: utils.toISOString(base.datetime), @@ -164,6 +165,7 @@ Flags.list = async function (filters, uid) { const userObj = await user.getUserFields(flagObj.uid, ['username', 'picture']); flagObj = { state: 'open', + assignee: null, ...flagObj, reporter: { username: userObj.username, diff --git a/src/messaging/data.js b/src/messaging/data.js index 4043752be4..9fbf14eb63 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -82,6 +82,7 @@ module.exports = function (Messaging) { messages = await Promise.all(messages.map(async (message) => { if (message.system) { message.content = validator.escape(String(message.content)); + message.cleanedContent = utils.stripHTMLTags(utils.decodeHTMLEntities(message.content)); return message; } diff --git a/src/navigation/admin.js b/src/navigation/admin.js index 33a96fc193..5398ac8375 100644 --- a/src/navigation/admin.js +++ b/src/navigation/admin.js @@ -60,6 +60,9 @@ admin.get = async function () { async function getAvailable() { const core = require('../../install/data/navigation.json').map(function (item) { item.core = true; + item.id = item.id || ''; + item.properties = item.properties || { targetBlank: false }; + return item; }); diff --git a/src/posts/summary.js b/src/posts/summary.js index c86d10cdfa..66ee954b8f 100644 --- a/src/posts/summary.js +++ b/src/posts/summary.js @@ -74,7 +74,7 @@ module.exports = function (Posts) { } async function getTopicAndCategories(tids) { - const topicsData = await topics.getTopicsFields(tids, ['uid', 'tid', 'title', 'cid', 'slug', 'deleted', 'postcount', 'mainPid']); + const topicsData = await topics.getTopicsFields(tids, ['uid', 'tid', 'title', 'cid', 'slug', 'deleted', 'postcount', 'mainPid', 'teaserPid']); const cids = _.uniq(topicsData.map(topic => topic && topic.cid)); const categoriesData = await categories.getCategoriesFields(cids, ['cid', 'name', 'icon', 'slug', 'parentCid', 'bgColor', 'color', 'image', 'imageClass']); return { topics: topicsData, categories: categoriesData }; diff --git a/src/topics/data.js b/src/topics/data.js index 44625c47f2..2e1931e823 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -106,4 +106,8 @@ function modifyTopic(topic, fields) { if (topic.hasOwnProperty('upvotes') && topic.hasOwnProperty('downvotes')) { topic.votes = topic.upvotes - topic.downvotes; } + + if (fields.includes('teaserPid') || !fields.length) { + topic.teaserPid = topic.teaserPid || null; + } } diff --git a/src/topics/index.js b/src/topics/index.js index 11186c454f..42c25190ac 100644 --- a/src/topics/index.js +++ b/src/topics/index.js @@ -102,7 +102,7 @@ Topics.getTopicsByTids = async function (tids, options) { if (topics[i]) { topics[i].category = categoriesMap[topics[i].cid]; topics[i].user = usersMap[topics[i].uid]; - topics[i].teaser = teasers[i]; + topics[i].teaser = teasers[i] || null; topics[i].tags = tags[i]; topics[i].isOwner = topics[i].uid === parseInt(uid, 10); diff --git a/src/user/info.js b/src/user/info.js index 29687ad726..48f43e5ebb 100644 --- a/src/user/info.js +++ b/src/user/info.js @@ -101,7 +101,7 @@ module.exports = function (User) { banObj.user = usersData[index]; banObj.until = parseInt(banObj.expire, 10); banObj.untilReadable = new Date(banObj.until).toString(); - banObj.timestampReadable = new Date(banObj.timestamp).toString(); + banObj.timestampReadable = new Date(parseInt(banObj.timestamp, 10)).toString(); banObj.timestampISO = utils.toISOString(banObj.timestamp); banObj.reason = validator.escape(String(banObj.reason || '')) || '[[user:info.banned-no-reason]]'; return banObj; diff --git a/test/api.js b/test/api.js index e2496e7776..fa88a5b990 100644 --- a/test/api.js +++ b/test/api.js @@ -3,18 +3,226 @@ const assert = require('assert'); const path = require('path'); const SwaggerParser = require('@apidevtools/swagger-parser'); +const request = require('request-promise-native'); +const nconf = require('nconf'); -describe('Read API', () => { - let readApi; +const db = require('./mocks/databasemock'); +const helpers = require('./helpers'); +const user = require('../src/user'); +const groups = require('../src/groups'); +const categories = require('../src/categories'); +const topics = require('../src/topics'); +const plugins = require('../src/plugins'); +const flags = require('../src/flags'); +const messaging = require('../src/messaging'); + +describe('Read API', async () => { + let readApi = false; + const apiPath = path.resolve(__dirname, '../public/openapi/read.yaml'); + let jar; + let setup = false; + const unauthenticatedRoutes = ['/api/login', '/api/register']; // Everything else will be called with the admin user + + async function dummySearchHook(data) { + return [1]; + } + + after(async function () { + plugins.unregisterHook('core', 'filter:search.query', dummySearchHook); + }); + + async function setupData() { + if (setup) { + return; + } + + // Create sample users + const adminUid = await user.create({ username: 'admin', password: '123456', email: 'test@example.org' }); + const unprivUid = await user.create({ username: 'unpriv', password: '123456', email: 'unpriv@example.org' }); + await groups.join('administrators', adminUid); + + // Create a category + const testCategory = await categories.create({ name: 'test' }); + + // Post a new topic + const testTopic = await topics.post({ + uid: adminUid, + cid: testCategory.cid, + title: 'Test Topic', + content: 'Test topic content', + }); + + // Create a sample flag + await flags.create('post', 1, unprivUid, 'sample reasons', Date.now()); + + // Create a new chat room + await messaging.newRoom(1, [2]); + + // Attach a search hook so /api/search is enabled + plugins.registerHook('core', { + hook: 'filter:search.query', + method: dummySearchHook, + }); + + jar = await helpers.loginUser('admin', '123456'); + setup = true; + } it('should pass OpenAPI v3 validation', async () => { - const apiPath = path.resolve(__dirname, '../public/openapi/read.yaml'); try { - readApi = await SwaggerParser.validate(apiPath); + await SwaggerParser.validate(apiPath); } catch (e) { assert.ifError(e); } }); + + readApi = await SwaggerParser.dereference(apiPath); + + // Iterate through all documented paths, make a call to it, and compare the result body with what is defined in the spec + const paths = Object.keys(readApi.paths); + + paths.forEach((path) => { + let schema; + let response; + let url; + const headers = {}; + const qs = {}; + + function compare(schema, response, context) { + let required = []; + const additionalProperties = schema.hasOwnProperty('additionalProperties'); + + if (schema.allOf) { + schema = schema.allOf.reduce((memo, obj) => { + required = required.concat(obj.required ? obj.required : Object.keys(obj.properties)); + memo = { ...memo, ...obj.properties }; + return memo; + }, {}); + } else if (schema.properties) { + required = schema.required || Object.keys(schema.properties); + schema = schema.properties; + } else { + // If schema contains no properties, check passes + return; + } + + // Compare the schema to the response + required.forEach((prop) => { + if (schema.hasOwnProperty(prop)) { + assert(response.hasOwnProperty(prop), '"' + prop + '" is a required property (path: ' + path + ', context: ' + context + ')'); + + // Don't proceed with type-check if the value could possibly be unset (nullable: true, in spec) + if (response[prop] === null && schema[prop].nullable === true) { + return; + } + + // Therefore, if the value is actually null, that's a problem (nullable is probably missing) + assert(response[prop] !== null, '"' + prop + '" was null, but schema does not specify it to be a nullable property (path: ' + path + ', context: ' + context + ')'); + + switch (schema[prop].type) { + case 'string': + assert.strictEqual(typeof response[prop], 'string', '"' + prop + '" was expected to be a string, but was ' + typeof response[prop] + ' instead (path: ' + path + ', context: ' + context + ')'); + break; + case 'boolean': + assert.strictEqual(typeof response[prop], 'boolean', '"' + prop + '" was expected to be a boolean, but was ' + typeof response[prop] + ' instead (path: ' + path + ', context: ' + context + ')'); + break; + case 'object': + assert.strictEqual(typeof response[prop], 'object', '"' + prop + '" was expected to be an object, but was ' + typeof response[prop] + ' instead (path: ' + path + ', context: ' + context + ')'); + compare(schema[prop], response[prop], context ? [context, prop].join('.') : prop); + break; + case 'array': + assert.strictEqual(Array.isArray(response[prop]), true, '"' + prop + '" was expected to be an array, but was ' + typeof response[prop] + ' instead (path: ' + path + ', context: ' + context + ')'); + + if (schema[prop].items) { + // Ensure the array items have a schema defined + assert(schema[prop].items.type || schema[prop].items.allOf, '"' + prop + '" is defined to be an array, but its items have no schema defined (path: ' + path + ', context: ' + context + ')'); + + // Compare types + if (schema[prop].items.type === 'object' || Array.isArray(schema[prop].items.allOf)) { + response[prop].forEach((res) => { + compare(schema[prop].items, res, context ? [context, prop].join('.') : prop); + }); + } else if (response[prop].length) { // for now + response[prop].forEach((item) => { + assert.strictEqual(typeof item, schema[prop].items.type, '"' + prop + '" should have ' + schema[prop].items.type + ' items, but found ' + typeof items + ' instead (path: ' + path + ', context: ' + context + ')'); + }); + } + } + break; + } + } + }); + + // Compare the response to the schema + Object.keys(response).forEach((prop) => { + if (additionalProperties) { // All bets are off + return; + } + + assert(schema[prop], '"' + prop + '" was found in response, but is not defined in schema (path: ' + path + ', context: ' + context + ')'); + }); + } + + // TOXO: fix -- premature exit for POST-only routes + if (!readApi.paths[path].get) { + return; + } + + it('should have examples when parameters are present', () => { + const parameters = readApi.paths[path].get.parameters; + let testPath = path; + if (parameters) { + parameters.forEach((param) => { + assert(param.example !== null && param.example !== undefined, path + ' has parameters without examples'); + + switch (param.in) { + case 'path': + testPath = testPath.replace('{' + param.name + '}', param.example); + break; + case 'header': + headers[param.name] = param.example; + break; + case 'query': + qs[param.name] = param.example; + break; + } + }); + } + + url = nconf.get('url') + testPath; + }); + + it('should resolve with a 200 when called', async () => { + await setupData(); + + try { + response = await request(url, { + jar: !unauthenticatedRoutes.includes(path) ? jar : undefined, + json: true, + headers: headers, + qs: qs, + }); + } catch (e) { + assert(!e, path + ' resolved with ' + e.message); + } + }); + + // Recursively iterate through schema properties, comparing type + it('response should match schema definition', () => { + const has200 = readApi.paths[path].get.responses['200']; + if (!has200) { + return; + } + + const hasJSON = has200.content && has200.content['application/json']; + if (hasJSON) { + schema = readApi.paths[path].get.responses['200'].content['application/json'].schema; + compare(schema, response, 'root'); + } + + // TODO someday: text/csv, binary file type checking? + }); + }); }); describe('Write API', () => { diff --git a/test/topics.js b/test/topics.js index c91395407b..682ce72025 100644 --- a/test/topics.js +++ b/test/topics.js @@ -1071,7 +1071,7 @@ describe('Topic\'s', function () { assert.ifError(err); assert.equal(response.statusCode, 200); assert(body); - assert.deepEqual(body, { + assert.deepEqual(body.pagination, { prev: { page: 1, active: false }, next: { page: 1, active: false }, first: { page: 1, active: true },