Add channel routes.

This commit is contained in:
Paul
2021-07-11 17:59:20 +01:00
parent 5bfdb16b03
commit a0904b9909
9 changed files with 6271 additions and 96 deletions
+5732 -49
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -37,6 +37,7 @@ export function tag(name: string, description: string) {
export function resource(path: string, methods: OpenAPIV3.PathItemObject) {
console.info(`Generating resource ${path}.`);
if (resources[path]) throw `Resource ${path} already exists!`;
resources[path] = methods;
}
+487
View File
@@ -0,0 +1,487 @@
import { body, parameter, ref, success } from "../openapi/generators.js";
import { group, resource, routeAuthenticated, tag } from "../openapi/paths.js";
import { schema } from "../typescript.js";
group("Channels");
//#region Channel Information
tag("Channel Information", "Query and fetch channels on Revolt");
const channelParams = {
parameters: [
await parameter('channel', 'Channel ID', ref("Id"))
]
}
resource('/channels/:channel', {
get: routeAuthenticated(
"Fetch Channel",
"Retrieve a channel.",
{
...channelParams,
...await success(
"Retrieved channel.",
ref("Channel")
)
}
),
patch: routeAuthenticated(
"Edit Channel",
"Edit a channel object.",
{
...channelParams,
...await body("Requested changes to channel object.", schema`
import type { Status } from './Users';
import type { AutumnId } from './_common';
interface ${'EditChannels'} {
/**
* Channel name
**/
name: string;
/**
* Channel description
**/
description?: string;
icon?: AutumnId;
/**
* Field to remove from channel object
*/
remove?: 'Icon' | 'Description';
}
`),
...await success("Succesfully changed channel object.")
}
),
delete: routeAuthenticated(
"Close Channel",
"Deletes a server channel, leaves a group or closes a DM.",
await success("Deleted Channel")
)
});
//#endregion
//#region Channel Invites
tag("Channel Invites", "Create and manage invites for channels");
resource('/channels/:channel/invites', {
post: routeAuthenticated(
"Create Invite",
"Creates an invite to this channel.\n\nChannel must be a `TextChannel`.",
{
...channelParams,
...await success("Invite", schema`
interface ${'InviteCode'} {
/**
* Invite Code
*/
code: string;
}
`)
}
)
});
//#endregion
//#region Channel Permissions
tag("Channel Permissions", "Manage permissions for channels");
const roleParams = {
parameters: [
await parameter('channel', 'Channel ID', ref("Id")),
await parameter('role', 'Role ID', ref("Id"))
]
}
const channelPermissions = await body("Channel Permissions", schema`
interface ${'ChannelPermissions'} {
permissions: number
}
`)
resource('/channels/:channel/permissions/:role', {
put: routeAuthenticated(
"Set Role Permission",
"Sets permissions for the specified role in this channel.\n\nChannel must be a `TextChannel` or `VoiceChannel`.",
{
...roleParams,
...channelPermissions,
...await success("Successfully updated permissions.")
}
)
});
resource('/channels/:channel/permissions/default', {
put: routeAuthenticated(
"Set Default Permission",
"Sets permissions for the default role in this channel.\n\nChannel must be a `Group`, `TextChannel` or `VoiceChannel`.",
{
...channelParams,
...channelPermissions,
...await success("Successfully updated permissions.")
}
)
});
//#endregion
//#region Messaging
tag("Messaging", "Send and manipulate messages");
const messageParams = {
parameters: [
await parameter('channel', 'Channel ID', ref("Id")),
await parameter('message', 'Message ID', ref("Id"))
]
}
const retrievedMessages = await success("Message array or object with requested data.", schema`
import { Message } from './Channels';
import { User } from './Users';
import { Member } from './Servers';
type ${'RetrievedMessages'} = Message[] | {
messages: Message[],
users: User[],
members?: Member[]
}
`);
resource('/channels/:channel/messages', {
post: routeAuthenticated(
"Send Message",
"Sends a message to the given channel.",
{
...channelParams,
...await body("Message to be sent.", schema`
import type { Id, Nonce, AutumnId } from './_common';
interface ${'SendMessage'} {
/**
* Message content to send.
* @minLength 0
* @maxLength 2000
*/
content: string;
nonce: Nonce;
/**
* Attachments to include in message.
*/
attachments?: AutumnId[];
/**
* Messages to reply to.
*/
replies?: {
/**
* Message Id
*/
id: Id;
/**
* Whether this reply should mention the message's author.
*/
mention: boolean;
}
}
`),
...await success(
"Sent message.",
ref("Message")
)
}
),
get: routeAuthenticated(
"Fetch Messages",
"Fetches multiple messages.",
{
...channelParams,
...await body("Fetch Options", schema`
import { Id } from './_common';
interface ${'FetchOptions'} {
/**
* Maximum number of messages to fetch.
*
* For fetching nearby messages, this is \`(limit + 1)\`.
*
* @minimum 1
* @maximum 100
*/
limit?: number;
/**
* Message id before which messages should be fetched.
*/
before?: Id;
/**
* Message id after which messages should be fetched.
*/
after?: Id;
/**
* Message sort direction
*/
sort: 'Latest' | 'Oldest';
/**
* Message id to fetch around, this will ignore 'before', 'after' and 'sort' options.
* Limits in each direction will be half of the specified limit.
* It also fetches the specified message ID.
*/
nearby?: Id;
/**
* Whether to include user (and member, if server channel) objects.
*/
include_users?: boolean;
}
`),
...retrievedMessages
}
)
});
resource('/channels/:channel/messages/:message', {
get: routeAuthenticated(
"Fetch Message",
"Retrieves a message by ID.",
{
...messageParams,
...await success(
"Message",
ref("Message")
)
}
),
patch: routeAuthenticated(
"Edit Message",
"Edits a message that you've previously sent.",
{
...messageParams,
...await body("Message edit data.", schema`
interface ${'MessageEdit'} {
/**
* Message content
* @minLength 1
* @maxLength 2000
*/
content: string;
}
`),
...await success("Message was changed.")
}
),
delete: routeAuthenticated(
"Delete Message",
"Delete a message you've sent or one you have permission to delete.",
{
...messageParams,
...await success("Message was deleted.")
}
)
});
resource('/channels/:channel/messages/stale', {
post: routeAuthenticated(
"Poll Message Changes",
"This route returns any changed message objects and tells you if any have been deleted.\n\nDon't actually poll this route, instead use this to update your local database.",
{
...channelParams,
...await body("Poll Options", schema`
import { Id } from './_common';
interface ${'PollOptions'} {
/**
* Array of message IDs.
*
* @maxItems 150
*/
ids: Id[];
}
`),
...await success("Polled Information", schema`
import { Message } from './Channels';
interface ${'PolledInformation'} {
/**
* Changed message objects.
*/
changed: Message[],
/**
* Array of deleted message IDs.
*/
deleted: string[]
}
`)
}
)
});
resource('/channels/:channel/messages/search', {
post: routeAuthenticated(
"Search for Messages",
"This route searches for messages within the given parameters.",
{
...channelParams,
...await body("Search Options", schema`
import { Id } from './_common';
interface ${'SearchOptions'} {
/**
* Full-text search query.
*
* See [MongoDB documentation](https://docs.mongodb.com/manual/text-search/#-text-operator) for more information.
*
* @minLength 1
* @maxLength 64
*/
query: string;
/**
* Maximum number of messages to fetch.
*
* @minimum 1
* @maximum 100
*/
limit?: number;
/**
* Message id before which messages should be fetched.
*/
before?: Id;
/**
* Message id after which messages should be fetched.
*/
after?: Id;
/**
* Message sort direction
*/
sort: 'Relevance' | 'Latest' | 'Oldest';
/**
* Whether to include user (and member, if server channel) objects.
*/
include_users?: boolean;
}
`),
...retrievedMessages
}
)
});
resource('/channels/:channel/ack/:message', {
put: routeAuthenticated(
"Acknowledge Message",
"Lets the server and all other clients know that we've seen this message id in this channel.",
{
...messageParams,
...await success("Acknowledged message.")
}
)
});
//#endregion
//#region Groups
tag("Groups", "Create, invite users and manipulate groups");
resource('/channels/create', {
post: routeAuthenticated(
"Create Group",
"Create a new group with friends.",
{
...await body("Group Data", schema`
import { Id, Nonce } from './_common';
interface ${'GroupData'} {
/**
* Group name
* @minLength 1
* @maxLength 32
*/
name: string;
/**
* Group description
* @minLength 0
* @maxLength 1024
*/
description?: string;
nonce: Nonce;
/**
* Array of user IDs to add to the group.
*
* Must be friends with them.
*
* @maxItems 49
*/
users?: string[];
}
`),
...await success('Group', ref("GroupChannel"))
}
)
});
resource('/channels/:channel/members', {
get: routeAuthenticated(
"Fetch Group Members",
"Retrieves users who are part of this group.",
{
...messageParams,
...await success("Members", schema`
import { User } from './Users';
type ${'Members'} = User[];
`)
}
),
put: routeAuthenticated(
"Add Group Member",
"Adds another user to the group.",
{
...messageParams,
...await success("User was added to the group.")
}
),
delete: routeAuthenticated(
"Remove Group Member",
"Removes a user from the group.",
{
...messageParams,
...await success("User was removed from the group.")
}
)
});
//#endregion
//#region Voice
tag("Voice", "Join and talk with other users");
resource('/channels/:channel/join_call', {
post: routeAuthenticated(
"Join Call",
"Asks the voice server for a token to join the call.",
{
...channelParams,
...await success("Join Data", schema`
interface ${'JoinData'} {
/**
* Voso Token
*/
token: string;
}
`)
}
)
});
//#endregion
+1
View File
@@ -1,6 +1,7 @@
export async function load() {
await import('./core.js');
await import('./users.js');
await import('./channels.js');
}
await load();
+29 -37
View File
@@ -7,14 +7,18 @@ group("Users");
//#region User Information
tag("User Information", "Query and fetch users on Revolt");
const userParams = {
parameters: [
await parameter('user', 'User ID', ref("Id"))
]
}
resource('/users/:user', {
get: routeAuthenticated(
"Fetch User",
"Retrieve a user's information.",
{
parameters: [
await parameter('user', 'User ID', ref("Id"))
],
...userParams,
...await success(
"User information.",
ref("User")
@@ -33,27 +37,27 @@ resource('/users/@me', {
import type { AutumnId } from './_common';
interface ${'EditUser'} {
status: Status;
status?: Status;
/**
* User profile data
**/
profile: {
profile?: {
/**
* Text to set as user profile description
* @maxLength 2000
*/
content: string;
content?: string;
background: AutumnId;
background?: AutumnId;
}
avatar: AutumnId;
avatar?: AutumnId;
/**
* Field to remove from user object
*/
remove: 'ProfileContent' | 'ProfileBackground' | 'StatusText' | 'Avatar';
remove?: 'ProfileContent' | 'ProfileBackground' | 'StatusText' | 'Avatar';
}
`),
...await success("Succesfully changed user object.")
@@ -94,9 +98,7 @@ resource('/users/:user/profile', {
"Fetch User Profile",
"Retrieve a user's profile data.",
{
parameters: [
await parameter('user', 'User ID', ref("Id"))
],
...userParams,
...await success(
"User profile.",
ref("Profile")
@@ -110,9 +112,7 @@ resource('/users/:user/default_avatar', {
"Fetch Default Avatar",
"This returns a default avatar based on the given id.",
{
parameters: [
await parameter('user', 'User ID', ref("Id"))
],
...userParams,
responses: {
'200': {
description: "Default avatar in PNG format",
@@ -135,9 +135,7 @@ resource('/users/:user/mutual', {
"Fetch Mutual Friends",
"Retrieve a list of mutual friends with another user.",
{
parameters: [
await parameter('user', 'User ID', ref("Id"))
],
...userParams,
...await success(
"Mutual friends.",
schema`
@@ -179,9 +177,7 @@ resource('/users/:user/dm', {
"Open Direct Message",
"Open a DM with another user.",
{
parameters: [
await parameter('user', 'User ID', ref('Id'))
],
...userParams,
...await success(
"DM channel with user.",
ref("DirectMessageChannel")
@@ -213,9 +209,7 @@ resource('/users/:user/relationship', {
"Fetch Relationship",
"Fetch your relationship with another other user.",
{
parameters: [
await parameter('user', 'User ID', ref('Id'))
],
...userParams,
...await success(
"Your relationship with the user.",
ref("RelationshipOnly")
@@ -224,14 +218,18 @@ resource('/users/:user/relationship', {
)
});
resource('/users/:user/friend', {
const friendParams = {
parameters: [
await parameter('username', 'Username', ref("Username"))
],
}
resource('/users/:username/friend', {
put: routeAuthenticated(
"Send Friend Request / Accept Request",
"Send a friend request to another user or accept another user's friend request.",
{
parameters: [
await parameter('user', 'User ID', ref('Id'))
],
...friendParams,
...await success(
"Sent friend request / added user as friend.",
ref("RelationshipOnly")
@@ -242,9 +240,7 @@ resource('/users/:user/friend', {
"Deny Friend Request / Remove Friend",
"Denies another user's friend request or removes an existing friend.",
{
parameters: [
await parameter('user', 'User ID', ref('Id'))
],
...friendParams,
...await success(
"Deleted friend request / removed user from friends.",
ref("RelationshipOnly")
@@ -258,9 +254,7 @@ resource('/users/:user/block', {
"Block User",
"Block another user.",
{
parameters: [
await parameter('user', 'User ID', ref('Id'))
],
...userParams,
...await success(
"Blocked user.",
ref("RelationshipOnly")
@@ -271,9 +265,7 @@ resource('/users/:user/block', {
"Unblock User",
"Unblock another user.",
{
parameters: [
await parameter('user', 'User ID', ref('Id'))
],
...userParams,
...await success(
"Unblocked user.",
ref("RelationshipOnly")
+1 -1
View File
File diff suppressed because one or more lines are too long
+9 -7
View File
@@ -1,6 +1,14 @@
import type { Attachment } from './Autumn';
import type { Id } from './_common';
/**
* Username
* @minLength 2
* @maxLength 32
* @pattern ^[a-zA-Z0-9_.]+$
*/
export type Username = string;
/**
* Your relationship with the user
*/
@@ -64,13 +72,7 @@ export interface User {
*/
_id: Id
/**
* Username
* @minLength 2
* @maxLength 32
* @pattern ^[a-zA-Z0-9_.]+$
*/
username: string
username: Username
/**
* User avatar
+6 -2
View File
@@ -1,4 +1,8 @@
import type { Relationship } from "./Users";
type FetchRelationships = Relationship[];
interface JoinData {
/**
* Voso Token
*/
token: string;
}
+5
View File
@@ -6,6 +6,9 @@ export type Id = string;
/**
* Nonce value, prefer to use ULIDs here for better feature support.
*
* Used to prevent double requests to create objects.
*
* @minLength 1
* @maxLength 36
*/
@@ -13,5 +16,7 @@ export type Nonce = string;
/**
* Autumn file ID, [learn more](https://example.com/TODO).
* @minLength 1
* @maxLength 128
*/
export type AutumnId = string;