import * as v from 'valibot'; import { accountSchema, groupMemberSchema, groupRelationshipSchema, groupSchema, statusSchema, } from '../entities'; import { filteredArray } from '../entities/utils'; import { PIXELFED } from '../features'; import type { PlApiBaseClient } from '../client-base'; import type { GroupRole } from '../entities'; import type { AdminGetGroupsParams } from '../params/admin'; import type { CreateGroupParams, GetGroupBlocksParams, GetGroupMembershipRequestsParams, GetGroupMembershipsParams, UpdateGroupParams, } from '../params/groups'; type EmptyObject = Record; /** Routes that are not part of any stable release */ const experimental = (client: PlApiBaseClient) => { const category = { admin: { /** @see {@link https://github.com/mastodon/mastodon/pull/19059} */ groups: { /** list groups known to the instance. Mimics the interface of `/api/v1/admin/accounts` */ getGroups: async (params?: AdminGetGroupsParams) => { const response = await client.request('/api/v1/admin/groups', { params }); return v.parse(filteredArray(groupSchema), response.json); }, /** return basic group information */ getGroup: async (groupId: string) => { const response = await client.request(`/api/v1/admin/groups/${groupId}`); return v.parse(groupSchema, response.json); }, /** suspends a group */ suspendGroup: async (groupId: string) => { const response = await client.request(`/api/v1/admin/groups/${groupId}/suspend`, { method: 'POST', }); return v.parse(groupSchema, response.json); }, /** lift a suspension */ unsuspendGroup: async (groupId: string) => { const response = await client.request(`/api/v1/admin/groups/${groupId}/unsuspend`, { method: 'POST', }); return v.parse(groupSchema, response.json); }, /** deletes an already-suspended group */ deleteGroup: async (groupId: string) => { const response = await client.request(`/api/v1/admin/groups/${groupId}`, { method: 'DELETE', }); return v.parse(groupSchema, response.json); }, }, }, /** @see {@link https://github.com/mastodon/mastodon/pull/19059} */ groups: { /** returns an array of `Group` entities the current user is a member of */ getGroups: async () => { let response; if (client.features.version.software === PIXELFED) { response = await client.request('/api/v0/groups/self/list'); } else { response = await client.request('/api/v1/groups'); } return v.parse(filteredArray(groupSchema), response.json); }, /** create a group with the given attributes (`display_name`, `note`, `avatar` and `header`). Sets the user who made the request as group administrator */ createGroup: async (params: CreateGroupParams) => { let response; if (client.features.version.software === PIXELFED) { response = await client.request('/api/v0/groups/create', { method: 'POST', body: { ...params, name: params.display_name, description: params.note, membership: 'public', }, contentType: params.avatar || params.header ? '' : undefined, }); if (response.json?.id) { return category.groups.getGroup(response.json.id); } } else { response = await client.request('/api/v1/groups', { method: 'POST', body: params, contentType: params.avatar || params.header ? '' : undefined, }); } return v.parse(groupSchema, response.json); }, /** returns the `Group` entity describing a given group */ getGroup: async (groupId: string) => { let response; if (client.features.version.software === PIXELFED) { response = await client.request(`/api/v0/groups/${groupId}`); } else { response = await client.request(`/api/v1/groups/${groupId}`); } return v.parse(groupSchema, response.json); }, /** update group attributes (`display_name`, `note`, `avatar` and `header`) */ updateGroup: async (groupId: string, params: UpdateGroupParams) => { const response = await client.request(`/api/v1/groups/${groupId}`, { method: 'PUT', body: params, contentType: params.avatar || params.header ? '' : undefined, }); return v.parse(groupSchema, response.json); }, /** irreversibly deletes the group */ deleteGroup: async (groupId: string) => { let response; if (client.features.version.software === PIXELFED) { response = await client.request('/api/v0/groups/delete', { method: 'POST', params: { gid: groupId }, }); } else { response = await client.request(`/api/v1/groups/${groupId}`, { method: 'DELETE', }); } return response.json; }, /** Has an optional role attribute that can be used to filter by role (valid roles are `"admin"`, `"moderator"`, `"user"`). */ getGroupMemberships: ( groupId: string, role?: GroupRole, params?: GetGroupMembershipsParams, ) => client.paginatedGet( client.features.version.software === PIXELFED ? `/api/v0/groups/members/list?gid=${groupId}` : `/api/v1/groups/${groupId}/memberships`, { params: { ...params, role } }, groupMemberSchema, ), /** returns an array of `Account` entities representing pending requests to join a group */ getGroupMembershipRequests: (groupId: string, params?: GetGroupMembershipRequestsParams) => client.paginatedGet( client.features.version.software === PIXELFED ? `/api/v0/groups/members/requests?gid=${groupId}` : `/api/v1/groups/${groupId}/membership_requests`, { params }, accountSchema, ), /** accept a pending request to become a group member */ acceptGroupMembershipRequest: async (groupId: string, accountId: string) => { const response = await client.request( `/api/v1/groups/${groupId}/membership_requests/${accountId}/authorize`, { method: 'POST' }, ); return response.json; }, /** reject a pending request to become a group member */ rejectGroupMembershipRequest: async (groupId: string, accountId: string) => { const response = await client.request( `/api/v1/groups/${groupId}/membership_requests/${accountId}/reject`, { method: 'POST' }, ); return response.json; }, /** delete a group post (actually marks it as `revoked` if it is a local post) */ deleteGroupStatus: async (groupId: string, statusId: string) => { const response = await client.request(`/api/v1/groups/${groupId}/statuses/${statusId}`, { method: 'DELETE', }); return v.parse(statusSchema, response.json); }, /** list accounts blocked from interacting with the group */ getGroupBlocks: (groupId: string, params?: GetGroupBlocksParams) => client.paginatedGet(`/api/v1/groups/${groupId}/blocks`, { params }, accountSchema), /** block one or more users. If they were in the group, they are also kicked of it */ blockGroupUsers: async (groupId: string, accountIds: string[]) => { const response = await client.request(`/api/v1/groups/${groupId}/blocks`, { method: 'POST', params: { account_ids: accountIds }, }); return response.json; }, /** block one or more users. If they were in the group, they are also kicked of it */ unblockGroupUsers: async (groupId: string, accountIds: string[]) => { const response = await client.request(`/api/v1/groups/${groupId}/blocks`, { method: 'DELETE', params: { account_ids: accountIds }, }); return response.json; }, /** joins (or request to join) a given group */ joinGroup: async (groupId: string) => { const response = await client.request(`/api/v1/groups/${groupId}/join`, { method: 'POST' }); return v.parse(groupRelationshipSchema, response.json); }, /** leaves a given group */ leaveGroup: async (groupId: string) => { const response = await client.request(`/api/v1/groups/${groupId}/leave`, { method: 'POST', }); return v.parse(groupRelationshipSchema, response.json); }, /** kick one or more group members */ kickGroupUsers: async (groupId: string, accountIds: string[]) => { const response = await client.request(`/api/v1/groups/${groupId}/kick`, { method: 'POST', params: { account_ids: accountIds }, }); return response.json; }, /** promote one or more accounts to role `new_role`. An error is returned if any of those accounts has a higher role than `new_role` already, or if the role is higher than the issuing user's. Valid roles are `admin`, and `moderator` and `user`. */ promoteGroupUsers: async (groupId: string, accountIds: string[], role: GroupRole) => { const response = await client.request(`/api/v1/groups/${groupId}/promote`, { method: 'POST', params: { account_ids: accountIds, role }, }); return v.parse(filteredArray(groupMemberSchema), response.json); }, /** demote one or more accounts to role `new_role`. Returns an error unless every of the target account has a strictly lower role than the user (you cannot demote someone with the same role as you), or if any target account already has a role lower than `new_role`. Valid roles are `admin`, `moderator` and `user`. */ demoteGroupUsers: async (groupId: string, accountIds: string[], role: GroupRole) => { const response = await client.request(`/api/v1/groups/${groupId}/demote`, { method: 'POST', params: { account_ids: accountIds, role }, }); return v.parse(filteredArray(groupMemberSchema), response.json); }, getGroupRelationships: async (groupIds: string[]) => { const response = await client.request('/api/v1/groups/relationships', { params: { id: groupIds }, }); return v.parse(filteredArray(groupRelationshipSchema), response.json); }, }, }; return category; }; export { experimental };