Skip to content

Commit

Permalink
add /crosspost command
Browse files Browse the repository at this point in the history
  • Loading branch information
Pukimaa committed May 19, 2024
1 parent ccdd5d7 commit aa9628f
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/wicked-flowers-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tako": minor
---

Added a /crosspost command that automatically publishes messages in an announcement channel.
44 changes: 44 additions & 0 deletions apps/docs/src/content/docs/en/commands/utility/crosspost.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Crosspost
description: |
A reference page for the '/crosspost' command inside the Tako Discord app.
With '/crosspost', you can setup the app to automatically publish all messages in an announcement channel.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Badge from '@astrojs/starlight/components/Badge.astro';

With `/crosspost`, you can setup the app to automatically publish all messages in an announcement channel.

## Usage

<Tabs>
<TabItem label="Slash Commands">
`/crosspost [channel] [state]`

**Example**:
`/crosspost channel:#news state:true` will enable crossposting for the `#news` channel.
</TabItem>
</Tabs>

## Permissions

In order to use the `/crosspost` subcommands, you need the `Manage Channels` & `Manage Messages` permisions.
:::tip
You can change the permisions via `Server Settings > Integrations > Tako` in your Discord server.
:::

## Options

<Tabs>
<TabItem label="Channel">
<Badge text="Default: The channel you executed the command from" />
The channel to set the state of whether the app should automatically publish all new messages from or not.

Needs to be an announcement channel!
</TabItem>
<TabItem label="State">
<Badge text="Default: The opposite of the current state, otherwise true" />
If set to `true`, the app will automatically publish all new messages from the channel. Otherwise, it will stop automatically publishing messages.
</TabItem>
</Tabs>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Channel" ADD COLUMN "crosspost" BOOLEAN NOT NULL DEFAULT false;
5 changes: 3 additions & 2 deletions apps/tako/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ model Guild {
}

model Channel {
id String @id @unique
stickyEmbed Boolean @default(false)
id String @id @unique
stickyEmbed Boolean @default(false)
stickyMessage String?
autoReact String[] @default([])
crosspost Boolean @default(false)
}

model Badge {
Expand Down
143 changes: 143 additions & 0 deletions apps/tako/src/commands/utility/crosspost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import type { ChatInputCommandInteraction } from 'discord.js';
import {
ChannelType,
PermissionFlagsBits,
SlashCommandBuilder,
} from 'discord.js';
import config from '../../../config.ts';
import prisma from '../../database.ts';
import i18next from '../../i18n.ts';
import {
createEmbed,
getLanguage,
slashCommandTranslator,
} from '../../util/general.ts';
import type { Command } from '../index.ts';

export default {
data: new SlashCommandBuilder()
.setName(i18next.t('crosspost.name', { ns: 'utility' }))
.setNameLocalizations(slashCommandTranslator('crosspost.name', 'utility'))
.setDescription(i18next.t('crosspost.description', { ns: 'utility' }))
.setDescriptionLocalizations(
slashCommandTranslator('crosspost.description', 'utility'),
)
.addChannelOption((option) =>
option
.setName(i18next.t('crosspost.options.channel.name', { ns: 'utility' }))
.setNameLocalizations(
slashCommandTranslator('crosspost.options.channel.name', 'utility'),
)
.setDescription(
i18next.t('crosspost.options.channel.description', { ns: 'utility' }),
)
.setDescriptionLocalizations(
slashCommandTranslator(
'crosspost.options.channel.description',
'utility',
),
)
.addChannelTypes(ChannelType.GuildAnnouncement),
)
.addBooleanOption((option) =>
option
.setName(i18next.t('crosspost.options.state.name', { ns: 'utility' }))
.setNameLocalizations(
slashCommandTranslator('crosspost.options.state.name', 'utility'),
)
.setDescription(
i18next.t('crosspost.options.state.description', { ns: 'utility' }),
)
.setDescriptionLocalizations(
slashCommandTranslator(
'crosspost.options.state.description',
'utility',
),
),
)
.setDefaultMemberPermissions(
PermissionFlagsBits.ManageChannels | PermissionFlagsBits.ManageMessages,
)
.setDMPermission(false)
.toJSON(),
async execute(interaction: ChatInputCommandInteraction) {
const channel =
interaction.options.getChannel('channel') ?? interaction.channel;
const existingData = await prisma.channel.findFirst({
where: { id: channel?.id },
select: { crosspost: true },
});
const state =
interaction.options.getBoolean('state') ??
!existingData?.crosspost ??
true;
const lng = await getLanguage(
interaction.guildId,
interaction.user.id,
true,
);

if (channel?.type !== ChannelType.GuildAnnouncement) {
await interaction.reply({
embeds: [
createEmbed({
color: config.colors.red,
description: i18next.t(
'crosspost.errors.invalidChannel.description',
{
ns: 'utility',
lng,
},
),
emoji: config.emojis.error,
title: i18next.t('crosspost.errors.invalidChannel.title', {
ns: 'utility',
lng,
}),
}),
],
ephemeral: true,
});
return;
}

await prisma.channel.upsert({
where: { id: channel.id },
create: {
id: channel.id,
crosspost: state,
},
update: {
crosspost: state,
},
});

await interaction.reply({
embeds: [
createEmbed({
color: state ? config.colors.green : config.colors.red,
description: i18next.t(
'crosspost.success' +
(state ? '.enabled' : '.disabled') +
'.description',
{
ns: 'utility',
lng,
channel: channel.id,
},
),
emoji: state ? config.emojis.success : config.emojis.error,
title: i18next.t(
'crosspost.success' + (state ? '.enabled' : '.disabled') + '.title',
{
ns: 'utility',
lng,
channel: channel.id,
},
),
}),
],
ephemeral: true,
});
},
} satisfies Command;
13 changes: 13 additions & 0 deletions apps/tako/src/events/messageCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ import type { Event } from './index.ts';
export default {
name: Events.MessageCreate,
async execute(message) {
// Crosspost
if (message.channel.type === ChannelType.GuildAnnouncement) {
const data = await prisma.channel.findFirst({
where: { id: message.channelId },
select: { crosspost: true },
});

if (data?.crosspost) {
await message.crosspost();
}
}

// Auto-react
const isForum =
message.channel.isThread() &&
(message.channel.parent?.type === ChannelType.GuildForum ||
Expand Down
30 changes: 30 additions & 0 deletions apps/tako/src/locales/en/utility.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,5 +202,35 @@
"description": "Whether or not to send the translation as an ephemeral message"
}
}
},
"crosspost": {
"name": "crosspost",
"description": "Automatically publish all messages in an announcement channel",
"options": {
"channel": {
"name": "channel",
"description": "The channel to publish all messages from"
},
"state": {
"name": "state",
"description": "Whether or not to enable crossposting"
}
},
"success": {
"enabled": {
"title": "Enabled Crossposting",
"description": "All new messages from <#{{channel}}> will now be automatically published."
},
"disabled": {
"title": "Disabled Crossposting",
"description": "All new messages in <#{{channel}}> will no longer be automatically published."
}
},
"errors": {
"invalidChannel": {
"title": "Invalid Channel",
"description": "The channel you provided is not an announcement channel. Please provide a valid announcement channel!"
}
}
}
}

0 comments on commit aa9628f

Please sign in to comment.