From ec61a23a73b178997841355651acc63db103a288 Mon Sep 17 00:00:00 2001 From: Colin Loretz Date: Mon, 11 Sep 2023 19:34:10 +0000 Subject: [PATCH] Added localized Getting Started guides --- docs/Getting_Started.mdx | 2 + docs/da/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ docs/de/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ docs/fr/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ docs/ja/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ docs/nl/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ docs/pl/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ docs/pt-br/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ docs/tr/Getting_Started.mdx | 487 +++++++++++++++++++++++++++++++++ 9 files changed, 3898 insertions(+) create mode 100644 docs/da/Getting_Started.mdx create mode 100644 docs/de/Getting_Started.mdx create mode 100644 docs/fr/Getting_Started.mdx create mode 100644 docs/ja/Getting_Started.mdx create mode 100644 docs/nl/Getting_Started.mdx create mode 100644 docs/pl/Getting_Started.mdx create mode 100644 docs/pt-br/Getting_Started.mdx create mode 100644 docs/tr/Getting_Started.mdx diff --git a/docs/Getting_Started.mdx b/docs/Getting_Started.mdx index 18425b34b0..9933140fac 100644 --- a/docs/Getting_Started.mdx +++ b/docs/Getting_Started.mdx @@ -1,3 +1,5 @@ + + # Building your first Discord app Discord apps let you customize and extend your servers using a collection of APIs and interactive features. This guide will walk you through building your first Discord app using JavaScript, and by the end you'll have an app that uses slash commands, sends messages, and responds to component interactions. diff --git a/docs/da/Getting_Started.mdx b/docs/da/Getting_Started.mdx new file mode 100644 index 0000000000..e947b6f4ab --- /dev/null +++ b/docs/da/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Sådan udvikler du din første Discord-app + +Discord-apps lader dig tilpasse og udvide dine servere med en samling af APIs og interaktive funktioner. Denne vejledning tager dig gennem processen at udvikle din første Discord-app i JavaScript. Når du er færdig, vil du have en app, der bruger slash-kommandoer, sender beskeder og reagerer på interaktion med komponenterne. + +Vi vil udvikle en Discord-app, der lader servermedlemmerne spille sten-saks-papir (med syv valgmuligheder i stedet for de sædvanlige tre). Denne vejledning er målrettet nybegyndere, men den antager et basalt kendskab til [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Her kan du se, hvordan den færdige app vil se ud: + +![Demo af app-eksempel](getting-started-demo.gif) + +Lad os gøre brugerrejsen lidt mere tydelig: + +1. Bruger 1 starter et nyt spil og vælger deres genstand med appens `/challenge` slash-kommando +2. En besked bliver sendt til kanalen med en knap, så andre kan acceptere udfordringen +3. Bruger 2 trykker på knappen **Acceptér** +4. Bruger 2 modtager en kortvarig besked, hvorfra vedkommende skal vælge sin genstand +5. Resultatet af spillet bliver delt i den oprindelige kanal, hvor alle kan se det + + + +- **[GitHub repository](https://github.com/discord/discord-example-app)**, hvor koden fra denne vejledning bor sammen med nogle ekstra funktionsspecifikke kodeeksempler. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, et bibliotek med typer og hjælpefunktioner til Discord-apps. +- **[Express](https://expressjs.com)**, et populært JavaScript-web framework vi bruger til at oprette en server, hvor Discord kan sende os anmodninger. +- **[Glitch](https://glitch.com/)**, et online miljø, der simplificerer udviklingen og hostingen af apps i de tidlige prototype- og udviklingsfaser. Du kan ogås udvikle lokalt med et værktøj som **[ngrok](https://ngrok.com/)**. + + +--- + +## Step 1: Skab en app + +Først skal du skabe en app i udviklerportalen, hvis du ikke allerede har en: + + + +Navngiv din app, og tryk på **Skab**. + +Når du har skabt din app, lander du på siden **Generel oversigt** i appens indstillinger, hvor du kan opdatere grundlæggende information om din app såsom beskrivelse og ikon. Du kan også se et **applikations-ID** og en **URL for slutpunkt for interaktioner**, som vi skal bruge lidt senere i denne vejledning. + +### Konfigurering af din bot + +Derefter konfigurerer vi [bot-brugeren](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) for din app, så den kan se ud som og opføre sig ligesom andre medlemmer af serveren. + +I sidepanelet til venstre skal du klikke på **Bot**. På denne side kan du konfigurere indstillinger som dens [priviligerede intentioner](#DOCS_TOPICS_GATEWAY/privileged-intents), eller om den kan installeres af andre brugere. + + +Intentioner bestemmer, hvilke hændelser Discord sender din app til, når du laver en [Gateway API-forbindelse](#DOCS_TOPICS_GATEWAY). Hvis du eksempelvis vil have din app til at gøre noget, når brugere føjer en reaktion til en besked, kan du sende `GUILD_MESSAGE_REACTIONS` (`1 << 10`)-intentionen. + +Nogle intentioner er [privilegerede](#DOCS_TOPICS_GATEWAY/privileged-intents), hvilket betyder, at de lader din app tilgå data, der kan være følsomme (såsom indholdet af beskeder). Privilegerede intentioner findes og kan styres på siden **Bot** i din apps indstillinger. Standard, ikke-privilegerede intentioner kræver ingen yderligere tilladelser eller konfigurationer. + +Du finder mere information om intentioner sammen med en liste over alle intentioner, inkl. deres tilknyttede hændelser i [Gateway-dokumentationen](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Bot-fanen i appens indstillinger](app-add-bot.png) + +Der er også en **Token**-sektion på siden **Bot**, der lader dig kopiere og nulstille din bots token. + +Bot-tokens bruges til at godkende API-anmodninger og bære din bot-brugers tilladelser, hvilket gør dem *meget følsomme*. Sørg for *ikke* at dele din token eller bruge den til nogen form for versionskontrol. + +Kopier nu din token, og gem den et sikkert sted (såsom i en administrator af adgangskoder). + +> warn +> Du vil ikke kunne se din token igen, medmindre du regenererer den, så sørg for at opbevare den et sikkert sted. + +### Tilføjelse af anvendelsesområder og bot-tilladelser + +Apps skal bruge godkendelse fra den installerende bruger for at udføre handlinger i Discord (såsom at lave en slash-kommando eller hente en liste over servermedlemmer). Lad os vælge et par anvendelsesområder og tilladelser, der skal anmodes om, inden appen bliver installeret. + + +Når du laver en app, bestemmer anvendelsesområder og tilladelser, hvad din app kan gøre og få tilgang til på Discord-servere. + +- [OAuth2-anvendelsesområder](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) bestemmer, hvilken dataadgang og hvilke handlinger din app har adgang til, tildelt på vegne af en installerende eller bekræftende bruger. +- [Tilladelser](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) er din bot-brugers detaljerede tilladelser, ligesom andre brugere på Discord også har. De kan godkendes af den installerende bruger eller senere opdateres under serverens indstillinger eller med [overskrivninger af tilladelser](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Klik på **OAuth2** i venstre sidepanel, og vælg **URL-generator**. + +> info +> URL-generatoren skaber et installationslink baseret på de anvendelsesområder og tilladelser, du har valgt for din app. Du kan bruge linket til at installere appen på din egen server eller dele det med andre, så de kan installere den. + +Lige nu skal du tilføje to anvendelsesområder: +- `applications.commands`, der lader din app skabe [kommandoer](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot`, der tilføjer din bot-bruger. Når du har valgt `bot`, kan du også vælge forskellige tilladelse til din bot. Lige nu skal du bare afkrydse **Send meddelelser**. + +Se en liste med alle [OAuth2-anvendelsesområder](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes), eller læs mere om [tilladelser](#DOCS_TOPICS_PERMISSIONS) i dokumentationen. + +### Installation af din app + +Når du har tilføjet anvendelsesområder, burde du se en URL, som du kan kopiere og bruge til at installere din app. + +![Screenshot af URL-generator](url-generator.png) + +> info +> Når du udvikler apps, bør du bygge og teste dem på en server, der ikke bruges aktivt af andre. Hvis du ikke har din egen server allerede, kan du [oprette en gratis](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Kopiér den førnævnte URL, og indsæt den i din browser. Du bliver ført gennem installationsprocessen, hvor du skal sikre, at du installerer din app på en server, hvor du kan udvikle på den og teste den. + +Når du har installeret din app, kan du gå til din server og se, at den har tilsluttet sig ✨ + +Nu da din app er konfigureret og installeret, kan vi begynde at udvikle på den. + +--- + +## Trin 2: Kør din app + +Al koden brugt i app-eksemplet kan findes i [GitHub repository](https://github.com/discord/discord-example-app). + +For at gøre det lidt nemmere at udvikle appen, bruger den [Discord-interaktioner](https://github.com/discord/discord-interactions-js), der leverer typer og hjælpefunktioner. Hvis du foretrækker at anvende andre sprog eller biblioteker, skal du se dokumentationen om [Community-ressourcer](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remix af projektet + +Denne vejledning bruger Glitch, der lader dig klone og udvikle inde i din browser. Hvis du foretrækker at udvikle din app lokalt, er der en vejledning i at bruge ngrok [i README](https://github.com/discord/discord-example-app#running-app-locally). + +> info +> Glitch er fantastisk til udvikling og test, men [den har nogle tekniske begrænsninger](https://help.glitch.com/kb/article/17-technical-restrictions/), så du bør overveje andre hosting-udbydere til produktions-apps. + +Begynd med at **[remixe (eller klone) Glitch-projektet 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Når du har remixet projektet, lander du på et nyt Glitch-projekt. + + +![Glitch-projektoversigt](glitch-project.png) + +- Dit **project name** er et unikt navn på dit projekt, der kan ses i øverste venstre hjørne +- **`.env`** er filen, hvor alle legitimationsoplysninger for din app bliver gemt +- **Logs** er stedet, hvor dit projekts output kan findes – det er nyttigt for at se, om appen kører, samt information om fejl, din app støder på +- **Share**-knappen i øverste, højre hjørne er stedet, hvor du finder det live projekts URL, som du skal bruge til at opsætte interaktivitet senere i denne vejledning + + +#### Projektstruktur + +Alle projektets filer er på venstre side af dit Glitch-projekt. Herunder er der en oversigt over hovedmapperne og filerne: + +``` +├── examples -> korte, funktionsspecifikke app-prøveeksemplarer +│ ├── app.js -> færdig app.js kode +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> dine legitimationsoplysninger og ID'er +├── app.js -> primært entrypoint for app +├── commands.js -> slash-kommandonyttelaster + hjælpere +├── game.js -> logik specifik til RPS +├── utils.js -> utility-funktioner og enums +├── package.json +├── README.md +└── .gitignore +``` + +### Tilføj legitimationsoplysninger + +Der er allerede noget kode i din `app.js`-fil, men du skal bruge din apps token og ID for at lave anmodninger. Alle dine legitimationsoplysninger kan blive gemt direkte i `.env`-filen. + +Først skal du kopiere din bot-brugers token fra tidligere og indsætte den i **`DISCORD_TOKEN`**-variablen i din `.env`-fil. + +Derefter skal du gå til siden **Generel oversigt** i din app og derefter kopiere dens **App ID** og **Public Key**. Indsæt værdierne i din `.env`-fil som **`APP_ID`** og **`PUBLIC_KEY`**. + +Nu da dine legitimationsoplysninger er konfigureret, så lad os installere og håndtere slash-kommandoer. + +### Installér slash-kommandoer + +> info +> For at installere slash-kommandoer benytter appen [`node-fetch`](https://github.com/node-fetch/node-fetch). Du kan se implementeringen af installationen i `utils.js` i `DiscordRequest()`-funktionen. + +Projektet indeholder et `register`-script, du kan bruge til at installere kommandoerne i `ALL_COMMANDS`, der er defineret i bunden af `commands.js`. Det installerer kommandoerne som globale kommandoer ved at kalde HTTP API'ens [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) endpoint. + +Hvis du ønsker at tilpasse dine kommandoer eller tilføje ekstra kommandoer, kan du refererer kommandostrukturen i [kommandodokumentationen](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Kør `register`-scriptet ved at klikke på **Terminal** i bunden af dit Glitch-projekt og indsætte følgende kommando: + +``` +npm run registrer +``` + +Tryk på enter for at køre kommandoen. + +Hvis du går tilbage til din server, bør du nu se slash-kommandoerne. Men hvis du prøver at køre dem, sker der ikek noget, da din app ikke modtager eller håndterer nogen anmodninger fra Discord. + + +Discord har to API's som du frit kan vælge mellem og blande, når du laver apps: + +- **[HTTP API](#DOCS_REFERENCE/http-api)** er en REST-lignende API til generelle operationer som at sende og opdatere data i Discord eller hente data om en ressource. +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)** er en WebSocket-baseret API, der er nyttig til at beholde en tilstand eller lytte til begivenheder på en Discord-server. Vi benytter den ikke i denne vejledning, men du kan finde mere information om, hvordan du skaber en Gateway-forbindelse, samt de forskellige begivenheder, du kan lytte efter, i [Gateway-dokumentationen](#DOCS_TOPICS_GATEWAY). + + +--- + +## Trin 3: Håndtering af interaktivitet + +For at gøre din app i stand til at modtage slash-kommandoanmodninger (og andre interaktioner) skal Discord bruge en offentlig URL for at sende dem. Denne URL kan konfigureres i din apps indstillinger som **slutpunkt for interaktioner**. + +### Tilføj en URL for et slutpunkt for interaktioner + +Glitch-projekter har en offentlig URL, der som standard er synlig. Kopiér dit projekts URL ved at klikke på knappen **Del** i øverste, højre hjørne, og kopiér så "Live site"-projektlinket nær bunden af modalen. + +> info +> Hvis du udvikler lokalt, er der instrukser til at føre dine anmodninger til dit lokalmiljø [i GitHub README](https://github.com/discord/discord-example-app#running-app-locally). + +Når du har kopieret linket, skal du gå til din apps indstillinger fra [udviklingsportalen](https://discord.com/developers/applications). + +På din apps side med **Generel information** er der en instilling for **URL for slutpunkt for interaktioner**, hvor du kan indsætte din apps URL og hægte `/interactions` på den, og det er her, Express-appen konfigureres til at lytte efter anmodninger. + +![URL for slutpunkt for interaktioner i app-indstillinger](interactions-url.png) + +Klik på **Gem ændringer**, og sørg for, at dit slutpunkt er korrekt bekræftet. + +App-eksemplet håndterer bekræftelse på to måder: +- Den bruger `PUBLIC_KEY` og [discord-interaktionspakken](https://github.com/discord/discord-interactions-js#usage) med en wrapper-funktion (importeret fra `utils.js`), der gør, at den passer til [Express' `verify`-brugerflade](http://expressjs.com/en/5x/api.html#express.json). Den køres på alle indkommende anmodninger på din app. +- Den besvarer indkommende `PING`-anmodninger. + +Du kan lære mere om at forberede din app til at modtage interaktioner i [interaktionsdokumentationen](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Håndtering af slash-kommandoanmodninger + +Når slutpunktet er bekræftet, skal du gå til dit projekts `app.js`-fil og finde kodeblokken, der håndterer `/test`-kommandoen: + +```javascript +// "test"-kommando +if (name === 'test') { + // Send en besked i kanalen, hvor kommandoen blev udløst + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Henter en tilfældig emoji, der sendes fra en hjælpefunktion + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Koden herover reagerer på interaktionen med en besked i kanalen, hvor kommandoen kom fra. Du kan se alle tilgængelige svartyper såsom besvarelse med en modal [i dokumentationen](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` er en konstant, der er [eksporteret fra `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Gå til din server, og sørg for, at din apps `/test` slash-kommando fungerer. Når du udløser den, burde din app sende en besked, der indeholder teksten “hello world” efterfulgt af en tilfældig emoji. + +I den følgende sektion tilføjer vi en ekstra kommando, der benytter slash-kommandoerindstillinger, knapper og valgmuligheder til at bygge sten-saks-papir-spillet. + +--- + +## Trin 4: Tilføj beskedkomponenter + +`/challenge`-kommandoen er måden, vores sten-saks-papir-spil bliver startet. Når kommandoen udløses, sender appen beskedkomponenter til kanalen, der hjælper brugerne med at fuldføre spillet. + +### Tilføj en kommando med valgmuligheder + +`/challenge`-kommandoen, kaldet `CHALLENGE_COMMAND` i `commands.js`, har en række `options`. I vores app er de forskellige options objekter, der repræsenterer forskellige ting, en bruger kan vælge mellem i et spil sten-saks-papir, genereret ved brug af nøgler for `RPSChoices` i `game.js`. + +Du kan læse mere om kommando-valgmuligheder og deres struktur [i dokumentationen](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> Selvom denne vejledning ikke går i dybden med `game.js`-filen, er du velkommen til at grave lidt rundt og ændre kommandoerne eller valgmulighederne i kommandoerne. + + + +For at håndtere `/challenge`-kommandoen skal du føje følgende kode efter hvis-blokken `if name === “test”`: + +```javascript +// "challenge"-kommando +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Brugers genstandsvalg + const objectName = req.body.data.options[0].value; + + // Skab aktivt spil med besked-ID som spil-ID + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Tilføj spil-ID til senere brug + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Hvis du ikke er sikker på, hvor du skal indsætte koden, kan du se den fulde kode i `examples/app.js` i Glitch-projektet eller i roden `app.js` [på GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +Koden herover gør et par forskellige ting: +1. Parser anmodningsdataen for at få ID på brugeren, der udløste slash-kommandoen (`userId`), og valget (genstandsvalg) de traf (`objectName`). +2. Tilføjer et nyt spil til `activeGames`-objektet med interaktions-ID'et. Det aktive spil noterer `userId` og `objectName`. +3. Sender en besked tilbage til kanalen med en knap med et `custom_id` på `accept_button_`. + +> warn +> Kodeeksemplet bruger et objekt som in-memory lagring, men for produktionsapps bør du bruge en database. + +Når der sendes en besked med [beskedkomponenter](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component), tilføjes den individuelle nyttelast til et `components`-sæt. Anvendelige komponenter (såsom knapper) skal være i en [handlingsrække](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), som du kan se kodeeksemplet. + +Bemærk det unikke `custom_id`, der blev sendt med beskedkomponenterne, i dette tilfælde `accept_button_` med det aktive spils ID tilføjet. Et `custom_id` kan bruges til at håndtere anmodninger, som Discord sender dig, når nogen interagerer med komponenten, som du vil få at se om et øjeblik. + +Når du nu kører `/challenge`-kommandoen og vælger en valgmulighed, vil din app sende en besked med en **Accept**-knap. Lad os tilføje koden, der håndtere tryk på knappen. + + + + + +Når brugere interagerer med en beskedkomponent, sender Discord en anmodning med [interaktionstypen](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (eller `MESSAGE_COMPONENT`-værdien, når der anvendes `discord-interactions`). + +For at sætte en handler op for knappen tjekker vi interaktionens `type`, efterfulgt af en matching af `custom_id`. + +Indsæt følgende kode under type-handleren for `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id valg i nyttelast ved afsendelse af beskedkomponent +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // hent det tilhørende spil-ID + const gameId = componentId.replace('accept_button_', ''); + // Slet besked med token i anmodningskroppen + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Henter en tilfældig emoji, der sendes fra en hjælpefunktion + content: 'What is your object of choice?', + // Indikerer, at det bliver en kortvarig besked + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Tilføj spil-ID + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Slet forrige besked + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Koden herover: +1. Tjekker efter et `custom_id`, der matcher det, vi oprindeligt sendte (i dette tilfælde starter det med `accept_button_`). Custom-ID har også det aktive spil-ID tilføjet, så vi gemmer det i `gameID`. +2. [Sletter den oprindelige besked](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) ved at kalde en webhook med `node-fetch` og sende den unikke interaktions-`token` i anmodningens krop. Dette gøres for at rydde op i kanalen og for at forhindre, at andre brugere kan klikke på knappen. +3. Besvarer anmodningen ved at sende en besked, der indeholder en menu med valgmuligheder med genstandene i spillet. Nyttelasten bør se ud ligesom den forrige med undtagelse af `options`-sættet og `flags: 64`, [der indikerer, at beskeden er kortvarig](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +`options`-sættet befolkes ved hjælp af `getShuffledOptions()`-metoden i `game.js`, der manipulerer `RPSChoices`-værdierne, så de passer til formen på [beskedkomponentvalgene](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +Til slut skal vi tilføje kode, der håndterer interaktion med menuer med valgmuligheder og sender spillets resultat til kanalen. + +Da menuer med valgmuligheder blot er endnu en beskedkomponent, er koden, der håndterer deres interaktioner, næsten identisk med den for knapper. + +Modificér koden ovenfor, så den kan håndtere menuer med valgmuligheder: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id valg i nyttelast ved afsendelse af beskedkomponent +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // hent det tilhørende spil-ID + const gameId = componentId.replace('accept_button_', ''); + // Slet besked med token i anmodningskroppen + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Henter en tilfældig emoji, der sendes fra en hjælpefunktion + content: 'What is your object of choice?', + // Indikerer, at det bliver en kortvarig besked + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Tilføj spil-ID + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Slet forrige besked + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // hent det tilhørende spil-ID + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Hent bruger-ID og valgt genstand for besvarende bruger + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Beregn resultatet fra hjælpefunktion + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Fjern spil fra lager + delete activeGames[gameId]; + // Opdatér besked med token i anmodningskroppen + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Send resultater + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Opdatér kortvarig besked + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Ligesom med tidligere kode henter koden herover bruger-ID'et og deres valg af genstand fra interaktionsanmodningen. + +Den information, sammen med den oprindelige brugers ID og valg fra `activeGames`-objektet, sendes til `getResult()`-funktionen. `getResult()` bestemmer vinderen og bygger en læselig tekst, der sendes tilbage til kanalen. + +Vi kalder også en anden webhook, denne gang for at [opdater den opfølgende kortvarige besked](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), siden den ikke kan slettes. + +Endelig sendes resultatet til kanalen med `CHANNEL_MESSAGE_WITH_SOURCE`-interaktionssvartypen. + + + +... og det var det 🎊 Test din app for at sikre, at alt virker. + +--- + +## Næste skridt + +Tillykke, du har skabt din første Discord-app! 🤖 + +Forhåbentlig har du lært en smule om Discord-apps, hvordan du konfigurerer dem, og hvordan du gør dem interaktive. Herfra kan du fortsætte med at udvikle din app, eller du kan udforske, hvad der ellers kan lade sig gøre: +- Læs **[dokumentationen](#DOCS_INTRO)** for dybdegående information om API-funktioner +- Kig i `examples/`-mappen i dette projekt for mindre, funktionsspecifikke kodeeksempler +- Se vores **[community-ressourcer](#DOCS_TOPICS_COMMUNITY_RESOURCES)** for sprogspecifikke redskaber, leveret af medlemmer af fællesskabet +- Læs vores vejledning om at [hoste Discord-apps på Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Slut dig til **[Discord Developers-serveren](https://discord.gg/discord-developers)** for at stille spørgsmål om API'en, deltag i begivenheder afholdt af Discord API-teamet, og interagér med andre udviklere diff --git a/docs/de/Getting_Started.mdx b/docs/de/Getting_Started.mdx new file mode 100644 index 0000000000..c924177434 --- /dev/null +++ b/docs/de/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Erstellen deiner ersten eigenen Discord-App + +Discord-Apps ermöglichen dir die Anpassung und Erweiterung deines Servers mithilfe einer Reihe von APIs und interaktiven Features. Diese Anleitung führt dich durch die Erstellung deiner ersten Discord-App mit JavaScript. Das Ergebnis ist eine App, die Slash-Befehle verwendet, Nachrichten sendet und auf Interaktionen mit Komponenten reagiert. + +Wir werden eine Discord-App erstellen, mit der Servermitglieder Stein-Schere-Papier spielen können (mit 7 Wahlmöglichkeiten statt der üblichen 3). Diese Anleitung richtet sich an Anfänger, setzt aber ein grundlegendes Verständnis von [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics) voraus. + + +So wird die fertige App aussehen: + +![Demo der Beispiel-App](getting-started-demo.gif) + +Um den Spielablauf etwas besser zu erklären: + +1. Benutzer 1 startet ein neues Spiel und wählt mit dem Slash-Befehl `/challenge` ein Objekt. +2. Eine Nachricht wird an den Kanal geschickt. Sie enthält einen Button, der andere zum Annehmen der Herausforderung einlädt. +3. Benutzer 2 klickt auf den Button **Accept**. +4. Benutzer 2 erhält eine ephemerale (temporär verfügbare) Nachricht und kann dort selbst ein Objekt wählen. +5. Der Ausgang des Spiels wird im ursprünglichen Kanal für alle sichtbar gepostet. + + + +- **[Github-Repository](https://github.com/discord/discord-example-app)** mit dem Code für diese Anleitung sowie einigen weiteren Code-Beispielen für spezifische Features. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, eine Bibliothek mit Types und Helper-Funktionen für Discord-Apps +- **[Express](https://expressjs.com)**, ein beliebtes JavaScript-Web-Framework, mit dem wir einen Server erstellen werden, über den uns Discord Anfragen schicken kann. +- **[Glitch](https://glitch.com/)**, eine Online-Umgebung, die das Erstellen und Hosten von Apps während des Prototypings und der Entwicklung vereinfacht. Mit Tools wie **[ngrok](https://ngrok.com/)** kannst du auch lokal entwickeln. + + +--- + +## Schritt 1: Erstellung einer App + +Zuerst musst du im Entwicklerportal eine App erstellen, wenn du noch keine hast: + + + +Gib deiner App einen Namen und klick dann auf **Create**. + +Nachdem du deine App erstellt hast, landest du auf der Seite **General Overview** der Einstellungen für deine App, wo du grundlegende Informationen deiner App wie Beschreibung und Icon eingeben kannst. Außerdem siehst du eine **Application ID** und **Interactions Endpoint URL**, die wir später in diesem Guide benutzen werden. + +### Konfiguration deines Bots + +Als Nächstes konfigurieren wir den [Botbenutzer](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) für deine App, damit er wie andere Servermitglieder aussieht und handelt. + +Klick in der linken Seitenleiste auf **Bot**. Auf dieser Seite kannst du Einstellungen wie seine [Privileged Intents](#DOCS_TOPICS_GATEWAY/privileged-intents) festlegen, oder ob er von anderen Benutzern installiert werden kann. + + +Mit Intents wird festgelegt, welche Events Discord an deine App sendet, wenn du eine [Gateway-API-Verbindung](#DOCS_TOPICS_GATEWAY) erstellst. Wenn deine App zum Beispiel etwas tun soll, wenn Benutzer einer Nachricht eine Reaktion hinzufügen, kannst du den Intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`) vergeben. + +Manche Intents sind [Privileged](#DOCS_TOPICS_GATEWAY/privileged-intents), weil sie deiner App Zugriff auf Daten gewähren, die vertraulich sein können (wie der Inhalt von Nachrichten). Privileged Intents werden auf der **Bot**-Seite deiner App-Einstellungen angezeigt und können dort aktiviert oder deaktiviert werden. Alle anderen Intents, die nicht dazu zählen, werden Standard Intents genannt und benötigen keine zusätzlichen Berechtigungen oder Konfigurationen. + +Mehr Informationen zu Intents und eine Liste aller verfügbaren Intents mit ihren zugehörigen Events findest du in der [Dokumentation zu Gateways](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Bot-Tab in den App-Einstellungen](app-add-bot.png) + +Auf der **Bot**-Seite gibt es außerdem den Abschnitt **Token**, wo du das Token deines Bots kopieren und zurücksetzen kannst. + +Bot-Tokens werden benutzt, um API-Anfragen zu autorisieren und transportieren die Permissions (Berechtigungen) deines Botbenutzers, weshalb sie *streng vertraulich* sind. Du solltest dein Token *niemals* teilen oder in einer Versionskontrolle überprüfen. + +Kopiere es und speichere es an einem sicheren Ort (zum Beispiel einem Passwortmanager). + +> warn +> Stell sicher, dass du dein Token gut aufbewahrst. Du kannst es sonst nur sehen, indem du es erneut generierst. + +### Scopes und Bot Permissions hinzufügen + +Apps benötigen die Genehmigung von installierenden Benutzern, um Aktionen in Discord auszuführen (wie die Erstellung eines Slash-Befehls oder die Abfrage einer Liste von Servermitgliedern). Wählen wir ein paar Scopes und Permissions aus, bevor wir die App installieren. + + +Wenn du eine App erstellst, bestimmst du mit Scopes und Permissions, was deine App auf Discord-Servern tun und worauf sie zugreifen kann. + +- [OAuth2 Scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) legen den Datenzugriff und die möglichen Aktionen deiner App fest. Sie werden so von installierenden oder authentifizierenden Benutzern übernommen. +- [Permissions](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) sind die granularen Berechtigungen für deinen Botbenutzer, wie sie auch andere Discord-Benutzer haben. Sie können vom installierenden Benutzer gewährt oder später in den Servereinstellungen oder mit [Permission Overwrites](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) aktualisiert werden. + + +Klick auf **Oauth2** in der linken Seitenleiste und wähle dann **URL Generator**. + +> info +> Der URL Generator erstellt einen Installationslink basierend auf den Scopes und Permissions, die du für deine App auswählst. Du kannst den Link verwenden, um die App auf deinem eigenen Server zu installieren, oder ihn mit anderen teilen, damit sie die App installieren können. + +Füge vorerst zwei Scopes hinzu: +- `applications.commands` ermöglicht es deiner App, [Commands](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) (Befehle) zu erstellen. +- `bot` fügt deinen Botbenutzer hinzu. Nachdem du `bot` ausgewählt hast, kannst du auch verschiedene Permissions für deinen Bot festlegen. Wähle vorerst nur **Send Messages**. + +Es gibt eine Liste der [Oauth2 Scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) und du kannst in der Dokumentation mehr zu [Permissions](#DOCS_TOPICS_PERMISSIONS) lesen. + +### Installation deiner App + +Sobald du Scopes hinzugefügt hast, solltest du eine URL sehen, die du kopieren kannst, um deine App zu installieren. + +![Screenshot des URL Generators](url-generator.png) + +> info +> Wenn du Apps entwickelst, solltest du sie auf einem Server erstellen und testen, der nicht aktiv von anderen verwendet wird. Wenn du noch keinen eigenen Server hast, kannst du [kostenlos einen erstellen](https://support.discord.com/hc/de/articles/204849977-Wie-erstelle-ich-einen-Server-). + +Kopiere die oben erwähnte URL in deinen Browser. Du wirst durch den Installationsprozess geführt. Stell sicher, dass du die App auf einem Server installierst, wo du sie entwickeln und testen kannst. + +Nachdem du deine App installiert hast, kannst du auf deinen Server gehen und sehen, dass er beigetreten ist ✨ + +Deine App ist jetzt konfiguriert und installiert. Jetzt können wir sie entwickeln! + +--- + +## Schritt 2: Ausführen deiner App + +Der gesamte Code in der Beispiel-App ist im [Github-Repository](https://github.com/discord/discord-example-app) zu finden. + +Um die Entwicklung etwas zu vereinfachen, verwendet die App [discord-interactions](https://github.com/discord/discord-interactions-js) für Types und Helper-Funktionen. Wenn du andere Sprachen oder Bibliotheken bevorzugst, wirf einen Blick in die Dokumentation zu [Community Resources](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remixen des Projekts + +Diese Anleitung verwendet Glitch, das das Klonen und die Entwicklung im Browser ermöglicht. Wenn du deine App lieber lokal entwickeln willst, findest du [in der README](https://github.com/discord/discord-example-app#running-app-locally) eine Anleitung zur Verwendung von ngrok. + +> info +> Glitch eignet sich bestens zum Entwickeln und Testen, hat aber [technische Beschränkungen](https://help.glitch.com/kb/article/17-technical-restrictions/). Deshalb sollten für Apps in Anwendung andere Hosting-Anbieter gewählt werden. + +Beginne mit dem **[Remix (oder Klonen) des Glitch-Projekts 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Nach dem Remix des Projekts landest du in einem neuen Glitch-Projekt. + + +![Projektübersicht von Glitch](glitch-project.png) + +- Dein **Project Name** ist ein einzigartiger Name für dein Projekt, der in der oberen linken Ecke steht. +- **`.env`** ist die Datei, in der all deine Anmeldeinformationen für die App gespeichert werden. +- In den **Logs** findest du die Ausgabe deines Projekts – so kannst du sehen, ob die App funktioniert, und findest Informationen zu auftretenden Fehlern. +- Über den Button **Share** in der oberen rechten Ecke erhältst du die Live-URL des Projekts. Du benötigst sie später in dieser Anleitung, um die Interaktivität einzurichten. + + +#### Projektstruktur + +Alle Dateien für das Glitch-Projekt sind auf der linken Seite aufgeführt. Unten ist ein Überblick der Hauptordner und -dateien: + +``` +├── examples -> kurze Beispiel-Apps für spezifische Features +│ ├── app.js -> fertiger app.js-Code +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> deine Anmeldeinformationen und IDs +├── app.js -> Einsprungpunkt der App +├── commands.js -> Payloads + Helper für Slash-Befehle +├── game.js -> RPS-spezifische Logik +├── utils.js -> Dienstfunktionen und Enums +├── package.json +├── README.md +└── .gitignore +``` + +### Anmeldeinformationen hinzufügen + +Deine `app.js`-Datei enthält schon etwas Code, aber du benötigst Token und ID deiner App, um Anfragen zu stellen. Alle deine Anmeldeinformationen können direkt in der `.env`-Datei gespeichert werden. + +Kopier zuerst das Token deines Botbenutzers von vorhin und füg es in die Variable **`DISCORD_TOKEN`** deiner `.env`-Datei ein. + +Ruf dann die Seite **General Overview** deiner App auf und kopiere **App ID** und **Public Key**. Füg die Werte in deine `.env`-Datei als **`APP_ID`** und **`PUBLIC_KEY`** ein. + +Damit sind deine Anmeldeinformationen konfiguriert! Jetzt können wir Slash-Befehle installieren und einrichten. + +### Slash-Befehle installieren + +> info +> Um Slash-Befehle zu installieren, verwendet die App [`node-fetch`](https://github.com/node-fetch/node-fetch). Du kannst die Implementierung für die Installation in `utils.js` in der Funktion `DiscordRequest()` sehen. + +Das Projekt enthält ein `register`-Skript, das du benutzen kannst, um die Befehle in `ALL_COMMANDS` (am Ende von `commands.js`) zu installieren. Sie werden als globale Befehle installiert, indem der Endpunkt [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) der HTTP-API angefragt wird. + +Wenn du deine Befehle anpassen oder welche hinzufügen willst, kannst du den Abschnitt Command Structure in der [Dokumentation zu Befehlen](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) zu Rate ziehen. + +Führ das `register`-Skript aus, indem du am unteren Rand deines Glitch-Projekts auf **Terminal** klickst und den folgenden Befehl einfügst: + +``` +npm run register +``` + +Drück Enter, um den Befehl auszuführen. + +Wenn du jetzt wieder auf deinen Server gehst, solltest du die Slash-Befehle sehen. Aber wenn du sie ausführst, wird nichts passieren, denn deine App erhält noch keine Anfragen von Discord. + + +Discord hat zwei APIs, die du kombinieren kannst, um Apps zu erstellen: + +- **[HTTP API](#DOCS_REFERENCE/http-api)** ist eine REST-API für allgemeine Operationen wie das Senden und Aktualisieren von Daten in Discord oder die Abfrage von Daten zu einer Ressource. +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)** ist eine WebSocket-basierte API, mit deren Hilfe der Zustand beibehalten oder Events eines Discord-Servers „gehört“ werden können. Wir werden sie nicht in diesem Guide benutzen. Mehr Informationen zur Erstellung einer Gateway-Verbindung und zu den verschiedenen Events, die gehört werden können, findest du in der [Dokumentation zu Gateway](#DOCS_TOPICS_GATEWAY). + + +--- + +## Schritt 3: Bearbeiten der Interaktivität + +Damit deine App Anfragen über Slash-Befehle (und andere Interaktionen) erhalten kann, benötigt Discord eine öffentliche URL, um sie zu senden. Diese URL kann in deinen App-Einstellungen als **Interaction Endpoint URL** konfiguriert werden. + +### Hinzufügen einer Interaction Endpoint URL + +Glitch-Projekte haben standardmäßig eine öffentliche URL. Kopier die URL deines Projekts mit dem Button **Share** in der oberen rechten Ecke und kopiere dann den „Live Site“-Projektlink fast ganz unten im Modal. + +> info +> Wenn du lokal entwickelst, findest du [in der Github-README](https://github.com/discord/discord-example-app#running-app-locally) Anweisungen, wie du Anfragen in deine lokale Umgebung tunnelst. + +Begib dich mit dem kopierten Link in deine App-Einstellungen im [Entwicklerportal](https://discord.com/developers/applications). + +Auf der Seite **General Information** deiner App findest du die Option **Interactive Endpoint URL**, wo du die URL deiner App einfügen und `/interactions` (enthält die Konfiguration der Express-App, um Anfragen zu hören) anhängen kannst. + +![Interactions Endpoint URL in den App-Einstellungen](interactions-url.png) + +Klick auf **Save Changes** und überprüfe, ob dein Endpunkt erfolgreich verifiziert wurde. + +Die Beispiel-App geht auf zwei Arten mit Verifizierungen um: +- Sie verwendet den `PUBLIC_KEY` und [discord-interactions](https://github.com/discord/discord-interactions-js#usage) mit einer Wrapper-Funktion (aus `utils.js` importiert), um dem [`verify`-Interface von Express](http://expressjs.com/en/5x/api.html#express.json) zu entsprechen. Das wird bei jeder Anfrage ausgeführt, die bei der App eingeht. +- Sie reagiert auf eingehende `PING`-Anfragen. + +In der [Dokumentation zu Interactions](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction) kannst du mehr darüber erfahren, wie du deine App auf eingehende Interaktionen vorbereiten kannst. + +### Anfragen für Slash-Befehle bearbeiten + +Jetzt ist unser Endpunkt verifiziert. Öffne die Datei `app.js` deines Projekts und finde den Code-Block für den Befehl `/test`: + +```javascript +// "test"-Befehl +if (name === 'test') { + // sendet eine Nachricht an den Kanal, in dem der Befehl ausgelöst wurde + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ruft ein zufälliges Emoji von einer Helper-Funktion ab, das mitgesendet werden soll + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Der Code oben reagiert auf die Interaktion mit einer Nachricht in dem Kanal, wo sie ausgelöst wurde. [In der Dokumentation](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type) findest du alle verfügbaren Antworttypen, zum Beispiel mit einem Modal. + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` ist eine [aus `discord-interactions` exportierte](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) Konstante. + +Geh auf deinen Server und überprüfe, ob dein Slash-Befehl `/test` funktioniert. Wenn du ihn auslöst, sollte deine App eine Nachricht mit „hello world“ und einem zufälligen Emoji senden. + +Im folgenden Abschnitt fügen wir für unser Stein-Schere-Papier-Spiel einen weiteren Befehl hinzu, der Slash-Befehle, Buttons und Auswahlmenüs benutzt. + +--- + +## Schritt 4: Hinzufügen von Nachrichtenkomponenten + +Der Befehl `/challenge` wird unser Stein-Schere-Papier-Spiel beginnen. Wenn er ausgelöst wird, sendet die App Nachrichtenkomponenten an den Kanal, die den Benutzer zum Abschluss des Spiels führen. + +### Hinzufügen eines Befehls mit Optionen + +Der Befehl `/challenge` (zu finden in `commands.js` als `CHALLENGE_COMMAND`) hat eine Reihe von `options`. In unserer App sind das Objekte, die ein Benutzer auswählen kann, wenn er Stein-Schere-Papier spielt. Sie werden mit Keys von `RPSChoices` in `game.js` generiert. + +[In der Dokumentation](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure) kannst du mehr über Befehlsoptionen und ihre Struktur lesen. + +> info +> Diese Anleitung geht nicht weiter auf die Datei `game.js` ein, aber sieh sie dir ruhig an und ändere Befehle oder Optionen der Befehle. + + + +Füge den folgenden Code nach dem If-Block `if name === “test”` ein, um den Befehl `/challenge` zu bearbeiten: + +```javascript +// "challenge"-Befehl +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // gewähltes Objekt des Benutzers + const objectName = req.body.data.options[0].value; + + // erstellt aktives Spiel mit der ID der Nachricht als Spiel-ID + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // hängt die Spiel-ID für spätere Verwendung an + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Wenn du nicht sicher bist, wohin der Code kopiert werden muss, findest du den vollständigen Code auch in `examples/app.js` im Glitch-Projekt oder in der vollständigen `app.js` auf [Github](https://github.com/discord/discord-example-app/blob/main/app.js). + +Der obige Code erfüllt eine Reihe von Funktionen: +1. Er parst die Anfrage, um die ID des Benutzers, der den Slash-Befehl ausgelöst hat (`userId`), und seine gewählte Option (das gewählte `objectName`-Objekt) zu erhalten. +2. Er fügt dem Objekt `activeGames` ein neues Spiel mit der Interaktions-ID hinzu. Dort werden `userId` und `objectName` festgehalten. +3. Er sendet eine Nachricht zurück an den Kanal, die einen Button mit einer `custom_id` von `accept_button_` enthält. + +> warn +> Der Beispielcode verwendet In-Memory-Speicherung für das Objekt, aber für Apps in Anwendung solltest du eine Datenbank benutzen. + +Wenn eine Nachricht mit [Message Components](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) (Nachrichtenkomponenten) gesendet wird, werden die individuellen Payloads an ein `components`-Array angehängt. Ausführbare Komponenten (wie Buttons) müssen wie im Beispielcode in einer [Action Row](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows) sein. + +Wie du siehst, wird die einzigartige `custom_id` mit Nachrichtenkomponenten geschickt, in diesem Fall `accept_button_`, mit der angehängten ID des aktiven Spiels. Eine `custom_id` kann verwendet werden, um Anfragen von Discord zu bearbeiten, wenn jemand mit der Nachrichtenkomponente interagiert. Damit beschäftigen wir uns gleich. + +Wenn du jetzt den `/challenge`-Befehl ausführst und eine Option wählst, wird deine App eine Nachricht mit dem Button **Accept** senden. Also fügen wir jetzt den Code für das Betätigen dieses Buttons hinzu. + + + + + +Wenn Benutzer mit einer Message Component interagieren, sendet Discord eine Anfrage mit dem [Interaction Type](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (oder dem Wert von `MESSAGE_COMPONENT`, wenn `discord-interactions` verwendet wird). + +Für die Bearbeitung des Buttons prüfen wir den `type` der Interaktion, gefolgt vom Abgleich der `custom_id`. + +Kopier den folgenden Code unter die Type-Bearbeitung für `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id, die in der Payload beim Senden der Nachrichtenkomponente festgelegt wird +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // fragt die zugehörige Spiel-ID ab + const gameId = componentId.replace('accept_button_', ''); + // löscht Nachricht mit Token in der Anfrage + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ruft ein zufälliges Emoji von einer Helper-Funktion ab, das mitgesendet werden soll + content: 'What is your object of choice?', + // zeigt an, dass es eine ephemerale Nachricht sein wird + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // hängt Spiel-ID an + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // löscht vorherige Nachricht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Der obige Code: +1. Sucht nach einer `custom_id`, die mit unserer ursprünglich gesendeten übereinstimmt (in diesem Fall beginnt sie mit `accept_button_`). Diese ID hat auch die ID des aktiven Spiels angehängt, also speichern wir diese in `gameID`. +2. [Löscht die ursprüngliche Nachricht](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response), indem mit `node-fetch` ein WebHook aufgerufen und das einzigartige Interaktions-`token` in der Anfrage weitergegeben wird. Damit wird der Kanal aufgeräumt und andere Benutzer können den Button nicht anklicken. +3. Reagiert auf die Anfrage mit dem Senden einer Nachricht, die ein Auswahlmenü mit den Objekten für das Spiel enthält. Die Payload sollte der vorherigen sehr ähnlich sein, mit Ausnahme des `options`-Arrays und `flags: 64` ([zeigt an, dass die Nachricht ephemeral ist](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message)). + +Das `options`-Array wird mit der `getShuffledOptions()`-Methode in `game.js` befüllt, die die `RPSChoices`-Werte manipuliert, um sie an die Form von [Message Component Options](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure) anzupassen. + + + + + +Als Letztes müssen wir den Code hinzufügen, der die Interaktionen im Auswahlmenü bearbeitet und das Ergebnis des Spiels an den Kanal sendet. + +Da Auswahlmenüs nur eine weitere Nachrichtenkomponente sind, ist der Code für ihre Interaktionen beinahe identisch mit dem für Buttons. + +Modifiziere den obigen Code, um das Auswahlmenü zu bearbeiten: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id, die in der Payload beim Senden der Nachrichtenkomponente festgelegt wird +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // fragt die zugehörige Spiel-ID ab + const gameId = componentId.replace('accept_button_', ''); + // löscht Nachricht mit Token in der Anfrage + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ruft ein zufälliges Emoji von einer Helper-Funktion ab, das mitgesendet werden soll + content: 'What is your object of choice?', + // zeigt an, dass es eine ephemerale Nachricht sein wird + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // hängt Spiel-ID an + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // löscht vorherige Nachricht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // fragt die zugehörige Spiel-ID ab + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // fragt Benutzer-ID und gewähltes Objekt für antwortenden Benutzer ab + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // kalkuliert Ergebnis aus Helper-Funktion + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // entfernt Spiel aus Speicher + delete activeGames[gameId]; + // aktualisiert Nachricht mit Token in der Anfrage + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // sendet Ergebnis + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // aktualisiert ephemerale Nachricht + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Ähnlich wie der vorherige Code fragt dieser Code die Benutzer-ID und dessen ausgewähltes Objekt aus der Interaktionsanfrage ab. + +Diese Informationen sowie die ID des ursprünglichen Benutzers und seine Auswahl aus dem `activeGames`-Objekt werden an die `getResult()`-Funktion weitergegeben. Die `getResult()`-Funktion bestimmt den Sieger und erstellt einen lesbaren String, der zurück an den Kanal gesendet wird. + +Wir rufen außerdem einen weiteren WebHook auf, der dieses Mal [die ephemerale Nachricht aktualisiert](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), da sie nicht gelöscht werden kann. + +Am Ende wird das Ergebnis mit dem Interaction Response Type `CHANNEL_MESSAGE_WITH_SOURCE` an den Kanal gesendet. + + + +… und das war‘s 🎊 Jetzt kannst du deine App testen und prüfen, ob alles funktioniert. + +--- + +## Nächste Schritte + +Glückwunsch, du hast deine erste Discord-App erstellt! 🤖 + +Hoffentlich konntest du ein paar Dinge über die Erstellung, Konfiguration und Interaktivität von Discord-Apps lernen. Jetzt ist es an dir, deine App weiter zu gestalten oder zu entdecken, was noch möglich ist: +- Lies **[die Dokumentation](#DOCS_INTRO)** für detaillierte Informationen zu API-Features. +- Schau dir im `examples/`-Ordner dieses Projekts weitere kleinere Code-Beispiele für spezifische Features an. +- Entdecke die **[Community-Ressourcen](#DOCS_TOPICS_COMMUNITY_RESOURCES)** für sprachspezifische Tools von Community-Mitgliedern. +- Lies unser Tutorial zum [Hosten von Discord-Apps auf Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS). +- Tritt dem **[Server Discord Developers](https://discord.gg/discord-developers)** bei, um Fragen zur API zu stellen, an Events des API-Teams von Discord teilzunehmen und dich mit anderen Entwicklern auszutauschen. diff --git a/docs/fr/Getting_Started.mdx b/docs/fr/Getting_Started.mdx new file mode 100644 index 0000000000..24e6283ddd --- /dev/null +++ b/docs/fr/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Création de ta première application Discord + +Les applications Discord te permettent de personnaliser et d'étendre tes serveurs grâce à un ensemble d'API et de fonctions interactives. Ce guide t'aidera à créer ta première application Discord en employant JavaScript, et à la fin, tu disposeras d'une application qui utilise des commandes slash, envoie des messages et répond aux interactions avec des éléments. + +Nous allons créer une application Discord qui permet aux membres du serveur de jouer à pierre-feuille-ciseaux (avec 7 choix au lieu des 3 habituels). Ce guide s'adresse aux débutants, mais il nécessite une connaissance des bases de [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Voici à quoi ressemblera l'application : + +![Démo de l'exemple d'application](getting-started-demo.gif) + +Voici le flux utilisateur présenté de manière un peu plus explicite : + +1. L'utilisateur 1 lance une nouvelle partie et choisit son objet à l'aide de la commande slash `/defi` de l'application. +2. Un message est envoyé dans le salon avec un bouton invitant d'autres utilisateurs à relever le défi. +3. L'utilisateur 2 appuie sur le bouton **Accepter**. +4. L'utilisateur 2 reçoit un message éphémère qui lui permet de sélectionner l'objet de son choix. +5. Le résultat de la partie est posté dans le salon d'origine pour que tout le monde puisse le voir. + + + +- **[Dépôt GitHub](https://github.com/discord/discord-example-app)** où est stocké le code de ce guide ainsi que d'autres exemples de code aux fonctionnalités spécifiques. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, une bibliothèque qui fournit des types et des fonctions d'assistance pour les applications Discord. +- **[Express](https://expressjs.com)**, une infrastructure Web JavaScript populaire que nous allons utiliser pour créer un serveur où Discord peut nous envoyer les requêtes. +- **[Glitch](https://glitch.com/)**, un environnement en ligne qui simplifie la création et l'hébergement d'applications pendant les phases initiales de prototypage et de développement. Tu peux aussi développer en local avec un outil tel que **[ngrok](https://ngrok.com/)**. + + +--- + +## Étape 1 : création d'une application + +Pour commencer, tu dois créer une application sur le portail des développeurs si tu ne l'as pas déjà fait : + + + +Saisis un nom pour ton application, puis appuie sur **Créer**. + +Une fois ton application créée, tu arrives sur la page **Vue d'ensemble** de ses paramètres, où tu peux mettre à jour des informations de base relatives à ton application, telles que sa description et son icône. Tu y trouves également l'**identifiant de l'application** et l'**URL du point de terminaison des interactions**, qui nous serviront un peu plus loin dans le guide. + +### Configuration de ton bot + +Maintenant, nous allons configurer l'[utilisateur bot](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) pour ton application, ce qui lui permet d'apparaître et de se comporter de façon semblable aux autres membres du serveur. + +Dans l'encadré de gauche, clique sur **Bot**. Depuis cette page, tu peux configurer des paramètres tels que ses [privileged intents](#DOCS_TOPICS_GATEWAY/privileged-intents) ou déterminer si d'autres utilisateurs peuvent l'installer. + + +Les intents déterminent les événements que Discord envoie à ton application lorsque tu crées une [connexion d'API Gateway](#DOCS_TOPICS_GATEWAY). Par exemple, si tu souhaites que ton application fasse quelque chose lorsque des utilisateurs ajoutent une réaction à un message, tu peux utiliser l'intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`). + +Certains intents sont [privileged](#DOCS_TOPICS_GATEWAY/privileged-intents), ce qui signifie qu'ils permettent à ton application d'accéder à des données qui peuvent être considérées comme sensibles (comme le contenu des messages). Les privileged intent sont listés et peuvent être activés ou désactivés sur la page **Bot** dans les paramètres de ton application. Les standards intents, quant à eux, ne nécessitent aucune permission ou configuration supplémentaire. + +Tu peux obtenir plus d'informations sur les intents ainsi qu'une liste complète des intents disponibles, avec leurs événements associés, en consultant la [documentation de Gateway](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Onglet Bot dans les paramètres de l'application](app-add-bot.png) + +Il existe également une section **Token** sur la page **Bot**, qui permet de copier le token de ton bot et de le réinitialiser si besoin. + +Les tokens de bot servent à autoriser les requêtes d'API et portent les permissions de ton utilisateur bot, ce qui les rend *hautement sensibles*. Tu ne dois *jamais* partager ton token ou l'inclure dans un système de contrôle de version. + +Copie le token et garde-le dans un endroit sûr (par exemple, dans un gestionnaire de mots de passe). + +> warn +> Tu ne pourras plus voir ton token à moins d'en générer un nouveau, alors conserve-le dans un endroit sûr. + +### Ajout de champs d'application et de permissions de bot + +Les applications doivent être approuvées par les utilisateurs qui les installent afin d'effectuer des actions dans Discord (comme la création d'une commande slash ou la récupération d'une liste des membres du serveur). Sélectionnons quelques champs d'application et permissions à demander avant l'installation de l'application. + + +Lors de la création d'une application, les champs d'application et permissions déterminent ce que ton application peut faire et ce à quoi elle peut accéder sur les serveurs Discord. + +- Les [champs d'application OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) déterminent les accès aux données et actions que ton application peut effectuer. Elles sont accordées au nom de l'utilisateur qui procède à l'installation ou qui s'authentifie. +- Les [permissions](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) sont les permissions granulaires pour ton utilisateur bot, les mêmes que celles accordées aux autres utilisateurs dans Discord. Elles peuvent être approuvées par l'utilisateur qui procède à l'installation ou mises à jour ultérieurement dans les paramètres du serveur ou à l'aide d'[écrasements de permissions](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Clique sur **OAuth2** dans l'encadré de gauche, puis sélectionne **générateur d'URL**. + +> info +> Le générateur d'URL crée un lien d'installation en fonction des champs d'application et permissions que tu as sélectionnées pour ton application. Tu peux utiliser ce lien pour installer l'application sur ton propre serveur, ou le partager avec d'autres personnes pour leur permettre de l'installer. + +Pour l'instant, ajoute deux champs d'application : +- `applications.commands` qui permet à ton application de générer des [commandes](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot` ajoute ton utilisateur bot. Une fois que tu as sélectionné `bot`, tu peux également sélectionner différentes permissions pour ton bot. Pour l'instant, coche uniquement **Envoyer des messages**. + +Tu peux consulter une liste de tous les [champs d'application OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) ou en apprendre davantage sur les [permissions](#DOCS_TOPICS_PERMISSIONS) dans la documentation. + +### Installation de ton application + +Après avoir ajouté des champs d'application, tu devrais voir apparaître une URL que tu peux copier afin d'installer ton application. + +![Capture d'écran du générateur d'URL](url-generator.png) + +> info +> Pendant le développement d'une application, il est conseillé de la développer et de la tester sur un serveur qui n'est pas utilisé par d'autres personnes. Si tu ne disposes pas déjà de ton propre serveur, tu peux en [créer un gratuitement](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Copie l'URL générée précédemment, puis colle-la dans ton navigateur. Tu recevras des explications pour chaque étape du processus d'installation, au cours duquel tu devras vérifier que tu installes ton application sur un serveur qui te permettra de la développer et de la tester. + +Une fois ton application installée, tu peux te rendre sur ton serveur pour vérifier qu'elle a bien été intégrée ✨ + +Maintenant que ton application est configurée et installée, commençons son développement. + +--- + +## Étape 2 : exécution de ton application + +L'intégralité du code utilisé dans cet exemple d'application est disponible dans [le dépôt GitHub](https://github.com/discord/discord-example-app). + +Pour simplifier un peu le développement, l'application utilise [discord-interactions](https://github.com/discord/discord-interactions-js), qui fournit des types et des fonctions d'assistance. Si tu préfères utiliser d'autres langages ou bibliothèques, tu peux consulter la documentation des [ressources de la communauté](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remixage du projet + +Ce guide utilise Glitch, qui permet de cloner et de développer depuis ton navigateur. Si tu préfères développer ton application en local, des instructions relatives à l'utilisation de ngrok sont disponibles [dans le LISEZMOI](https://github.com/discord/discord-example-app#running-app-locally). + +> info +> Glitch est un excellent outil de développement et de test, mais [il présente certaines contraintes techniques](https://help.glitch.com/kb/article/17-technical-restrictions/) et il convient donc d'envisager d'autres fournisseurs d'hébergement pour les applications déjà en production. + +Pour commencer, **[remixe (ou clone) le projet Glitch 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Une fois ceci fait, Glitch te redirigera vers un nouveau projet. + + +![Vue d'ensemble de projet Glitch](glitch-project.png) + +- Le **nom de projet** est un nom spécifique à ton projet, et se trouve dans le coin supérieur gauche de l'interface. +- **`.env`** est le fichier dans lequel est stocké l'ensemble de tes informations d'identification pour ton application. +- Les **Logs** présentent les données de sortie de ton projet, ce qui est utile pour savoir si l'application est en cours d'exécution ou pour obtenir des informations sur les erreurs détectées. +- Le bouton **Share** dans le coin supérieur droit de l'interface permet d'accéder à l'URL active du projet, dont tu auras besoin pour mettre en place l'interactivité dans la suite de ce guide. + + +#### Structure du projet + +Tous les fichiers du projet se trouvent dans l'encadré de gauche de ton projet Glitch. Voici une vue d'ensemble des principaux dossiers et fichiers : + +``` +├── examples -> exemples d'applications courtes aux fonctionnalités spécifiques +│ ├── app.js -> code app.js terminé +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> tes informations d'identification et identifiants +├── app.js -> point d'entrée principal de l'application +├── commands.js -> payloads des commandes slash + fonctions d'assistance +├── game.js -> logique spécifique à pierre-feuille-ciseaux +├── utils.js -> fonctions utilitaires et énumérations +├── package.json +├── README.md +└── .gitignore +``` + +### Ajout d'informations d'identification + +Ton fichier `app.js` contient déjà du code, mais tu auras besoin de ton identifiant et de ton token d'application pour effectuer des requêtes. Toutes tes informations d'identification peuvent être stockées directement dans le fichier `.env`. + +Tout d'abord, copie le token de l'utilisateur bot que tu as précédemment configuré, et copie-le dans la variable **`DISCORD_TOKEN`** de ton fichier `.env`. + +Ensuite, rends-toi sur la page **Vue d'ensemble** de ton application, et copie l'**identifiant de l'application « APP_ID »** ainsi que sa **clé publique « PUBLIC_KEY »**. Colle-les dans les variables **`APP_ID`** et **`PUBLIC_KEY`** de ton fichier `.env`. + +Maintenant que tes informations d'identification sont configurées, installons et gérons des commandes slash. + +### Installation de commandes slash + +> info +> Pour installer des commandes slash, l'application utilise [`node-fetch`](https://github.com/node-fetch/node-fetch). Tu peux voir l'implémentation pour l'installation dans le fichier `utils.js` à l'intérieur de la fonction `DiscordRequest()`. + +Le projet contient un script `register` que tu peux utiliser pour installer les commandes dans la section `ALL_COMMANDS`, qui est définie à la fin du fichier `commands.js`. Il installe les commandes en tant que commandes globales en appelant le point de terminaison [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) de l'API HTTP. + +Si tu souhaites personnaliser les commandes ou en ajouter d'autres, tu peux consulter la structure des commandes dans la [documentation des commandes](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Pour exécuter le script `register`, clique sur le bouton **Terminal** en bas de l'interface du projet Glitch et colle la commande suivante : + +``` +npm run register +``` + +Appuie sur la touche Entrée pour exécuter la commande. + +Si tu retournes sur ton serveur, tu devrais voir apparaître les commandes slash. Mais il ne se passera rien si tu essaies de les exécuter, car ton application ne reçoit et ne traite aucune requête de Discord. + + +Discord propose deux API que tu peux combiner pour créer des applications : + +- L'**[API HTTP](#DOCS_REFERENCE/http-api)** est une API similaire à une API REST qui permet d'effectuer des opérations générales telles que l'envoi et la mise à jour de données dans Discord, ou la récupération de données relatives à une ressource. +- L'**[API Gateway](#DOCS_REFERENCE/gateway-websocket-api)** est une API basée sur WebSocket qui est utile pour maintenir l'état ou suivre les événements qui se produisent sur un serveur Discord. Nous n'utiliserons pas cette API dans ce guide, mais si tu veux en savoir plus sur la création d'une connexion Gateway et sur les différents événements que tu peux suivre, consulte la [documentation de Gateway](#DOCS_TOPICS_GATEWAY). + + +--- + +## Étape 3 : gestion de l'interactivité + +Pour permettre à ton application de recevoir des requêtes de commande slash (et d'autres interactions), Discord a besoin d'une URL publique pour les envoyer. Cette URL peut être configurée dans les paramètres de ton application en tant qu'**URL de point de terminaison des interactions**. + +### Ajout d'une URL de point de terminaison des interactions + +Les projets Glitch disposent d'une URL publique exposée par défaut. Pour copier l'URL de ton projet, clique sur le bouton **Share** dans le coin supérieur droit de l'interface, puis copie le lien du projet « Live site » en bas de la fenêtre qui vient de s'ouvrir. + +> info +> Si tu développes en local, tu trouveras des instructions expliquant comment établir un protocole de tunnellisation des requêtes vers ton environnement local [dans le LISEZMOI de GitHub](https://github.com/discord/discord-example-app#running-app-locally). + +Une fois le lien copié, va dans les paramètres de ton application depuis [le portail des développeurs](https://discord.com/developers/applications). + +Sur la page **Informations générales** de ton application, tu trouveras une option **URL de point de terminaison interactive**. Tu peux y coller l'URL de ton application suivie de `/interactions`, ce qui correspond à l'endroit où l'application Express écoute les requêtes. + +![URL de point de terminaison des interactions dans les paramètres de l'application](interactions-url.png) + +Clique sur **Sauvegarder les modifications** et assure-toi que la vérification de ton point de terminaison a réussi. + +L'exemple d'application gère la vérification de deux façons : +- Elle utilise la `PUBLIC_KEY` et le [package discord-interactions](https://github.com/discord/discord-interactions-js#usage) avec une fonction wrapper (importée de `utils.js`) qui la rend conforme à l'interface `verify` d'[Express](http://expressjs.com/en/5x/api.html#express.json). Ceci est exécuté pour chaque requête entrante de votre application. +- Elle répond aux requêtes de `PING` entrantes. + +Pour en savoir plus sur la préparation de ton application à la réception d'interactions, consulte [la documentation sur les interactions](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Gestion des requêtes de commandes slash + +Après la vérification de ton point de terminaison, ouvre le fichier `app.js` de ton projet et trouve le bloc de code qui gère la commande `/test` : + +```javascript +// commande « test » +if (name === 'test') { + // Envoi d'un message dans le salon à partir duquel la commande a été déclenchée + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Sélectionne un émoji aléatoire à envoyer à partir d'une fonction d'assistance + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Le code ci-dessus répond à l'interaction en envoyant un message dans le salon duquel il est issu. La liste de tous les types de réponses disponibles, comme une réponse dans une fenêtre, est détaillée [dans la documentation](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` est une constante [exportée depuis le package `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33). + +Va sur ton serveur et vérifie le bon fonctionnement de la commande slash `/test` de ton application. Lorsque tu déclenches la commande, ton application doit t'envoyer un message contenant « hello world » accompagné d'un émoji aléatoire. + +Dans la section suivante, nous allons ajouter une commande supplémentaire qui utilise des options de commande slash, des boutons et des menus de sélection pour créer le jeu pierre-feuille-ciseaux. + +--- + +## Étape 4 : ajout d'éléments de message + +La commande `/defi` permet de lancer notre jeu pierre-feuille-ciseaux. Quand cette commande est déclenchée, l'application envoie des éléments de message dans le salon, et ceux-ci guident les utilisateurs qui veulent jouer. + +### Ajout d'une commande avec des options + +La commande `/defi`, appelée `CHALLENGE_COMMAND` dans `commands.js`, dispose d'un ensemble d'`options`. Dans notre application, les options sont des objets qui représentent différentes choses qu'un utilisateur peut sélectionner lors d'une partie de pierre-feuille-ciseaux, et sont générées en utilisant les clés `RPSChoices` dans `game.js`. + +Tu peux en apprendre davantage sur les options de commande et leur structure [en consultant la documentation](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> Ce guide ne traite pas en profondeur du fichier `game.js`, mais n'hésite pas à y jeter un coup d'œil et à modifier les commandes ou leurs options. + + + +Pour gérer la commande `/defi`, ajoute le code suivant après le bloc if `if name === “test”` : + +```javascript +// commande « defi » +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Choix d'objet de l'utilisateur + const objectName = req.body.data.options[0].value; + + // Création d'une partie active en utilisant l'identifiant de message comme identifiant de partie + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Ajout de l'identifiant de partie à utiliser ultérieurement + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Si tu ne vois pas où coller ce code, tu peux consulter le code complet dans `examples/app.js` dans le projet Glitch ou dans le fichier `app.js` à la racine [sur GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +Le code ci-dessus fait plusieurs choses : +1. Il analyse le corps de la requête pour extraire l'identifiant de l'utilisateur qui a déclenché la commande slash (`userId`) ainsi que l'option (choix d'objet) sélectionnée (`objectName`). +2. Il ajoute un nouveau nom de partie à l'objet `activeGames` en utilisant l'identifiant d'interaction. La partie active enregistre le `userId` et le `objectName`. +3. Il renvoie un message dans le salon avec un bouton doté d'un `custom_id` de type `accept_button_`. + +> warn +> L'exemple de code utilise un objet comme stockage en mémoire, mais pour les applications en production, il est préférable d'utiliser une base de données. + +Lors de l'envoi d'un message avec des [éléments de message](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component), les payloads individuels sont annexés à un tableau `components`. Les éléments actionnables (tels que les boutons) doivent être inclus dans une [ligne d'action](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), que tu peux voir dans l'exemple de code. + +Observe le `custom_id` unique envoyé avec les éléments de message, ici `accept_button_` avec l'identifiant de partie active en annexe. Un `custom_id` peut être utilisé pour gérer les requêtes que Discord t'envoie lorsque quelqu'un interagit avec l'élément, ce que tu verras dans un moment. + +Désormais, lorsque tu exécutes la commande `/defi` et sélectionnes une option, ton application envoie un message avec un bouton **Accepter**. Ajoutons du code pour gérer le clic sur le bouton. + + + + + +Lorsque des utilisateurs interagissent avec un élément de message, Discord envoie une requête avec un [type d'interaction](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) égal à `3` (ou la valeur `MESSAGE_COMPONENT` lors de l'utilisation de `discord-interactions`). + +Pour mettre en place un gestionnaire pour le bouton, nous allons vérifier le `type` d'interaction, puis le `custom_id`. + +Colle le code suivant sous le gestionnaire de type pour `APPLICATION_COMMAND` : + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id défini dans le payload lors de l'envoi de l'élément de message +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // récupération de l'identifiant de partie associé + const gameId = componentId.replace('accept_button_', ''); + // Suppression du message avec le token dans le corps de la requête + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Sélectionne un émoji aléatoire à envoyer à partir d'une fonction d'assistance + content: 'What is your object of choice?', + // Indique qu'il s'agit d'un message éphémère + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Annexe l'identifiant de partie + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Suppression du message précédent + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Le code ci-dessus : +1. Vérifie qu'il existe un identifiant personnalisé `custom_id` correspondant à ce que nous avons envoyé précédemment (ici, il commence par `accept_button_`). L'identifiant personnalisé comprend également l'identifiant de partie active en annexe, donc nous le stockons dans `gameID`. +2. [Supprime le message d'origine](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) en appelant un webhook avec `node-fetch` et en passant le `token` d'interaction unique dans le corps de la requête. Cette opération permet de nettoyer le salon pour éviter que d'autres utilisateurs ne cliquent sur le bouton. +3. Répond à la requête en envoyant un message contenant un menu de sélection avec les choix d'objets pour le jeu. Le payload devrait être assez similaire au précédent, à l'exception du tableau `options` et du `flags: 64`, [qui indique que le message est éphémère](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +Le tableau `options` est peuplé en utilisant la méthode `getShuffledOptions()` dans `game.js`, qui manipule les valeurs `RPSChoices` pour être conforme au format des [options des éléments de message](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +La dernière chose à ajouter est le code permettant de gérer les interactions avec le menu de sélection et d'envoyer le résultat de la partie dans le salon. + +Comme les menus de sélection sont également des éléments de message, le code qui gère leurs interactions est presque identique au code des boutons. + +Modifie le code ci-dessus pour gérer le menu de sélection : + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id défini dans le payload lors de l'envoi de l'élément de message +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // récupération de l'identifiant de partie associé + const gameId = componentId.replace('accept_button_', ''); + // Suppression du message avec le token dans le corps de la requête + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Sélectionne un émoji aléatoire à envoyer à partir d'une fonction d'assistance + content: 'What is your object of choice?', + // Indique qu'il s'agit d'un message éphémère + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Annexe l'identifiant de partie + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Suppression du message précédent + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // récupération de l'identifiant de partie associé + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Obtention de l'identifiant d'utilisateur et du choix d'objet de l'utilisateur qui répond + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Calcul du résultat à l'aide d'une fonction d'assistance + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Suppression de la partie du stockage + delete activeGames[gameId]; + // Mise à jour du message avec le token dans le corps de la requête + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Envoi des résultats + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Mise à jour du message éphémère + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Comme le code précédent, le code ci-dessus obtient l'identifiant de l'utilisateur et sa sélection d'objet à partir de la demande d'interaction. + +Ces informations, ainsi que l'identifiant et la sélection de l'utilisateur d'origine stockés dans l'objet `activeGames`, sont transmises à la fonction `getResult()`. `getResult()` détermine le vainqueur, puis crée une chaîne lisible à renvoyer dans le salon. + +Nous appelons également un autre webhook, cette fois-ci pour [mettre à jour le message éphémère de suivi](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) puisqu'il ne peut pas être supprimé. + +Enfin, les résultats sont envoyés dans le salon en utilisant le type de réponse d'interaction `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +… et voilà 🎊 Il ne te reste plus qu'à tester ton application pour vérifier que tout fonctionne. + +--- + +## Étapes suivantes + +Félicitations, tu viens de créer ta première application Discord ! 🤖 + +Nous espérons que tu en sais maintenant un peu plus sur les applications Discord, leur configuration et la manière de les rendre interactives. Tu peux désormais poursuivre le développement de ton application ou explorer les autres possibilités qui s'offrent à toi : +- Lire **[la documentation](#DOCS_INTRO)** pour en savoir plus sur les fonctionnalités des API +- Parcourir le dossier `examples/` de ce projet pour y trouver des exemples de code courts aux fonctionnalités spécifiques +- Explorer les **[ressources de la communauté](#DOCS_TOPICS_COMMUNITY_RESOURCES)** pour découvrir des outils spécifiques à un langage maintenus par les membres de la communauté +- Lire notre tutoriel sur [l'hébergement d'applications Discord sur Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Rejoindre le **[serveur Discord Developers](https://discord.gg/discord-developers)** pour poser des questions sur les API, participer à des événements organisés par l'équipe API de Discord, et interagir avec d'autres développeurs diff --git a/docs/ja/Getting_Started.mdx b/docs/ja/Getting_Started.mdx new file mode 100644 index 0000000000..fc2ba16ebd --- /dev/null +++ b/docs/ja/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# 初めてのDiscordアプリ作成 + +Discordアプリは、様々なAPIやインタラクティブ機能により、あなたのサーバーのカスタマイズや拡張を助けてくれる存在です。このガイドでは、JavaScriptを使って初めてのDiscordアプリを作るお手伝いをします。ガイドを最後までたどれば、スラッシュコマンドの使用、メッセージの使用、コンポーネント・インタラクションへの応答に対応したアプリが完成します。 + +サーバーメンバーがじゃんけん(ただし通常の3つではなく7つの手が選べる)をできるDiscordアプリを作ります。このガイドは初心者向けですが、[JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics)の基本を知っていることが前提となります。 + + +これが完成したアプリのお手本です: + +![アプリ実例のデモ](getting-started-demo.gif) + +このユーザーフローをもう少し明確にしてみましょう: + +1. ユーザー1が新しいゲームを開始し、アプリの`/challenge`スラッシュコマンドを使ってオブジェクトを選ぶ +2. 他のメンバーに挑戦を促すボタンを添えたメッセージがチャンネルに送られる +3. ユーザー2が**Accept(承諾)**ボタンを押す +4. ユーザー2に、オブジェクトを選ぶよう促す一時メッセージが送られる +5. ゲームの結果が、元のチャンネルに公開で投稿される + + + +- **[Githubレポジトリ](https://github.com/discord/discord-example-app)**:このガイドのコードと、追加の機能固有のコード例がいくつか掲載されています。 +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**:Discordアプリのタイプおよびヘルパー関数を提供するライブラリです。 +- **[Express](https://expressjs.com)**:人気のJavaScriptウェブフレームワーク。Discordがリクエストを送信できるサーバーの作成に使います。 +- **[Glitch](https://glitch.com/)**:初期のプロトタイピングおよび開発段階でのアプリの構築およびホストをシンプル化してくれるオンライン環境です。**[ngrok](https://ngrok.com/)**のようなツールを用いてローカルで開発することもできます。 + + +--- + +## ステップ1:アプリを作成する + +アプリが既にない場合はまず、開発者ポータルでアプリを作成する必要があります: + + + +アプリの名前を入力し、**Create(作成)**を押してください。 + +アプリを作成すると、アプリの設定の**概要**ページが開きます。ここではアプリの説明やアイコンなど、基本情報を更新できます。Yまた**アプリケーションID**と**インタラクション・エンドポイントURL**も確認できます。これらはガイドで後ほど使用します。 + +### Botを設定する + +次にアプリの[Botユーザー](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts)を設定します。これにより、Botがサーバー内で他のメンバーと同様に表示・動作するようになります。 + +左側のサイドバーで**Bot**をクリックします。このページでは、Botの[特権インテント(privileged intents)](#DOCS_TOPICS_GATEWAY/privileged-intents)や、Botが他のユーザーによってインストールできるかどうかなどの設定を行えます。 + + +インテントとは、[ゲートウェイAPI接続](#DOCS_TOPICS_GATEWAY)を作成する際に、Discordがあなたのアプリにどのイベントを送信するかを決定するものです。たとえば、ユーザーがメッセージにリアクションを追加したときに動作するアプリを作りたいなら、`GUILD_MESSAGE_REACTIONS` (`1 << 10`) インテントを渡します。 + +一部のインテントは[特権](#DOCS_TOPICS_GATEWAY/privileged-intents)インテントであり、センシティブと判断される可能性のあるデータ(メッセージの内容など)にアプリがアクセスできるようにします。特権インテントはアプリの設定の**Bot**ページに表示され、ここで切り替えできます。標準の非特権インテントは、追加の権限や設定を必要としません。 + +インテントについての詳細情報、利用可能な全インテント一覧とそれらに関連付けられたイベントについては、[ゲートウェイ・ドキュメント](#DOCS_TOPICS_GATEWAY/gateway-intents)をご覧ください。 + + +![アプリ設定のBotタブ](app-add-bot.png) + +**Bot**ページには、Botのトークンをコピーしたりリセットしたりできる**トークン**セクションもあります。 + +BotトークンはAPIリクエストの認証に使われ、Botユーザーの権限を含んでいるため、*きわめて機密性が高い*ものです。トークンを共有したり、何らかのバージョン管理にチェックインしたりすることは*絶対に*しないでください。 + +トークンをコピーし、安全な場所(パスワードマネージャーなど)に保管しておきましょう。 + +> 警告 +> トークンは再生成しない限り2度と見ることはできませんので、必ず安全な場所に保管してください。 + +### スコープとBot権限を追加する + +アプリは、ダウンロードするユーザーから、Discordでアクション(スラッシュコマンドを作成する、サーバーメンバーのリストを取得するなど)を行う許可を得る必要があります。アプリをインストールする前に、スコープと権限をいくつか選択しましょう。 + + +アプリの作成にあたって、あなたのアプリがDiscordサーバーでできること、アクセスできるものを定めるのがスコープと権限です。 + +- [OAuth2スコープ](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes)は、インストールまたは認証を行うユーザーに代わってあなたのアプリが行えるデータアクセスやアクションを定めます。 +- [権限](#DOCS_TOPICS_PERMISSIONS/permission-overwrites)は、Botユーザーに与える粒度の細かい権限であり、Discordにおける他のユーザーが有しているのと同様のものです。インストールするユーザーが承認することもできますし、後から[権限の上書き](#DOCS_TOPICS_PERMISSIONS/permission-overwrites)を用いてサーバー設定で更新することもできます。 + + +左側のサイドバーで**OAuth2**をクリックし、続いて**URLジェネレータ(URL generator)**を選択します。 + +> 情報 +> URLジェネレータは、あなたがアプリ用に選択したスコープと権限に基づいてインストール用リンクを生成します。このリンクで自分のサーバーにアプリをインストールできるほか、他の人と共有してインストールしてもらうこともできます。 + +今のところは2つのスコープを追加してみましょう: +- `applications.commands`:アプリが[コマンド](#DOCS_INTERACTIONS_APPLICATION_COMMANDS)を生成できるようにします。 +- `bot`:Botユーザーを追加します。`bot`を選択したら、Bot用に他の各種権限を追加できます。今のところは、**メッセージを送信**だけチェックしておきましょう。 + +[OAuth2スコープ](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes)の一覧をご確認いただくか、ドキュメントで[権限](#DOCS_TOPICS_PERMISSIONS)についての詳細をご覧ください。 + +### アプリをインストールする + +スコープを追加したら、URLが表示されます。これをコピーしてアプリをインストールすることができます。 + +![URLジェネレータのスクリーンショット](url-generator.png) + +> 情報 +> アプリ開発にあたっては、他の人がアクティブに利用していないサーバーでビルドおよびテストを行ってください。自分のサーバーがまだない方は、[無料で作成できます](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-)。 + +上記よりURLをコピーし、ブラウザにペーストしてください。インストールのステップを踏む際は、アプリの開発とテストをできるサーバーに間違いなくインストールしていることを確かめてください。 + +アプリをインストールしたら、サーバーに移動して、アプリが参加したことを確かめましょう✨ + +アプリの設定とインストールが完了したら、開発を始めましょう。 + +--- + +## ステップ2:アプリを実行する + +アプリ実例で使われたコードはすべて[Githubレポジトリ](https://github.com/discord/discord-example-app)に掲載されています。 + +開発がしやすくなるよう、このアプリでは、タイプおよびヘルパー関数を提供する[discord-interactions](https://github.com/discord/discord-interactions-js)を使用しています。他の言語やライブラリを使用したい場合は、[コミュニティ・リソース](#DOCS_TOPICS_COMMUNITY_RESOURCES)ドキュメントをご確認ください。 + +### プロジェクトをリミックスする + +このガイドでは、ブラウザでクローンと開発ができるGlitchを使用しています。ローカルでアプリの開発をしたい場合は、[README](https://github.com/discord/discord-example-app#running-app-locally)にngrokの使い方が掲載されています。 + +> 情報 +> Glitchは開発とテストには最適ですが、[技術的な制限があるため](https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions)、プロダクションアプリについては他のホスティング・プロバイダをご検討ください。 + +まず**[Glitchプロジェクトをリミックス(またはクローン)しましょう🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)** + +プロジェクトをリミックスすると、新しいGlitchプロジェクトが開きます。 + + +![Glitchプロジェクトの概要](glitch-project.png) + +- あなたの**プロジェクト名**は、プロジェクト固有の名前であり、左上隅に表示されます +- **`.env`**はあなたのアプリのクレデンシャルがすべて保存されるファイルです +- **ログ**は、あなたのプロジェクトのアウトプットがある場所です。アプリがきちんと実行されているかを確かめたり、アプリに生じたエラーをチェックしたりするのに役立ちます +- 右上隅の**共有(Share)**ボタンを押すと、ライブプロジェクトURLが表示されます。このURLは、このガイドで後ほどインタラクティビティを設定するのに必要です + + +#### プロジェクトの構造 + +プロジェクト用のファイルはすべて、Glitchプロジェクトの左側に表示されます。下記は主なフォルダーとファイルを概観したものです: + +``` +├── examples -> 特定機能向けの短いサンプルアプリ +│ ├── app.js -> 書き終えたapp.jsコード +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> あなたのクレデンシャルとID +├── app.js -> アプリのメインエントリポイント +├── commands.js -> スラッシュコマンドのペイロードとヘルパー +├── game.js -> RPS固有のロジック +├── utils.js -> ユーティリティ関数と列挙型 +├── package.json +├── README.md +└── .gitignore +``` + +### クレデンシャルを追加する + +`app.js`ファイルには既にコードが入っていますが、リクエストを行うにはアプリのトークンとIDが必要です。あなたのクレデンシャルはすべて直接`.env`ファイルに保存できます。 + +まず、先ほどのBotユーザーのトークンをコピーし、`.env`ファイルの**`DISCORD_TOKEN`**変数にペーストします。 + +次に、アプリの**概要**ページに移動し、**アプリID**と**パブリックキー**をコピーします。`.env`ファイルに、**`APP_ID`**および**`PUBLIC_KEY`**として値をペーストします。 + +クレデンシャルの設定が終わったら、スラッシュコマンドをインストールしてハンドルしてみましょう。 + +### スラッシュコマンドをインストールする + +> 情報 +> アプリはスラッシュコマンドをインストールするにあたり、[`node-fetch`](https://github.com/node-fetch/node-fetch)を利用しています。インストールの実装は、`DiscordRequest()`関数内の`utils.js`で確認できます。 + +プロジェクトには`register`スクリプトが含まれています。これを用いて、`commands.js`の最下部で定義されている`ALL_COMMANDS`のコマンドをインストールできます。これはHTTP APIの[`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands)エンドポイントを呼び出すことで、コマンドをグローバルコマンドとしてインストールします。 + +コマンドをカスタマイズしたい、または新しいものを追加したい場合は、[コマンド・ドキュメント](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure)にてコマンドの構造をご確認ください。 + +Glitchプロジェクトの最下部にある**ターミナル(Terminal)**をクリックして`register`スクリプトを実行し、下記のコマンドをペーストします: + +``` +npm run register +``` + +Enterキーを押してコマンドを実行します。 + +サーバーに戻ると、スラッシュコマンドが表示されるようになっているはずです。ただし、アプリはまだDiscordからのリクエストを受け取ったりハンドルしたりできないため、実行しても何も起きません。 + + +Discordには2種類のAPIがあり、これらを組み合わせてアプリを作成できます: + +- **[HTTP API](#DOCS_REFERENCE/http-api)**:RESTに似たAPIであり、Discord上でのデータ送信やアップデート、リソースに関するデータの取得などの全般的操作に使用します。 +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)**:WebSocketベースのAPIであり、ステートを維持したり、Discordサーバーで起こっているイベントをリッスンしたりするのに便利です。このガイドでは使いませんが、ゲートウェイ接続の作成方法や、リッスンできる各種イベントについては、[ゲートウェイ・ドキュメント](#DOCS_TOPICS_GATEWAY)をご覧ください。 + + +--- + +## ステップ3:インタラクティビティをハンドルする + +Discordでは、アプリがスラッシュコマンド・リクエスト(およびその他のインタラクション)を受け取れるようにするには、それらを送信するための公開URLが必要となります。このURLは、アプリの設定で**インタラクション・エンドポイントURL**として設定できます。 + +### インタラクション・エンドポイントURLを追加する + +Glitchプロジェクトでは、デフォルトで公開URLが見られるようになっています。右上隅の**共有(Share)**ボタンをクリックしてプロジェクトのURLをコピーし、続いてモーダルの下部近くにある「ライブ中のサイト(Live Site)」プロジェクトリンクをコピーしてください。 + +> 情報 +> ローカルで開発をしている場合は、ローカルの環境にリクエストをトンネリングする手順を[Github README](https://github.com/discord/discord-example-app#running-app-locally)で確認できます。 + +リンクがコピーできたら、[開発者ポータル](https://discord.com/developers/applications)からアプリの設定を開きます。 + +アプリの**概要**ページに**インタラクティブ・エンドポイントURL**オプションがあります。ここでアプリのURLをペーストし、Expressアプリがリクエストをリッスンするよう設定される`/interactions`をアペンドできます。 + +![アプリ設定におけるインタラクション・エンドポイントURL](interactions-url.png) + +**変更を保存(Save Changes)**をクリックし、エンドポイントが認証されたことを確かめましょう。 + +サンプルアプリは2つの方法で認証をハンドリングします: +- `PUBLIC_KEY`およびラッパー関数(`utils.js`よりインポート)を伴った[discord-interactionsパッケージ](https://github.com/discord/discord-interactions-js#usage)を利用する。これにより、[Expressの`verify`インターフェース](http://expressjs.com/en/5x/api.html#express.json)に適合します。これはあなたのアプリにリクエストが入ってくるたびに実行されます。 +- 入ってくる`PING`リクエストに応答する。 + +アプリがインタラクションを受け取れるようにする方法について、詳しくは[インタラクション・ドキュメント](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction)をご覧ください。 + +### スラッシュコマンド・リクエストをハンドリングする + +エンドポイントの認証が完了したら、プロジェクトの`app.js`ファイルに移動し、`/test`コマンドをハンドリングするコードブロックを見つけてください: + +```javascript +// 「test」コマンド +if (name === 'test') { + // コマンドがトリガーされた起点のチャンネルにメッセージを送る + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ヘルパー関数から送る絵文字をランダムに取得する + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +上記のコードは、起点となったチャンネルにおけるメッセージとのインタラクションに応答しています。可能な応答タイプ(モーダルで応答するなど)は[ドキュメント](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type)でご確認いただけます。 + +> 情報 +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE`は[`discord-interactions`からエクスポートされた](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33)定数です + +サーバーに移動し、アプリの`/test`スラッシュコマンドが機能することを確かめましょう。トリガーすると、アプリは「hello world」という言葉のあとにランダムな絵文字を含むメッセージを送信するはずです。 + +次のセクションでは、じゃんけんゲームを構築するため、スラッシュコマンド・オプションを利用する別のコマンド、ボタン、選択メニューを追加していきます。 + +--- + +## ステップ4:メッセージ・コンポーネントを追加する + +このじゃんけん式ゲームは、`/challenge`コマンドで開始されます。コマンドがトリガーされると、アプリはチャンネルにメッセージ・コンポーネントを送信し、これによってユーザーはゲームを完了するよう誘導されます。 + +### オプションのあるコマンドを追加する + +`/challenge`コマンドは、`commands.js`では`CHALLENGE_COMMAND`と呼ばれており、一連の`options`を有します。今回のアプリでは、オプションはユーザーがじゃんけんをする際に選択できる様々なものを表しており、`game.js`における`RPSChoices`のキーを利用して生成されます。 + +コマンドオプションとその構造については[ドキュメント](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure)をご覧ください。 + +> 情報 +> このガイドでは`game.js`にはあまり深入りしませんが、コマンドやコマンド内のオプションを変えるなど、いろいろといじってみましょう。 + + + +`/challenge`コマンドをハンドリングするには、ifブロック`if name === “test”`のあとに次のコードを追加してください: + +```javascript +// 「challenge」コマンド +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // ユーザーの選択したオブジェクト + const objectName = req.body.data.options[0].value; + + // メッセージIDをゲームIDとして用い、アクティブなゲームを作成する + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // 後ほど使用するため、ゲームIDをアペンドする + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> 情報 +> コードをペーストする場所が分からない場合は、Glitchプロジェクトの`examples/app.js`でコード全体を見るか、[Github](https://github.com/discord/discord-example-app/blob/main/app.js)でルート`app.js`を見てみましょう。 + +上記のコードは、次のような動きをしています: +1. リクエストボディをパースし、スラッシュコマンドをトリガーしたユーザーのID(`userId`)とそのユーザーが選択したオプション(選んだオブジェクト)(`objectName`)を取得します。 +2. インタラクションIDを使用して、`activeGames`オブジェクトに新しいゲームを追加します。アクティブなゲームは`userId`と`objectName`を記録します。 +3. チャンネルに、`accept_button_`の`custom_id`を伴う、ボタンのついたメッセージを送り返します。 + +> 警告 +> サンプルコードではオブジェクトをメモリ内ストレージとして使用していますが、プロダクションアプリではデータベースを使用してください。 + +[メッセージ・コンポーネント](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component)を伴うメッセージを送るとき、個々のペイロードは`components`アレイにアペンドされます。実行可能なコンポーネント(ボタンなど)は、コードサンプルで確認できる[アクション行](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows)の中にある必要があります。 + +メッセージ・コンポーネントと共に送られる一意の`custom_id`にお気づきでしょうか。この場合は、アクティブなゲームのIDがアペンドされた`accept_button_`になります。誰かがコンポーネントとインタラクトした際にDiscordがあなたに送るリクエストをハンドリングするには、`custom_id`が使用できます。これについては後ほどご説明します。 + +これで、`/challenge`コマンドを実行してオプションを選ぶと、アプリが**挑戦受諾(Accept)**ボタンを伴うメッセージを送信します。ボタンを押す動作をハンドリングできるよう、コードを追加しましょう。 + + + + + +ユーザーがメッセージ・コンポーネントとインタラクトすると、Discordは[インタラクション・タイプ](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type)が`3`(または`discord-interactions`を使用している場合は`MESSAGE_COMPONENT`の値)のリクエストを送信します。 + +ボタンのハンドラを設定するため、インタラクションの`type`を確認し、続いて`custom_id`のマッチングを行います。 + +`APPLICATION_COMMAND`のタイプハンドラの下に、下記のコードをペーストしてください: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// メッセージ・コンポーネントを送信する際、custom_idをペイロード内に設定する +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // 関連付けられたゲームIDを取得する + const gameId = componentId.replace('accept_button_', ''); + // リクエストボディのトークンを含むメッセージを削除する + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ヘルパー関数から送る絵文字をランダムに取得する + content: 'What is your object of choice?', + // 一時メッセージであることを示す + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // ゲームIDをアペンドする + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // 以前のメッセージを削除する + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +上記のコードは以下のように動作します: +1. 元々送ったものとマッチする`custom_id`をチェックします(この場合は`accept_button_`で始まるものです)。カスタムIDにはアクティブなゲームIDもアペンドされていますので、これを`gameID`に保存します。 +2. `node-fetch`を使用してウェブフックを呼び出し、リクエストボディ内の一意のインタラクション`token`を渡すことで、[元のメッセージを削除](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response)します。これは他のユーザーがボタンをクリックしてしまわないよう、チャンネルをクリーンアップするための動作です。 +3. ゲームのオブジェクトの選択肢を示す選択メニューを含んだメッセージを送ることで、リクエストに応答します。ペイロードは前のものとよく似ていますが、`options`アレイと[一時メッセージであることを示す](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message)`flags: 64`がある点で異なります。 + +`options`アレイは`game.js`の`getShuffledOptions()`メソッドを利用して入力されます。これは`RPSChoices`の値を操作して[メッセージ・コンポーネント・オプション](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure)の形に合わせてゆくものです。 + + + + + +最後に追加するのは、選択メニューとのインタラクションをハンドリングし、ゲームの結果をチャンネルに送信するコードです。 + +選択メニューもメッセージ・コンポーネントに他ならないため、メニューとのインタラクションをハンドリングするコードも、ボタンのそれとほぼ同じになります。 + +上記のコードを編集して、選択メニューをハンドリングしましょう: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// メッセージ・コンポーネントを送信する際、custom_idをペイロード内に設定する +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // 関連付けられたゲームIDを取得する + const gameId = componentId.replace('accept_button_', ''); + // リクエストボディのトークンを含むメッセージを削除する + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // ヘルパー関数から送る絵文字をランダムに取得する + content: 'What is your object of choice?', + // 一時メッセージであることを示す + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // ゲームIDをアペンドする + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // 以前のメッセージを削除する + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // 関連付けられたゲームIDを取得する + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // ユーザー応答のためユーザーIDと選択されたオブジェクトを取得する + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // ヘルパー関数から結果を計算する + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // ゲームをストレージから削除する + delete activeGames[gameId]; + // リクエストボディのトークンを含むメッセージを更新する + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // 結果を送信する + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // 一時メッセージを更新する + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +以前のコードと同様、上記のコードは、インタラクション・リクエストからユーザーIDとそのユーザーの選択したオブジェクトを取得しています。 + +この情報、ならびに元のユーザーのIDと`activeGames`オブジェクトからの選択が、`getResult()`関数に渡されます。`getResult()`が勝者を決定し、チャンネルに送り返すための読み取り可能な文字列をビルドします。 + +また、別のウェブフックも呼び出して、[フォローアップの一時メッセージを削除できない代わりに更新します](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message)。 + +最後に、`CHANNEL_MESSAGE_WITH_SOURCE`インタラクション応答タイプを使用して、結果がチャンネルに送られます。 + + + +……以上です 🎊 アプリをテストしてみて、すべてが想定通りに動くかどうか確かめましょう。 + +--- + +## 今後のステップ + +初めてのDiscordアプリの完成、おめでとうございます!🤖 + +Discordアプリのこと、設定する方法、そしてインタラクティブなアプリを作る方法について、学んでいただけていれば幸いです。ここからは、アプリを開発をさらに進めてもよいですし、他にできることを調べてみてもよいでしょう: +- API機能についてさらに詳しく知るため、**[ドキュメント](#DOCS_INTRO)**を読んでみる +- より小規模な、機能固有のコード例を見るため、このプロジェクトの`examples/`フォルダーを見てみる +- **[コミュニティリソース](#DOCS_TOPICS_COMMUNITY_RESOURCES)**で、コミュニティメンバーが管理している言語ごとのツールを見てみる +- [Cloudflare WorkersでDiscordアプリをホストする](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS)チュートリアルを読む +- **[Discord開発者サーバー](https://discord.gg/discord-developers)**に加入して、APIについて質問したり、Discord APIチームの主催するイベントに参加したり、他の開発者と交流したりする diff --git a/docs/nl/Getting_Started.mdx b/docs/nl/Getting_Started.mdx new file mode 100644 index 0000000000..da9e784a90 --- /dev/null +++ b/docs/nl/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Het bouwen van je eerste Discord-app + +Met Discord-apps kun je je servers aanpassen en uitbreiden via een aantal API's en interactieve functies. Deze gids helpt je stap voor stap bij het bouwen van je eerste Discord-app met behulp van JavaScript, waardoor je app uiteindelijk gebruikmaakt van slashopdrachten, berichten verstuurt en reageert op interacties tussen componenten. + +We gaan een app bouwen waarmee serverleden steen-papier-schaar kunnen spelen (met 7 keuzes in plaats van 3). Deze gids richt zich op beginners, maar gaat uit van basiskennis van [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Zo komt de voltooide app eruit te zien: + +![Demo van de voorbeeld-app](getting-started-demo.gif) + +Ter verduidelijking van de gebruikersflow: + +1. Gebruiker 1 begint aan een nieuw spel en kiest een object via de slashopdracht `/challenge` in de app +2. Er wordt een bericht naar een kanaal gestuurd met een knop waarmee anderen de uitdaging kunnen accepteren +3. Gebruiker 2 klikt op de knop **Accepteren** +4. Gebruiker 2 ontvangt een kortstondig bericht waarin een object naar keuze kan worden geselecteerd +5. Het resultaat van het spel wordt in het oorspronkelijke kanaal gepost, zodat iedereen het kan zien + + + +- **[GitHub-register](https://github.com/discord/discord-example-app)** waar de code uit deze gids zich bevindt, samen met wat extra codevoorbeelden voor speciale functies. +- **[discord-interacties](https://github.com/discord/discord-interactions-js)**, een bibliotheek met soort- en hulpfuncties voor Discord-apps. +- **[Express](https://expressjs.com)**, een populair JavaScript-webframewerk dat we gebruiken om een server te creëren waarvandaan Discord ons verzoeken kan sturen. +- **[Glitch](https://glitch.com/)**, een online omgeving die het bouwen en hosten van apps vereenvoudigt in de vroege prototype- en ontwikkelingsfase. Je kunt ook lokaal ontwikkelen met een tool als **[ngrok](https://ngrok.com/)**. + + +--- + +## Stap 1: Een app creëren + +Eerst moet je een app creëren in het ontwikkelaarsportaal, als je dat nog niet hebt gedaan: + + + +Voer een naam in voor je app en klik dan op **Creëren**. + +Na het creëren van je app, kom je terecht op de pagina **Algemeen overzicht** van de app-instellingen, waar je basisinformatie over je app kunt updaten, zoals de beschrijving en het pictogram. Je ziet daar ook een **applicatie-ID** en **eindpunt-URL voor interacties**, waar we later in de gids mee te maken krijgen. + +### Je bot configureren + +Nu gaan we de [botgebruiker](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) voor je app configureren, waardoor hij kan verschijnen en zich kan gedragen als andere serverleden. + +Klik in de linker zijbalk op **Bot**. Op deze pagina kun je instellingen configureren zoals de [privileged intents](#DOCS_TOPICS_GATEWAY/privileged-intents) van je bot en of je wilt dat andere gebruikers hem kunnen installeren. + + +Intents bepalen welke evenementen Discord naar je app stuurt als je een [Gateway API-verbinding](#DOCS_TOPICS_GATEWAY) creëert. Als je bijvoorbeeld wilt dat je app iets doet als gebruikers reageren op een bericht, kun je de intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`) doorgeven. + +Sommige intents zijn [privileged intents](#DOCS_TOPICS_GATEWAY/privileged-intents), wat betekent dat ze je app toegang geven tot data die als gevoelig beschouwd kunnen worden (zoals de inhoud van berichten). Privileged intents verschijnen op de **Bot**-pagina in je app-instellingen, waar je ze ook aan en uit kunt zetten. Voor gewone intents heb je geen extra machtigingen of configuraties nodig. + +Meer informatie over intents en een volledige lijst van beschikbare intents en de bijbehorende evenementen is te vinden in de [Gateway-documentatie](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Bot-tab in app-instellingen](app-add-bot.png) + +Er is ook een **Token**-sectie op de **Bot**-pagina, waarmee je het token van je bot kunt kopiëren en resetten. + +Met bottokens worden API-verzoeken geautoriseerd. Ze bevatten de machtigingen van je botgebruiker, waardoor ze *zeer kwetsbaar* zijn. Deel *nooit* je token en gebruik hem nooit bij versiecontrole. + +Maar je kunt je token gerust kopiëren en hem dan veilig opbergen (bijvoorbeeld in een wachtwoordbeheerprogramma). + +> waarschuwing +> Je kunt je token niet zien tenzij je hem regenereert, dus berg hem ergens veilig op. + +### Scopes en botmachtigingen toevoegen + +Apps hebben toestemming nodig van gebruikers die ze installeren om acties uit te voeren in Discord (zoals het creëren van slahopdrachten of het ophalen van een lijst met serverleden). Laten we een paar scopes en machtigingen kiezen om aan te vragen voordat de app wordt geïnstalleerd. + + +Bij het creëren van een app bepaal je met scopes en botmachtigingen wat je app kan doen en waartoe de app toegang krijgt op Discord-servers. + +- [OAuth2-scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) bepalen de datatoegang en acties waarvan je app gebruik mag maken, toegekend uit naam van een gebruiker die de app installeert of authentiseert. +- [Machtigingen](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) zijn de gespecialiseerde toestemmingen voor je botgebruiker, zoals andere gebruikers op Discord ook hebben. Ze kunnen toestemming krijgen van de installerende gebruiker, of later worden bijgewerkt in de serverinstellingen of met [machtigingsoverschrijvingen](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Klik in de zijbalk links op **OAuth2** en selecteer vervolgens **URL-generator**. + +> info +> De URL-generator creëert een installatielink gebaseerd op de scopes en machtigingen die je selecteert voor je app. Je kunt de link gebruiken om de app op je eigen server te installeren of om hem te delen met anderen, zodat zij hem kunnen installeren. + +Voeg voorlopig twee scopes toe: +- `applications.commands`, waarmee je app [opdrachten](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) kan creëren. +- `bot` voegt je botgebruiker toe. Nadat je `bot` hebt geselecteerd, kun je ook andere machtigingen selecteren voor je bot. Vink voorlopig alleen **Berichten verzenden** aan. + +Bekijk een lijst met alle [OAuth2-scopes](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) of lees meer over [machtigingen](#DOCS_TOPICS_PERMISSIONS) in de documentatie. + +### Je app installeren + +Als je eenmaal scopes hebt toegevoegd, verschijnt er een URL die je kunt kopiëren om je app te installeren. + +![Screenshot van URL-generator](url-generator.png) + +> info +> Als je apps ontwikkelt, kun je ze het beste bouwen en testen op een server die niet actief wordt gebruikt door anderen. Als je nog geen eigen server hebt, kun je [er gratis eentje creëren](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Kopieer de bovenstaande URL en plak hem in je browser. Je wordt vervolgens door het installatieproces geleid, waarbij je ervoor moet zorgen dat je je app installeert op een server waarop hij ontwikkeld en getest kan worden. + +Na het installeren van je app kun je naar je server gaan om te zien of alles werkt ✨ + +Nu je app is geconfigureerd en geïnstalleerd, kun je hem gaan ontwikkelen. + +--- + +## Stap 2: Je app laten draaien + +Alle code uit de voorbeeld-app vind je in [het GitHub-register](https://github.com/discord/discord-example-app). + +Om het ontwikkelen wat makkelijker te maken, maakt de app gebruik van [discord-interactions](https://github.com/discord/discord-interactions-js), die soort- en hulpfuncties verschaffen. Als je liever andere talen of bibliotheken gebruikt, raadpleeg dan de documentatie van de [communityhulpbronnen.](#DOCS_TOPICS_COMMUNITY_RESOURCES) + +### Het project remixen + +Deze gids maakt gebruik van Glitch, waarmee je in je browser kunt klonen en ontwikkelen. Als je je app liever lokaal ontwikkelt, vind je [in de README](https://github.com/discord/discord-example-app#running-app-locally) instructies over het gebruik van ngrok. + +> info +> Glitch is geweldig voor ontwikkeling en testen, maar [het heeft ook zijn technische beperkingen](https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions). Daarom is het goed om voor productie-apps ook naar andere hostingproviders te kijken. + +**[Remix (of kloon) om te beginnen het Glitch-project 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Als je het project remixt, kom je in een nieuw Glitch-project terecht. + + +![Projectoverzicht Glitch](glitch-project.png) + +- Je **projectnaam** is een unieke naam voor je project, die je vindt in de linker bovenhoek +- **`.env`** is het bestand waar alle verificatiegegevens voor je app in worden opgeslagen +- In **logs** kun je de output van je project vinden. Hier kun je zien of de app wel draait, en info bekijken over problemen waar je app tegenaan loopt +- De knop **Delen**, rechts boven in het scherm, is de plaats waar de live project-URL te vinden is. Verderop in deze gids gebruiken we die om interactiviteit in te stellen + + +#### Projectstructuur + +Alle bestanden voor het project staan aan de linkerkant van je Glitch-project. Hieronder zie je een overzicht van de hoofdmappen en -bestanden: + +``` +├── examples -> korte, functie-specifieke voorbeeld-apps +│ ├── app.js -> voltooide app.js-code +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> je verificatiegegevens en ID's +├── app.js -> belangrijkste ingang voor app +├── commands.js -> payloads van slashopdrachten + hulpfuncties +├── game.js -> specifieke SPS-logica +├── utils.js -> hulpprogrammafuncties en enums +├── package.json +├── README.md +└── .gitignore +``` + +### Verificatiegegevens toevoegen + +Er staat al wat code in je `app.js`-bestand, maar om verzoeken in te dienen, heb je de token en ID van je app nodig. Al je verificatiegegevens kun je opslaan in het `.env`-bestand. + +Eerst kopieer je het eerder genoemde token van je botgebruiker en plak je die in de **`DISCORD_TOKEN`**-variabele van je `.env`-bestand. + +Ga daarna naar de pagina **Algemeen overzicht** en kopieer de **app-ID** en **openbare code**. Plak de waarden in je `.env`-bestand als **`APP_ID`** en **`PUBLIC_KEY`**. + +Nu je verificatiegegevens zijn geconfigureerd, gaan we slashopdrachten installeren en er verder mee werken. + +### Slashopdrachten installeren + +> info +> Om slashopdrachten te installeren, maakt de app gebruik van [`node-fetch`](https://github.com/node-fetch/node-fetch). Je kunt de implementatie voor de installatie zien in `utils.js`, binnen de `DiscordRequest()`-functie. + +Het project bevat een `register`-script waarmee je de opdrachten kunt installeren in `ALL_COMMANDS`, wat je onderaan `commands.js` vindt. Dit installeert de opdrachten als algemene opdrachten door het [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands)-eindpunt van de HTTP API op te roepen. + +Als je je opdrachten wilt aanpassen of extra opdrachten wilt toevoegen, kun je verwijzen naar de opdrachtstructuur in de [opdrachtdocumentatie](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Run het `register`-script door onderaan het Glitch-project op **Terminal** te klikken en de volgende opdracht te plakken: + +``` +npm run register +``` + +Druk op Enter om de opdracht te activeren. + +Als je teruggaat naar je server, moet je nu de slashopdrachten zien verschijnen. Maar als je ze probeert uit te voeren, gebeurt er niets, omdat je app geen verzoeken ontvangt of verwerkt van Discord. + + +Discord heeft twee API's die je kunt combineren om apps te bouwen: + +- **[HTTP API](#DOCS_REFERENCE/http-api)** is een REST-achtige API voor algemene handelingen zoals het versturen en updaten van data in Discord, of het ophalen van data over een hulpbron. +- **[Gateway API](#DOCS_REFERENCE/gateway-websocket-api)** is een op WebSocket gebaseerde API die nuttig is voor het behouden van een status en om te luisteren naar evenementen die plaatsvinden op een Discord-server. We gebruiken deze API niet in deze gids, maar als je meer wilt weten over het creëren van een Gateway-verbinding en de verschillende evenementen waarnaar je kunt luisteren, raadpleeg dan de [Gateway-documentatie](#DOCS_TOPICS_GATEWAY). + + +--- + +## Step 3: Werken met interactiviteit + +Om ervoor te zorgen dat je app slashopdrachtverzoeken (en andere interacties) kan ontvangen, heeft Discord een openbare URL nodig om ze te versturen. Je kunt deze URL configureren in de instellingen van je app als **eindpunt-URL voor interacties**. + +### Een eindpunt-URL voor interacties toevoegen + +In Glitch-projecten is standaard een openbare URL te zien. Kopieer de URL van je project door op de knop **Delen** te klikken rechtsboven in de hoek. Kopieer vervolgens de projectlink 'Live site' onderaan de modal. + +> info +> Als je lokaal ontwikkelt, kun je [in de README van GitHub](https://github.com/discord/discord-example-app#running-app-locally) instructies vinden om verzoeken naar je lokale omgeving te leiden. + +Nu de link gekopieerd is, ga je naar de instellingen van je app vanuit [het ontwikkelaarsportaal](https://discord.com/developers/applications). + +Op de pagina **Algemene informatie** van je app staat de optie **Interactieve eindpunt-URL**. Hier kun je de URL van de app in plakken en er `/interactions` aanhangen. Dat is waar de Express-app geconfigureerd kan worden om verzoeken op te vangen. + +![Eindpunt-URL voor interacties in app-instellingen](interactions-url.png) + +Klik op **Wijzigingen opslaan** en controleer of het is gelukt om je eindpunt te verifiëren. + +In de voorbeeld-app wordt verificatie op twee manieren aangepakt: +- Het gebruikt de `PUBLIC_KEY` en het [pakket discord-interactions](https://github.com/discord/discord-interactions-js#usage) met een wrapper-functie (geïmporteerd uit `utils.js`) waardoor het geschikt wordt voor de [`verify`-interface van Express](http://expressjs.com/en/5x/api.html#express.json). Dit wordt toegepast op elk binnenkomend verzoek op je app. +- Het reageert op binnenkomende `PING`-verzoeken. + +Raadpleeg voor meer informatie over het voorbereiden van je app op het ontvangen van interacties [de interactiedocumentatie](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Werken met slashopdracht-verzoeken + +Nu het eindpunt geverifieerd is, ga je naar het `app.js`-bestand van je project en zoek je het codeblok voor de `/test`-opdracht: + +```javascript +// "test" opdracht +if (name === 'test') { + // Stuur een bericht naar het kanaal waarin de opdracht is geactiveerd + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Haalt een willekeurige emoji op om te versturen vanaf een hulpfunctie + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Bovenstaande code reageert op de interactie door een bericht naar het kanaal te sturen waar de interactie is ontstaan. Je kunt alle beschikbare reactiesoorten bekijken, zoals reageren met een modal, [in de documentatie](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` is een constante [die wordt geëxporteerd uit `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Ga naar je server en zorg ervoor dat de `/test`-slashopdracht van je app werkt. Als je hem activeert, moet je app een bericht versturen met de woorden 'hello world' erin, gevolgd door een willekeurige emoji. + +In de volgende sectie voegen we een extra opdracht toe met slashopdracht-opties, knoppen en keuzemenu's om het spelletje steen-papier-schaar op te bouwen. + +--- + +## Stap 4: Berichtonderdelen toevoegen + +Met de opdracht `/challenge` wordt ons steen-papier-schaar-achtige spelletje gestart. Als de opdracht wordt geactiveerd, stuurt de app een berichtonderdeel naar het kanaal, dat gebruikers tot het eind van het spel zal begeleiden. + +### Een opdracht met opties toevoegen + +De opdracht `/challenge`, `CHALLENGE_COMMAND` genaamd in `commands.js`, heeft verschillende `options`. In onze app zijn de opties verschillende objecten die een gebruiker kan kiezen bij het spelen van steen-papier-schaar, die worden gegenereerd met behulp van `RPSChoices`-codes in `game.js`. + +Je kunt meer lezen over opdrachtopties en hun structuur [in de documentatie](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> In deze gids staat niet veel over het `game.js`-bestand, maar verken het bestand gerust en wees niet bang opdrachten of opties in de opdrachten te wijzigen. + + + +Om met de opdracht `/challenge` te werken, moet je de volgende code toevoegen na het 'if block'`if name === “test”`: + +```javascript +// "challenge" opdracht +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Objectkeuze van gebruiker + const objectName = req.body.data.options[0].value; + + // Creëer een actief spel met bericht-ID als game-ID + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Voeg de game-ID bij om later te gebruiken + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Als je niet zeker weet waar je de code moet plakken, kun je de volledige code bekijken in `examples/app.js` in het Glitch-project of de root van `app.js` [op GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +De bovenstaande code doet een aantal dingen: +1. Hij analyseert de inhoud van het verzoek om de ID van de gebruiker op te halen die de slashopdracht heeft geactiveerd (`userId`) en de optie (objectkeuze) die de gebruiker heeft geselecteerd (`objectName`). +2. Hij voegt een nieuw spel toe aan het object `activeGames` met behulp van de interactie-ID. Het actieve spel registreert de `userId` en `objectName`. +3. Hij stuurt een bericht met daarin een knop met een `custom_id` van `accept_button_` naar het kanaal terug. + +> waarschuwing +> De voorbeeldcode gebruikt een object als opslag in het geheugen, maar voor productie-apps moet je een database gebruiken. + +Bij het sturen van een bericht met [berichtonderdelen](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) worden de individuele payloads aan een `components`-lijst toegevoegd. Onderdelen waar acties mee worden uitgevoerd (zoals knoppen) moeten deel uitmaken van een [actierij](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), die je in het codevoorbeeld ziet staan. + +Let op de unieke `custom_id` die meegestuurd wordt met berichtonderdelen. In dit geval is dat `accept_button_` waaraan de ID van het actieve spel is bijgevoegd. Een `custom_id` kan worden gebruikt om verzoeken af te handelen die Discord je stuurt als iemand interactie aangaat met het onderdeel, waarvan je straks een voorbeeld ziet. + +Als je nu de opdracht `/challenge` activeert en een optie kiest, zal je app een bericht sturen met de knop **Accepteren** erin. Laten we code toevoegen om de druk op de knop te verwerken. + + + + + +Als gebruikers interactie aangaan met een berichtonderdeel, verstuurt Discord een verzoek met één [interactietype](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) uit `3` opties (of de waarde van het `MESSAGE_COMPONENT` als `discord-interactions` wordt gebruikt). + +Om een verwerker in te stellen voor de knop, controleren we het `type` interactie en matchen we de `custom_id`. + +Plak de volgende code onder de typeverwerker voor `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id wordt ingesteld in payload bij versturen berichtonderdeel +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Haal de bijbehorende game-ID op + const gameId = componentId.replace('accept_button_', ''); + // Verwijder bericht met token in verzoekinhoud + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Haalt een willekeurige emoji op om te versturen vanaf een hulpfunctie + content: 'What is your object of choice?', + // Geeft aan dat het een kortstondig bericht wordt + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Voeg game-ID bij + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Verwijder eerder bericht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +De bovenstaande code: +1. Zoekt naar een `custom_id` die overeenkomt met wat we oorspronkelijk hebben verstuurd (in dit geval begint dat met `accept_button_`). Bij de aangepaste ID is de game-ID gevoegd, zodat we die kunnen opslaan in `gameID`. +2. [Verwijdert het oorspronkelijke bericht](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) door een webhook aan te roepen met behulp van `node-fetch` en door de unieke interactie-`token` door te geven in de inhoud van het verzoek. +3. Reageert op het verzoek door een bericht te sturen met een keuzemenu dat de objectkeuzes voor de game bevat. De payload is vergelijkbaar met de vorige, met uitzondering van de `options`-lijst en `flags: 64`, [die aangeeft dat het bericht kortstondig is](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +De `options`-lijst wordt gevuld met behulp van de `getShuffledOptions()`-methode in `game.js`, die de `RPSChoices`-waarden manipuleert om te passen bij de vorm van de [berichtcomponentopties](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +Het laatste wat je moet toevoegen is een code om keuzemenu-interacties te verwerken en het resultaat van het spel naar een kanaal te sturen. + +Aangezien keuzemenu's gewoon een berichtonderdeel zijn, is de code om de bijbehorende interacties te verwerken vergelijkbaar met knoppen. + +Pas de bovenstaande code aan voor het keuzemenu: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id wordt ingesteld in payload bij versturen berichtonderdeel +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Haal de bijbehorende game-ID op + const gameId = componentId.replace('accept_button_', ''); + // Verwijder bericht met token in verzoekinhoud + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Haalt een willekeurige emoji op om te versturen vanaf een hulpfunctie + content: 'What is your object of choice?', + // Geeft aan dat het een kortstondig bericht wordt + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Voeg game-ID bij + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Verwijder eerder bericht + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // Haal de bijbehorende game-ID op + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Haal de gebruikers-ID en objectkeuze voor de reagerende gebruiker op + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Bereken resultaat met hulpfunctie + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Verwijder game uit opslag + delete activeGames[gameId]; + // Update bericht met token in verzoekinhoud + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Verstuur resultaten + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Update kortstondig bericht + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Net zoals de eerdere code, haalt de bovenstaande code de gebruikers-ID en de objectkeuze op uit het interactieverzoek. + +Die informatie wordt samen met de ID van de oorspronkelijke gebruiker en de keuze van het `activeGames`-object doorgegeven aan de functie `getResult()`. `getResult()` bepaalt de winnaar en bouwt een leesbare string om naar het kanaal terug te sturen. + +We roepen ook nog een andere webhook aan, dit keer om [het kortstondige opvolgbericht te updaten](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), aangezien dat niet kan worden verwijderd. + +Als laatste worden de resultaten verstuurd naar het kanaal met behulp van het interactiereactietype `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +En dat was het! 🎊 Nu kun je je app testen en ervoor zorgen dat alles werkt. + +--- + +## Volgende stappen + +Gefeliciteerd met het bouwen van je eerste Discord-app! 🎊 + +Hopelijk heb je iets opgestoken over Discord-apps, hoe je ze kunt configureren en hoe je ze interactief kunt maken. Je kunt nu je app verder uitbouwen of ontdekken wat er nog meer mogelijk is: +- Lees **[de documentatie](#DOCS_INTRO)** voor meer informatie over API-functies +- Kijk de `examples/`-map van dit project door voor kleinere codevoorbeelden, speciaal voor bepaalde functies +- Check de **[communityhulpbronnen](#DOCS_TOPICS_COMMUNITY_RESOURCES)** voor tools in verschillende coderingstalen die door communityleden worden beheerd +- Lees onze tutorial over het [hosten van Discord-apps op Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Word lid van de **[Discord-ontwikkelaarsserver](https://discord.gg/discord-developers)** om vragen te stellen over de API, deel te nemen aan door het Discord API-team gehoste evenementen en met andere ontwikkelaars te praten diff --git a/docs/pl/Getting_Started.mdx b/docs/pl/Getting_Started.mdx new file mode 100644 index 0000000000..c49e2fdb9e --- /dev/null +++ b/docs/pl/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Tworzenie pierwszej aplikacji Discorda + +Aplikacje Discorda pozwalają spersonalizować i wzbogacić serwery przy pomocy API i interaktywnych funkcji. W tym przewodniku dowiesz się, jak stworzyć pierwszą aplikację Discorda w języku JavaScript, która wykorzystuje polecenia z ukośnikiem, wysyła wiadomości i reaguje na interakcje z elementami. + +Zaczniemy od stworzenia aplikacji Discorda, która pozwala członkom serwera grać w papier, kamień, nożyce (z 7 wyborami zamiast 3 wyborów, jak w tradycyjnej wersji gry). Ten przewodnik jest przeznaczony dla początkujących, ale zakłada, że znasz podstawy języka [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +Oto, jak będzie wyglądała gotowa aplikacja: + +![Demonstracja przykładowej aplikacji](getting-started-demo.gif) + +Poniżej przedstawiono szczegółowy zarys przepływu użytkowników: + +1. Użytkownik 1 rozpoczyna nową grę i wybiera obiekt przy pomocy polecenia z ukośnikiem `/challenge` +2. Na kanał zostaje wysłana wiadomość z przyciskiem zachęcającym innych do przyjęcia wyzwania +3. Użytkownik 2 naciska przycisk **Accept** (Przyjmij) +4. Użytkownik 2 otrzymuje znikającą wiadomość, w której wybiera obiekt +5. Wynik gry jest publikowany dla wszystkich na pierwotnym kanale + + + +- **[Repozytorium GitHuba](https://github.com/discord/discord-example-app)**, gdzie znajdziesz kod z tego przewodnika wraz z dodatkowymi przykładami kodu przedstawiającymi określone funkcje. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, biblioteka zawierająca typy i pomocnicze funkcje do aplikacji Discorda. +- **[Express](https://expressjs.com)**, popularny framework sieciowy JavaScript, którego użyjemy do utworzenia serwera, na który Discord może wysyłać żądania. +- **[Glitch](https://glitch.com/)**, internetowe środowisko, które upraszcza projektowanie i hostowanie aplikacji na wczesnym etapie prototypu i rozwoju. Możesz też projektować aplikację lokalnie przy pomocy narzędzia takiego jak **[ngrok](https://ngrok.com/)**. + + +--- + +## Krok 1: Tworzenie aplikacji + +Najpierw musisz stworzyć aplikację w portalu deweloperów, jeśli jeszcze jej nie masz: + + + +Wprowadź nazwę aplikacji i naciśnij **Stwórz**. + +Po utworzeniu aplikacji zostanie wyświetlona strona **Przegląd** ustawień aplikacji, gdzie możesz zaktualizować podstawowe dane swojej aplikacji takie jak jej opis i ikona. Znajdziesz tutaj również **ID aplikacji** i **końcowy adres URL interakcji**, które wykorzystamy w późniejszej części przewodnika. + +### Konfigurowanie bota + +W następnej kolejności skonfigurujemy [użytkownika bota](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) Twojej aplikacji, dzięki któremu będzie ona wyglądać i zachowywać się podobnie do innych członków serwera. + +Na lewym pasku bocznym kliknij **Bot**. Na tej stronie możesz skonfigurować ustawienia takie jak [uprawnienia intent typu „privileged”](#DOCS_TOPICS_GATEWAY/privileged-intents) lub określić, czy bot może być instalowany przez innych użytkowników. + + +Uprawnienia intent określają, które zdarzenia Discord będzie wysyłać do Twojej aplikacji, gdy tworzysz [połączenie API bramki](#DOCS_TOPICS_GATEWAY). Przykładowo jeśli chcesz, aby aplikacja wykonała jakąś czynność, gdy użytkownicy dodadzą reakcję do wiadomości, możesz przekazać uprawnienie intent `GUILD_MESSAGE_REACTIONS` (`1 << 10`). + +Niektóre uprawnienia intent są „[privileged](#DOCS_TOPICS_GATEWAY/privileged-intents)”, co znaczy, że zezwalają aplikacji na dostęp do danych, które można uznać za wrażliwe (takich jak zawartość wiadomości). Uprawnienia intent typu „privileged” są wyświetlane i mogą zostać włączone/wyłączone na stronie **Bot** ustawień aplikacji. Standardowe uprawnienia intent („non-privileged”) nie wymagają dodatkowych uprawnień ani konfiguracji. + +Więcej informacji na temat uprawnień intent i pełną ich listę, wraz z powiązanymi zdarzeniami, znajdziesz w [dokumentacji bramki](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Karta Bot w ustawieniach aplikacji](app-add-bot.png) + +Na stronie **Bot** znajduje się sekcja **Token**, gdzie możesz skopiować i zresetować token bota. + +Tokeny bota służą do uwierzytelniania żądań API i zawierają uprawnienia użytkownika bota, co czyni je *bardzo wrażliwymi*. *Nigdy* nie udostępniaj swojego tokena ani nie umieszczaj go w systemie kontroli wersji. + +Skopiuj token i zapisz go w bezpiecznym miejscu (np. menedżerze haseł). + +> ostrzeżenie +> Nie będzie można wyświetlić tokena ponownie, chyba że wygenerujesz go od nowa, więc przechowaj token w bezpiecznym miejscu. + +### Dodawanie zakresów i uprawnień bota + +Aplikacje potrzebują zgody instalujących je użytkowników, aby wykonywać czynności na Discordzie (takie jak tworzenie polecenia z ukośnikiem lub pobieranie listy członków serwera). Wybierzmy kilka zakresów i uprawnień, o których przyznanie będziemy prosić przed instalacją aplikacji. + + +Podczas tworzenia aplikacji zakresy i uprawnienia określają, co Twoja aplikacja może robić i do czego ma dostęp na serwerach Discorda. + +- [Zakresy OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) określają, do których danych aplikacja może uzyskiwać dostęp i jakie czynności może wykonywać w imieniu instalującego lub uwierzytelniającego użytkownika. +- [Uprawnienia](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) są szczegółowymi uprawnieniami dla użytkownika bota – takimi samymi jak te, które posiadają inni użytkownicy na Discordzie. Uprawnienia te mogą zostać przyznane przez instalującego użytkownika lub zaktualizowane później w ustawieniach serwera bądź przy pomocy [nadpisań uprawnień](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Kliknij **OAuth2** na lewym pasku bocznym, a następnie wybierz **Generator adresu URL**. + +> informacje +> Generator adresu URL tworzy łącze instalacyjne na podstawie zakresów i uprawnień wybranych dla aplikacji. Możesz użyć łącza do instalacji aplikacji na swoim serwerze lub udostępnić je innym, aby mogli zainstalować aplikację. + +Na razie dodaj dwa zakresy: +- `applications.commands`, który umożliwia aplikacji tworzenie [poleceń](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot` dodaje Twojego użytkownika bota. Po wybraniu `bot` możesz również wybrać różne uprawnienia bota. Na razie zaznacz tylko **Wysyłanie wiadomości**. + +Zobacz listę wszystkich [zakresów OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) lub przeczytaj więcej na temat [uprawnień](#DOCS_TOPICS_PERMISSIONS) w dokumentacji. + +### Instalacja aplikacji + +Po dodaniu zakresów powinien zostać wyświetlony adres URL, który możesz skopiować w celu instalacji aplikacji. + +![Zrzut ekranu generatora adresu URL](url-generator.png) + +> informacje +> Podczas pracy nad aplikacjami należy budować i testować je na serwerze, który nie jest aktywnie używany przez innych. Jeśli nie masz jeszcze własnego serwera, możesz [utworzyć go za darmo](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Skopiuj powyższy adres URL i wklej go w swojej przeglądarce. Zostanie wyświetlony interfejs instalacji, w którym należy upewnić się, że instalujesz aplikację na serwerze, na którym możesz rozwijać ją i testować. + +Po zainstalowaniu aplikacji przejdź do serwera, aby zobaczyć, czy została do niego dodana ✨ + +Po skonfigurowaniu i zainstalowaniu aplikacji możemy zacząć pracę nad nią. + +--- + +## Krok 2: Uruchomienie aplikacji + +Cały kod przykładowej aplikacji można znaleźć w [repozytorium GitHuba](https://github.com/discord/discord-example-app). + +Aby uprościć nieco pracę, aplikacja wykorzystuje bibliotekę [discord-interactions](https://github.com/discord/discord-interactions-js), która zawiera typy i funkcje pomocnicze. Jeśli wolisz użyć innych języków lub bibliotek, zobacz dokumentację [Zasoby społeczności](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Edycja projektu + +W tym przewodniku używamy narzędzia Glitch, które pozwala sklonować aplikację i pracować nad nią w przeglądarce. Jeśli wolisz pracować nad aplikacją lokalnie, zobacz instrukcje dotyczące używania narzędzia ngrok [w README](https://github.com/discord/discord-example-app#running-app-locally). + +> informacje +> Choć rozwiązanie Glitch znakomicie nadaje się do pracy nad aplikacją i jej testowania, [ma ograniczenia techniczne,](https://help.glitch.com/kb/article/17-technical-restrictions/) więc należy rozważyć użycie innych dostawców usług hostingowych do publicznej wersji aplikacji. + +Aby zacząć, **[edytuj (lub sklonuj) projekt Glitch 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Po edytowaniu projektu zostanie otwarty nowy projekt Glitch. + + +![Przegląd projektu Glitch](glitch-project.png) + +- **Nazwa projektu** to unikalna nazwa produktu widoczna w lewym górnym rogu +- **`.env`** to plik, w którym są przechowywane wszystkie Twoje dane uwierzytelniające do aplikacji +- **Dzienniki** zawierają dane wyjściowe projektu – pomagają one w ustaleniu, czy aplikacja działa; znajdziesz tu również informacje o wszelkich błędach występujących w aplikacji +- Przycisk **Udostępnij** w prawym górnym rogu pozwala uzyskać aktywny adres URL projektu, który będzie potrzebny do skonfigurowania interaktywności w dalszej części przewodnika + + +#### Struktura projektu + +Wszystkie pliki projektu są widoczne po lewej stronie projektu Glitch. Poniżej przedstawiono przegląd głównych folderów i plików: + +``` +├── examples -> krótkie, skupione na określonych funkcjach aplikacje przykładowe, +│ ├── app.js -> gotowy kod app.js, +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> Twoje dane uwierzytelniające i ID, +├── app.js -> główny punkt wejścia aplikacji, +├── commands.js -> payloady poleceń z ukośnikiem + elementy pomocnicze, +├── game.js -> logika gry w papier, kamień, nożyce, +├── utils.js -> funkcje narzędzi i wyliczenia. +├── package.json +├── README.md +└── .gitignore +``` + +### Dodawanie danych uwierzytelniających + +Plik `app.js` zawiera już kod, ale potrzebujesz tokena i ID aplikacji, aby przesyłać żądania. Wszystkie dane uwierzytelniające mogą być przechowywane bezpośrednio w pliku `.env`. + +Najpierw skopiuj token użytkownika bota, o którym była mowa wcześniej, i wklej go w parametrze **`DISCORD_TOKEN`** w pliku `.env`. + +Następnie przejdź do strony **Przegląd** aplikacji i skopiuj **ID aplikacji** oraz **publiczny klucz**. Wklej te wartości w pliku `.env` jako parametry **`APP_ID`** i **`PUBLIC_KEY`**. + +Po skonfigurowaniu danych uwierzytelniających czas zainstalować i wdrożyć polecenia z ukośnikiem. + +### Instalacja poleceń z ukośnikiem + +> informacje +> Aplikacja wykorzystuje moduł [`node-fetch`](https://github.com/node-fetch/node-fetch) do instalacji poleceń z ukośnikiem. Kod odpowiedzialny za instalację znajduje się w pliku `utils.js`, w funkcji `DiscordRequest()`. + +Projekt zawiera skrypt `register`, którego możesz użyć do instalacji poleceń w elemencie `ALL_COMMANDS`, który jest zdefiniowany na końcu pliku `commands.js`. Instaluje on polecenia jako globalne polecenia, wywołując punkt końcowy [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) API HTTP. + +Jeśli chcesz spersonalizować polecenia lub dodać ich więcej, możesz odnieść się do struktury poleceń przedstawionej w [ich dokumentacji](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Uruchom skrypt `register`, klikając **Terminal** na dole projektu Glitch i wklejając następujące polecenie: + +``` +npm run register +``` + +Naciśnij Enter, aby uruchomić polecenie. + +Jeśli wrócisz do swojego serwera, zobaczysz polecenia z ukośnikiem. Ale jeśli spróbujesz je uruchomić, nic się nie stanie, ponieważ Twoja aplikacja nie otrzymuje ani nie obsługuje żądań od Discorda. + + +Discord ma dwa API, które można łączyć w tworzonych aplikacjach: + +- **[API HTTP](#DOCS_REFERENCE/http-api)** jest API w stylu REST przeznaczonym do ogólnych operacji takich jak wysyłanie i aktualizowanie danych na Discordzie lub pobieranie informacji o zasobie. +- **[API bramki](#DOCS_REFERENCE/gateway-websocket-api)** to oparte na protokole WebSocket API przydatne do utrzymywania stanu lub nasłuchiwania zdarzeń na serwerze Discorda. Nie będziemy używać go w tym przewodniku, ale więcej informacji na temat tworzenia połączenia z bramką i różnych zdarzeń, które możesz nasłuchiwać, znajdziesz w [dokumentacji bramki](#DOCS_TOPICS_GATEWAY). + + +--- + +## Krok 3: Obsługa interaktywności + +Aby umożliwić aplikacji otrzymywanie żądań w postaci poleceń z ukośnikiem (i innych interakcji), Discord potrzebuje adresu URL, na który będzie je wysyłać. Można go skonfigurować w ustawieniach aplikacji, w polu **Końcowy adres URL interakcji**. + +### Dodawanie końcowego adresu URL interakcji + +Projekty Glitch mają publiczny adres URL, który jest domyślnie ujawniony. Skopuj go, klikając przycisk **Udostępnij** w prawym górnym rogu, a następnie skopiuj łącze projektu „Aktywna witryna” blisko dolnej części okna. + +> informacje +> Jeśli pracujesz nad aplikacją lokalnie, zobacz instrukcje dotyczące przekazywania żądań do lokalnego środowiska [w README na GitHubie](https://github.com/discord/discord-example-app#running-app-locally). + +Po skopiowaniu łącza przejdź do ustawień aplikacji z poziomu [portalu deweloperów](https://discord.com/developers/applications). + +Na stronie **Informacje ogólne** aplikacji znajduje się opcja **Końcowy adres URL interakcji**, gdzie możesz wkleić adres URL swojej aplikacji i dodać do niego ciąg `/interactions`, który wskazuje lokalizację, gdzie aplikacja Express będzie nasłuchiwać żądań. + +![Końcowy adres URL interakcji w ustawieniach aplikacji](interactions-url.png) + +Kliknij **Zapisz zmiany** i upewnij się, że końcowy adres został pomyślnie zweryfikowany. + +Przykładowa aplikacja obsługuje weryfikację na dwa sposoby: +- Wykorzystuje `PUBLIC_KEY` i [pakiet discord-interactions](https://github.com/discord/discord-interactions-js#usage) z funkcją wrapper (zaimportowaną z pliku `utils.js`), która zapewnia zgodność z interfejsem [Express`verify`](http://expressjs.com/en/5x/api.html#express.json). Jest ona uruchamiana za każdym razem, gdy Twoja aplikacja otrzyma żądanie. +- Funkcja reaguje na przychodzące żądania `PING`. + +Więcej informacji na temat przygotowywania aplikacji na przyjmowanie interakcji znajdziesz w [dokumentacji interakcji](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Obsługa poleceń z ukośnikiem + +Po zweryfikowaniu końcowego adresu URL przejdź do pliku `app.js` w projekcie i znajdź blok kodu odpowiadający za obsługę polecenia `/test`: + +```javascript +// polecenie „test” +if (name === 'test') { + // Wysyła wiadomość na kanał, na którym aktywowano polecenie + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Pobiera losowe emoji do wysłania z funkcji pomocniczej + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Powyższy kod reaguje na interakcję z wiadomością na kanale, z którego pochodzi. Możesz zobaczyć wszystkie dostępne typy reakcji, takie jak reagowanie oknem, [w dokumentacji](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> informacje +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` jest stałą [eksportowaną z pliku pakietu `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Przejdź do swojego serwera i upewnij się, że polecenie z ukośnikiem `/test` działa. Gdy je aktywujesz, aplikacja powinna wysłać wiadomość z tekstem „hello world” i losowym emoji. + +W następnym punkcie dodamy polecenie wykorzystujące opcje polecenia z ukośnikiem, przyciski i menu wyboru, aby stworzyć grę w papier, kamień, nożyce. + +--- + +## Krok 4: Dodanie elementów wiadomości + +Polecenie `/challenge` będzie uruchamiać grę w stylu gry w papier, kamień, nożyce. Po aktywowaniu polecenia aplikacja wyśle na kanał wiadomości instruujące użytkowników, jak ukończyć grę. + +### Dodawanie polecenia z opcjami + +Polecenie `/challenge`, zwane `CHALLENGE_COMMAND` w pliku `commands.js`, ma szereg opcji (`options`). W naszej aplikacji opcje są obiektami oznaczającymi różne elementy, które użytkownik może wybrać podczas gry w papier, kamień, nożyce, generowane przy pomocy kluczy `RPSChoices` w pliku `game.js`. + +Więcej o opcjach poleceń i ich strukturze przeczytasz [w dokumentacji](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> informacje +> Choć w tym przewodniku nie zagłębimy się w plik `game.js`, możesz poeksperymentować z nim, zmieniając polecenia lub ich opcje. + + + +Aby dodać obsługę polecenia `/challenge`, dodaj następujący kod po bloku „if” `if name === “test”`: + +```javascript +// Polecenie „challenge” +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Wybór obiektu użytkownika + const objectName = req.body.data.options[0].value; + + // Tworzy aktywną grę, używając ID wiadomości jako ID gry + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Dołącza ID gry do późniejszego użytku + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> informacje +> Jeśli nie wiesz, gdzie wkleić kod, możesz zobaczyć pełen kod w pliku `examples/app.js` w projekcie Glitch lub w nadrzędnym pliku `app.js` [na GitFHubie](https://github.com/discord/discord-example-app/blob/main/app.js). + +Powyższy kod wykonuje szereg czynności: +1. Przetwarza treść żądania w celu uzyskania ID użytkownika, który aktywował polecenie z ukośnikiem (`userId`), i wybraną przez niego opcję (wybrany obiekt) (`objectName`). +2. Dodaje nową grę do obiektu `activeGames` przy pomocy ID interakcji. Aktywna gra zapisuje elementy `userId` i `objectName`. +3. Wysyła na kanał wiadomość z przyciskiem z wartością `accept_button_` w polu `custom_id`. + +> ostrzeżenie +> Przykładowy kod wykorzystuje obiekt przechowywany w pamięci, ale na potrzeby publicznej wersji aplikacji zaleca się użycie bazy danych. + +Przy wysyłaniu [elementów wiadomości](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) indywidualne payloady są dodawane do tablicy `components`. Interaktywne elementy (takie jak przyciski) muszą znajdować się w [rzędzie czynności](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), który jest widoczny w przykładowym kodzie. + +Zwróć uwagę na unikalny `custom_id` wysyłany z elementami wiadomości, w tym przypadku `accept_button_` z dodanym ID gry. `custom_id` pozwala obsłużyć żądania przesyłane przez Discorda, gdy ktoś wejdzie w interakcję z elementem – zobaczysz za chwilę, jak to wygląda. + +Teraz gdy użyjesz polecenia `/challenge` i wybierzesz opcję, Twoja aplikacja wyśle wiadomość z przyciskiem **Accept** (Akceptuj). Dodajmy kod odpowiadający za obsługę naciśnięcia przycisku. + + + + + +Gdy użytkownicy wejdą w interakcję z elementem wiadomości, Discord wyśle żądanie z [typem interakcji](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (lub wartością `MESSAGE_COMPONENT` przy używaniu `discord-interactions`). + +W celu skonfigurowania procedury obsługi przycisku sprawdzimy typ (`type`) interakcji, a następnie `custom_id`. + +Wklej następujący kod pod procedurą obsługi typu dla `APPLICATION_COMMAND`: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id konfigurowany w payloadzie przy wysyłaniu elementu wiadomości +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Uzyskuje powiązany ID gry + const gameId = componentId.replace('accept_button_', ''); + // Usuwa wiadomość z tokenem w treści żądania + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Pobiera losowe emoji do wysłania z funkcji pomocniczej + content: 'What is your object of choice?', + // Określa, że wiadomość będzie znikająca + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Dodaje ID gry + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Usuwa poprzednią wiadomość + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Powyższy kod: +1. Sprawdza, czy parametr `custom_id` jest zgodny z pierwotnie wysłanym parametrem (w tym przypadku zaczyna się od `accept_button_`). Zawiera on również ID aktywnej gry, więc przechowujemy go w parametrze `gameID`. +2. [Usuwa pierwotną wiadomość](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response), wywołując webhook przy pomocy `node-fetch` i przekazując `token` unikalnej interakcji w treści żądania. Jest to konieczne, aby zachować porządek na kanale i zapobiec klikaniu przycisku przez innych użytkowników. +3. Wysyła w odpowiedzi na żądanie wiadomość zawierającą menu wyboru obiektu do gry. Payload powinien wyglądać podobnie do poprzedniego, z wyjątkiem tabeli `options` i parametru `flags: 64`, [który oznacza, że wiadomość jest znikająca](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +Tabela `options` jest wypełniana przy pomocy metody `getShuffledOptions()` w pliku `game.js`, która dostosowuje wartości `RPSChoices` do formatu [opcji elementu wiadomości](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +Na koniec należy dodać kod odpowiedzialny za obsługę interakcji z menu wyboru i wysyłanie wyniku gry na kanał. + +Ponieważ menu wyboru to tylko kolejny element wiadomości, kod odpowiedzialny za interakcję z nim będzie praktycznie taki sam jak w przypadku przycisków. + +Zmodyfikuj powyższy kod pod kątem obsługi menu wyboru: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id konfigurowany w payloadzie przy wysyłaniu elementu wiadomości +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // Uzyskuje powiązany ID gry + const gameId = componentId.replace('accept_button_', ''); + // Usuwa wiadomość z tokenem w treści żądania + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Pobiera losowe emoji do wysłania z funkcji pomocniczej + content: 'What is your object of choice?', + // Określa, że wiadomość będzie znikająca + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Dodaje ID gry + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Usuwa poprzednią wiadomość + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // Uzyskuje powiązany ID gry + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Pobiera ID i obiekt wybrany przez odpowiadającego użytkownika + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Oblicza wynik funkcji pomocniczej + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Usuwa grę z dysku + delete activeGames[gameId]; + // Aktualizuje wiadomość z tokenem w treści żądania + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Wysyła wynik + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Aktualizuje znikającą wiadomość + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Podobnie jak w przypadku poprzedniego kodu, powyższy kod pobiera ID użytkownika i wybrany przez niego obiekt z żądania interakcji. + +Te informacje, wraz z ID i wyborem pierwotnego użytkownika z obiektu `activeGames`, są przekazywane do funkcji `getResult()`. `getResult()` określa zwycięzcę, a następnie tworzy czytelny ciąg, który zostanie wysłany na kanał. + +Wywołujemy również kolejny webhook, tym razem w celu [aktualizacji następczej znikającej wiadomości,](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) ponieważ nie można jej usunąć. + +Na koniec wyniki są wysyłane na kanał przy pomocy typu reakcji na interakcję `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +To już wszystko 🎊 Możesz teraz przetestować swoją aplikację i upewnić się, że wszystko działa. + +--- + +## Kolejne kroki + +Gratulujemy utworzenia pierwszej aplikacji Discorda! 🤖 + +Mamy nadzieję, że ten artykuł przybliżył Ci nieco aplikacje Discorda i to, jak można konfigurować je i dodawać do nich interaktywne elementy. Teraz możesz kontynuować pracę nad swoją aplikacją lub zobaczyć inne możliwości: +- Przeczytaj **[dokumentację](#DOCS_INTRO)**, w której znajdziesz szczegółowe informacje o funkcjach API +- Zobacz folder `examples/` tego projektu, który zawiera mniejsze, skupione na określonych funkcjach przykłady kodu +- Zapoznaj się z **[zasobami społeczności](#DOCS_TOPICS_COMMUNITY_RESOURCES)** dotyczącymi przeznaczonych do określonych języków narzędzi tworzonych przez użytkowników Discorda +- Przeczytaj nasz samouczek dotyczący [hostowania aplikacji Discorda w serwisie Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Dołącz do **[serwera Discord Developers](https://discord.gg/discord-developers)**, gdzie możesz zadawać pytania na temat API, uczestniczyć w wydarzeniach organizowanych przez zespół API Discorda i rozmawiać z innymi deweloperami diff --git a/docs/pt-br/Getting_Started.mdx b/docs/pt-br/Getting_Started.mdx new file mode 100644 index 0000000000..752271a59e --- /dev/null +++ b/docs/pt-br/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# Criando seu primeiro app Discord + +Apps Discord permitem que você personalize e estenda seus servidores usando uma coleção de APIs e recursos interativos. Esse guia orientará você a criar seu primeiro app Discord usando JavaScript e, até o final, você terá um app que usa comandos de barra, envia mensagens e responde a interações de componentes. + +Vamos criar um app Discord que permite que os membros do servidor joguem pedra-papel-tesoura (com 7 opções em vez das 3 de sempre). Esse guia é voltado para iniciantes, mas presume um entendimento básico de [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics). + + +O app pronto ficará mais ou menos assim: + +![Demo do app de exemplo](getting-started-demo.gif) + +Só para deixar o fluxo de interações mais claro: + +1. O Usuário 1 inicia um novo jogo e escolhe o objeto usando o comando de barra `/challenge` do app. +2. Uma mensagem é publicada no canal com um botão convidando outros usuários a aceitarem o desafio. +3. O Usuário 2 aperta o botão **Aceitar** +4. O Usuário 2 recebe uma mensagem efêmera onde escolhe qual objeto quer usar. +5. O resultado do jogo é postado no canal original para que todos vejam. + + + +- **[Repositório do GitHub](https://github.com/discord/discord-example-app)** onde está hospedado o código deste guia, junto com alguns exemplos adicionais dos códigos de cada recurso. +- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, uma biblioteca que fornece tipos e funções auxiliares para apps Discord. +- **[Express](https://expressjs.com)**, um framework web popular para JavaScript, que usaremos para criar um servidor onde o Discord possa mandar solicitações. +- **[Glitch](https://glitch.com/)**, um ambiente online que simplifica a construção e hospedagem de apps nos estágios iniciais de prototipagem e desenvolvimento. Você também pode desenvolver localmente nele com uma ferramenta como a **[ngrok](https://ngrok.com/)**. + + +--- + +## Passo 1: Criando um app + +Primeiro, você precisa criar o app no portal do desenvolvedor, caso ainda não tenha um: + + + +Insira um nome para seu app, depois aperte **Criar**. + +Após criar seu app, você chegará na página de **Visão Geral** das configurações, onde você pode atualizar informações básicas do seu app, como a descrição e o ícone. Você também verá uma **ID de Aplicativo** e **URL de Endpoint de Interações**, que usaremos daqui a pouco no guia. + +### Configurando seu bot + +Agora, vamos configurar o [usuário-bot](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) para o seu app, de modo que ele se pareça e se comporte de forma similar a outros membros do servidor. + +Na barra lateral esquerda, clique em **Bot**. Nesta página, você pode definir configurações como as [intenções privilegiadas](#DOCS_TOPICS_GATEWAY/privileged-intents) ou se ele pode ser instalado por outros usuários. + + +Intenções determinam quais eventos o Discord enviará para o seu app quando você criar uma [conexão ao API de Gateway](#DOCS_TOPICS_GATEWAY). Por exemplo, se você quiser que seu app faça alguma coisa quando usuários adicionam uma reação a uma mensagem, você pode passar a intenção `GUILD_MESSAGE_REACTIONS` (`1 << 10`). + +Algumas intenções são [privilegiadas](#DOCS_TOPICS_GATEWAY/privileged-intents), ou seja, elas permitem que seu app acesse dados que podem ser considerados sigilosos (como conteúdo de mensagens). Intenções privilegiadas aparecem e podem ser ligadas ou desligadas na página de **Bots** das configurações do seu app. Intenções padrão (não-privilegiadas) não requerem permissões ou configurações adicionais. + +Para mais informações sobre as intenções e uma lista completa das intenções disponíveis e dos eventos associados a elas, leia a [documentação do Gateway](#DOCS_TOPICS_GATEWAY/gateway-intents). + + +![Aba de Bots nas configurações do app](app-add-bot.png) + +Também há uma seção **Token** na página **Bot**, que permite que você copie e redefina o token do seu bot. + +Tokens de bots são usados para autorizar solicitações de API e contêm as permissões do seu usuário-bot, ou seja, são *extremamente confidenciais*. Certifique-se de *nunca* compartilhar seu token ou incluí-lo em qualquer tipo de controle de versão. + +Pode copiar o token, e guarde-o em um lugar seguro (como um gerenciador de senhas). + +> aviso +> Você não conseguirá mais ver seu token a menos que gere um novo, então trate de guardá-lo em um lugar seguro. + +### Adicionando escopos e permissões de bot + +Apps precisam da permissão do usuário que o está instalando para realizar ações no Discord (como criar um comando de barra ou acessar uma lista de membros do servidor). Vamos selecionar alguns escopos e permissões para solicitar antes de instalar o app. + + +Ao criar um app, escopos e permissões determinam o que seu app pode fazer e acessar nos servidores do Discord. + +- [Escopos OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) determinam quais dados e quais ações seu app pode acessar e realizar, concedidos em nome de um usuário que esteja instalando ou autenticando o app. +- [Permissões](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) são as permissões granulares para seu usuário-bot, iguais às que outros usuários do Discord têm. Elas podem ser aprovadas pelo usuário que está instalando ou, mais tarde, atualizando o bot com configurações de servidor ou [redefinições de permissão](#DOCS_TOPICS_PERMISSIONS/permission-overwrites). + + +Clique em **OAuth2** na barra lateral, depois selecione o **gerador de URL**. + +> info +> O gerador de URL cria um link de instalação baseado nos escopos e permissões que você selecionou para o seu app. Você pode usar o link para instalar o app no seu próprio servidor, ou compartilhá-lo com outras pessoas para que elas as instalem. + +Por ora, adicione dois escopos: +- `applications.commands`, que permite que seu app crie [comandos](#DOCS_INTERACTIONS_APPLICATION_COMMANDS). +- `bot` adiciona seu usuário-bot. Após selecionar `bot`, também dá para selecionar várias permissões para o seu bot. Por ora, pode escolher só **Enviar Mensagens**. + +Leia a documentação para ver uma lista de todos os [escopos OAuth2](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) ou saber mais sobre [permissões](#DOCS_TOPICS_PERMISSIONS). + +### Instalando seu app + +Ao adicionar escopos, você deve ver um URL que pode copiar para instalar seu app. + +![Captura de tela do gerador de URL](url-generator.png) + +> info +> Ao desenvolver apps, é melhor criá-los e instalá-los em um servidor que ninguém usa. Se já não tiver seu próprio servidor, pode [criar um de graça](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-). + +Copie o URL acima e cole-o no seu navegador. A página vai te guiar pelo fluxo da instalação, onde você deve se certificar que está instalando seu app num servidor onde possa desenvolvê-lo e testá-lo. + +Após instalar seu app, você pode entrar no servidor e ver que ele entrou ✨ + +Com seu app configurado e instalado, vamos começar o desenvolvimento. + +--- + +## Passo 2: Executando seu app + +Todo o código usado no app de exemplo está disponível no [repositório do GitHub](https://github.com/discord/discord-example-app). + +Para simplificar o desenvolvimento, o app usa o [discord-interactions](https://github.com/discord/discord-interactions-js), que fornece tipos e funções auxiliares. Se você preferir usar outros idiomas ou bibliotecas, acesse a documentação dos [Recursos de Comunidade](#DOCS_TOPICS_COMMUNITY_RESOURCES). + +### Remixando o projeto + +Este guia usa o Glitch, que permite que você clone e desenvolva o app no seu navegador. Se você preferir desenvolver seu app localmente, o [LEIAME](https://github.com/discord/discord-example-app#running-app-locally) contém instruções sobre como usar o ngrok. + +> info +> Apesar do Glitch ser ótimo para desenvolvimento e testagem, ele tem restrições técnicas (ver https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions), então considere outras hospedagens quando for desenvolver para produção. + +Para começar, **[remixe (ou clone) o projeto do Glitch 🎏](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Após remixar o projeto, você abrirá um projeto novo do Glitch. + + +![Visão geral do projeto do Glitch](glitch-project.png) + +- Seu **nome de projeto** é um nome único para seu projeto, que aparece no canto superior-esquerdo. +- **`.env`** é o arquivo onde todas as suas credenciais do seu app são armazenadas. +- **Registros** são onde aparecem os resultados do seu projeto. Eles são úteis para verificar se o app está sendo executado ou ler informações sobre erros que o app encontrar. +- O botão **Compartilhar** no canto superior direito é onde aparece a URL do seu projeto, que você usará mais tarde neste guia para montar a interatividade. + + +#### Estrutura do projeto + +Todos os arquivos do projeto ficam do lado esquerdo do seu projeto do Glitch. Abaixo, uma visão geral das pastas e arquivos principais: + +``` +├── examples -> amostras de apps curtos de cada recurso +│ ├── app.js -> código app.js finalizado +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> suas credenciais e IDs +├── app.js -> entrypoint principal do app +├── commands.js -> payloads e auxiliares dos comandos de barra +├── game.js -> lógica específica do pedra-papel-tesoura +├── utils.js -> funções utilitárias e enums +├── package.json +├── README.md +└── .gitignore +``` + +### Adicionando credenciais + +Já existem alguns códigos no seu arquivo `app.js`, mas você precisará do token e ID do seu app para fazer solicitações. Todas as suas credenciais podem ser armazenadas diretamente no arquivo `.env`. + +Primeiro, copie o token do seu bot obtido anteriormente e cole-o na variável **`DISCORD_TOKEN`** do seu arquivo `.env`. + +Em seguida, navegue até a página **Visão Geral** do seu app, copie a **ID do app** e a **Chave Pública**. Cole os valores no seu arquivo `.env` como **`APP_ID`** e **`PUBLIC_KEY`**. + +Com suas credenciais configuradas, vamos instalar e direcionar os comandos de barra. + +### Instalando comandos de barra + +> info +> Para instalar comandos de barra, o app usa [`node-fetch`](https://github.com/node-fetch/node-fetch). Você pode ver a implementação da instalação em `utils.js` dentro da função `DiscordRequest()`. + +O projeto contém um script `register` que você pode usar para instalar os comandos em `ALL_COMMANDS`, que são definidos no fim de `commands.js`. Ele instala os comandos como globais chamando o endpoint [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) das APIs HTTP. + +Se quiser personalizar seus comandos ou adicionar novos, você pode consultar a estrutura de comando na [documentação de comandos](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure). + +Execute o script `register` clicando em **Terminal** na parte de baixo do seu projeto do Glitch e colando o seguinte comando: + +``` +npm run register +``` + +Aperte enter para executar o comando. + +Quando voltar lá para seu servidor, você deve ver os comandos de barra aparecendo. Mas, se tentar executá-los, nada vai acontecer, pois seu app não está recebendo ou processando solicitações do Discord. + + +O Discord tem duas APIs que você pode combinar como quiser para criar apps: + +- A **[API HTTP](#DOCS_REFERENCE/http-api)** é uma API tipo REST para operações gerais como o envio e atualização de dados no Discord, ou solicitações de dados sobre recursos. +- A **[API de Gateway](#DOCS_REFERENCE/gateway-websocket-api)** é uma API baseada em WebSocket que ajuda a manter o estado ou ouvir eventos que estão ocorrendo em um servidor Discord. Não vamos usá-la neste guia, mas você pode ler mais sobre como criar uma conexão de Gateway e os diferentes eventos que ela pode ouvir na [documentação de Gateway](#DOCS_TOPICS_GATEWAY). + + +--- + +## Passo 3: Lidando com a interatividade + +Para permitir que seu app receba solicitações de comando de barra (e outras interações), o Discord precisa de um URL público para onde mandá-las. Este URL pode ser configurado nas configurações do seu app, como o **URL de Endpoint de Interações**. + +### Adicionando um URL de Endpoint de Interações + +Projetos do Glitch têm um URL público exposto por padrão. Copie o URL do seu projeto clicando no botão **Compartilhar** no canto superior direito, depois copie o link do projeto "Live site" perto do final do modal. + +> info +> Se você estiver desenvolvendo localmente, há instruções sobre como direcionar solicitações ao seu ambiente local no [LEIAME do GitHub](https://github.com/discord/discord-example-app#running-app-locally). + +Com o link copiado, vá até as configurações do seu app no [portal do desenvolvedor](https://discord.com/developers/applications). + +Na página de **Informações Gerais** do seu app, há uma opção de **URL de Endpoint de Interação**, onde você deve colar o URL do seu app e colocar `/interactions` no fim dele, pois é daí que o app Express está configurado para esperar solicitações. + +![URL de Endpoint de Interações nas configurações do app](interactions-url.png) + +Clique em **Salvar Mudanças** e certifique-se que seu endpoint seja verificado corretamente. + +O app de exemplo faz a verificação de duas formas: +- Usando a `PUBLIC_KEY` e o [pacote discord-interactions](https://github.com/discord/discord-interactions-js#usage) com uma função wrapper (importada do `utils.js`) que faz ele se conformar à [interface `verify` do Express](http://expressjs.com/en/5x/api.html#express.json). Esse processo é realizado em cada solicitação que seu app recebe. +- Ele responde a solicitações `PING` recebidas. + +Você pode ler mais sobre como preparar seu app para receber interações na [documentação de interações](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction). + +### Processando solicitações de comando de barra + +Com o endpoint verificado, vá até o arquivo `app.js` do seu projeto e procure o bloco de código que cuida do comando `/test`: + +```javascript +// comando "test" +if (name === 'test') { + // Envia uma mensagem para o canal de onde o comando foi ativado + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Escolhe um emoji aleatório para enviar de uma função auxiliar + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +O código acima respondeu à interação com uma mensagem no canal na qual ela se originou. Você pode ver todos os tipos de respostas disponíveis (por exemplo, responder com um modal) [na documentação](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type). + +> info +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE` é uma constante [exportada do `discord-interactions`](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) + +Vá até seu servidor e certifique-se que o comando de barra `/test` do seu app esteja funcionando. Ao ativá-lo, o app deve mandar uma mensagem que contém "hello world" seguido de um emoji aleatório. + +Na seção a seguir, adicionaremos um comando adicional que usa opções de comando de barra, botões e menus de seleção para construir o jogo de pedra-papel-tesoura. + +--- + +## Passo 4: Adicionando componentes de mensagens + +Usaremos o comando `/challenge` para iniciar nosso jogo estilo pedra-papel-tesoura. Quando o comando é ativado, o app enviará componentes de mensagem ao canal, que guiarão os usuários para completar o jogo. + +### Adicionando um comando com opções + +O comando `/challenge`, chamado `CHALLENGE_COMMAND` no `commands.js`, tem um array de `options`. No nosso app, as opções são objetos representando coisas diferentes que usuários podem escolher enquanto jogam pedra-papel-tesoura, gerados usando chaves de `RPSChoices` em `game.js`. + +Você pode ler mais sobre opções de comando e a estrutura delas [na documentação](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure). + +> info +> Este guia não vai falar muito do arquivo `game.js`, mas fique à vontade para mexer nele, mudando os comandos ou as opções deles. + + + +Para lidar com o comando `/challenge`, adicione o seguinte código após o bloco "se" `if name === “test”`: + +```javascript +// comando "challenge" +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Objeto de escolha do usuário + const objectName = req.body.data.options[0].value; + + // Criar jogo ativo usando ID da mensagem como ID de jogo + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Anexar a ID do jogo para usar mais tarde + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> info +> Se não tiver certeza onde colar o código, você pode ver o código completo em `examples/app.js` no projeto do Glitch ou no root `app.js` [no GitHub](https://github.com/discord/discord-example-app/blob/main/app.js). + +O código acima faz algumas coisas: +1. Analisa o corpo da solicitação para obter a ID do usuário que ativou o comando de barra (`userId`) e a opção (escolha de objeto) que ele(a) selecionou (`objectName`). +2. Adiciona um novo jogo ao objeto `activeGames` usando a ID de interação. O jogo ativo registra o `userId` e o `objectName`. +3. Envia uma mensagem de volta ao canal com um botão contendo uma `custom_id` de `accept_button_`. + +> aviso +> O código de exemplo usa um objeto como armazenamento na memória, mas os apps para produção devem ter bases de dados. + +Ao enviar uma mensagem com [componentes de mensagem](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component), os payloads individuais são anexados a um array `components`. Componentes acionáveis (como botões) precisam estar dentro de uma [fileira de ações](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows), como aparece na amostra do código. + +Repare na `custom_id` enviada com componentes de mensagem (neste caso `accept_button_`) com a ID do jogo ativo anexada a ela. Uma `custom_id` pode ser usada para lidar com solicitações enviadas pelo Discord quando alguém interage com o componente. Você verá isso daqui a pouco. + +Agora, quando você usar o comando `/challenge` e escolher uma opção, seu app mandará uma mensagem com o botão **Aceitar**. Vamos adicionar um código para lidar com o apertar do botão. + + + + + +Quando usuários interagem com um componente de mensagem, o Discord envia uma solicitação com um [tipo de interação](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) de `3` (ou o valor `MESSAGE_COMPONENT` ao usar `discord-interactions`). + +Para montar um handler para o botão, vamos verificar o `type` da interação e alinhando com a `custom_id`. + +Cole o seguinte código sob o handler de tipo para `APPLICATION_COMMAND`s: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id definida no payload ao enviar o componente da mensagem +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // recebe a ID de jogo associada + const gameId = componentId.replace('accept_button_', ''); + // Exclui a mudança com o token no corpo da solicitação + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Escolhe um emoji aleatório para enviar de uma função auxiliar + content: 'What is your object of choice?', + // Indica que será uma mensagem efêmera + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Anexa a ID de jogo + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Exclui a mensagem anterior + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +O código acima: +1. Procura uma `custom_id` que combine com a enviada originalmente (neste caso, ela começa com `accept_button_`). A ID personalizada também tem a ID do jogo ativo anexada, então armazenamos ela na `gameID`. +2. [Exclui a mensagem original](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response) chamando um webhook através do `node-fetch` e passando o `token` de interação única no corpo da solicitação. Isso serve para manter o canal limpo e para impedir que outros usuários cliquem no botão. +3. Responde à solicitação enviando uma mensagem que contém um menu de seleção com as escolhas de objeto do jogo. O payload deve ser bem parecido com o anterior, com exceção do array de `options` e `flags: 64`, [que indica que a mensagem é efêmera](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message). + +O array de `options` é povoado usando o método `getShuffledOptions()` do `game.js`, que manipula os valores de `RPSChoices` para se conformar ao formato das [opções de componente de mensagem](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure). + + + + + +A última coisa a adicionar é um código que lide com interações do menu de seleção e envie os resultados do jogo para o canal. + +Já que menus de seleção são só outro componente de mensagem, o código que cuida das interações deles serão quase idênticos aos dos botões. + +Modifique o código acima para lidar com o menu de seleção: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id definida no payload ao enviar o componente da mensagem +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // recebe a ID de jogo associada + const gameId = componentId.replace('accept_button_', ''); + // Exclui a mudança com o token no corpo da solicitação + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Escolhe um emoji aleatório para enviar de uma função auxiliar + content: 'What is your object of choice?', + // Indica que será uma mensagem efêmera + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Anexa a ID de jogo + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Exclui a mensagem anterior + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // recebe a ID de jogo associada + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Recebe a ID de usuário e escolha de objeto do usuário que responde + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Calcula o resultado na função auxiliar + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Remove o jogo da armazenagem + delete activeGames[gameId]; + // Atualiza a mensagem com o token no corpo da solicitação + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Envia os resultados + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Atualiza a mensagem efêmera + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Parecido com códigos anteriores, o código acima busca a ID de usuário e a seleção de objeto da solicitação de interação. + +Essas informações, junto com a ID do usuário original e a seleção feita no objeto `activeGames`, são passadas para a função `getResult()`. A `getResult()` determina o vencedor, depois monta uma string legível para enviar de volta ao canal. + +Também estamos chamando outro webhook, desta vez para [atualizar a mensagem efêmera complementar](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message), já que ela não pode ser excluída. + +Por fim, os resultados são enviados no canal usando o tipo de interação de resposta `CHANNEL_MESSAGE_WITH_SOURCE`. + + + +...e pronto 🎊 Pode testar seu app pra garantir que está tudo funcionando. + +--- + +## Próximos passos + +Parabéns por criar seu primeiro app Discord! 🤖 + +Esperamos que você tenha aprendido um pouco sobre apps Discord e como torná-los interativos. Daqui, você pode continuar a montar seu app ou explorar outras possibilidades: +- Ler **[a documentação](#DOCS_INTRO)** para informações mais detalhadas sobre recursos da API. +- Navegar pela pasta `examples/` neste projeto para ver exemplos de código menores e mais específicos. +- Conferir **[recursos da comunidade](#DOCS_TOPICS_COMMUNITY_RESOURCES)** para ferramentas específicas de certas linguagens de programaçãoque são mantidas por membros da comunidade. +- Ler nosso tutorial sobre [como hospedar apps Discord no Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) +- Entrar no **[servidor de Desenvolvedores Discord](https://discord.gg/discord-developers)** para fazer perguntas sobre a API, participar de eventos organizados pela equipe da API do Discord e interagir com outros desenvolvedores. diff --git a/docs/tr/Getting_Started.mdx b/docs/tr/Getting_Started.mdx new file mode 100644 index 0000000000..815a60ce85 --- /dev/null +++ b/docs/tr/Getting_Started.mdx @@ -0,0 +1,487 @@ + + +# İlk Discord uygulamanı oluşturmak + +Discord uygulamaları, bir dizi API ve etkileşimli özellik kullanarak sunucularını özelleştirmene ve genişletmene olanak tanır. Bu rehber, JavaScript kullanarak ilk Discord uygulamanı oluşturmanda sana yol gösterecek ve rehberin sonunda eğik çizgi komutlarını kullanan, mesaj gönderen ve bileşen etkileşimlerine yanıt veren bir uygulamaya sahip olacaksın. + +Sunucu üyelerinin taş, kâğıt, makas oynayabilmelerini sağlayacak bir Discord uygulaması oluşturacağız (klasik 3 seçenek yerine 7 seçenek olacak). Bu kılavuz yeni başlayanlara yöneliktir ancak temel bir [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics) bilginin olduğunu varsayar. + + +Uygulama bittiğinde işte böyle gözükecek: + +![Uygulamanın örnek gösterimi](getting-started-demo.gif) + +Kullanıcı akışını biraz daha açık hâle getirmek adına: + +1. İlk Kullanıcı yeni bir oyun başlatır ve uygulamanın `/challenge` eğik çizgi komutunu kullanarak nesnesini seçer +2. Kanala, diğer kullanıcıların meydan okumayı kabul etmesini sağlayan bir buton içeren bir mesaj gönderilir +3. 2. kullanıcı **Kabul Et** butonuna tıklar +4. 2. kullanıcı, nesnesini seçebileceği geçici bir mesaj alır +5. Oyunun sonucu herkesin görebilmesi için orijinal kanalda paylaşılır + + + +- Bu kılavuzdaki kodun yanı sıra bazı ek özelliklere özgü kod örneklerinin bulunduğu **[GitHub deposu](https://github.com/discord/discord-example-app)**. +- Discord uygulamaları için tipler ve yardımcı fonksiyonlar sağlayan **[discord-interactions](https://github.com/discord/discord-interactions-js)** kitaplığı. +- Discord'un bize istek gönderebileceği bir sunucu oluşturmak için kullanacağımız popüler bir JavaScript web çerçevesi olan **[Express](https://expressjs.com)**. +- Erken prototip ve geliştirme aşamalarında uygulamaları oluşturma ve barındırma işlemlerini basitleştiren bir çevrim içi ortam olan **[Glitch](https://glitch.com/)**. İstersen **[ngrok](https://ngrok.com/)** gibi bir araçla yerel ortamında da geliştirebilirsin. + + +--- + +## Adım 1: Bir uygulama oluşturmak + +Öncelikle, eğer hâlihazırda bir uygulaman yoksa geliştirici portalında bir uygulama oluşturman gerekli: + + + +Uygulamanın ismini yaz ve **Oluştur** butonuna bas. + +Uygulamanı oluşturduktan sonra uygulamanla ilgili açıklama ve simge gibi temel bilgileri güncelleyebileceğin uygulama ayarlarının **Genel Bakış** sayfasına ulaşacaksın. Ayrıca rehberin ilerleyen bölümlerinde kullanacağımız bir **Uygulama Kimliği** ve **Etkileşim Bitiş Noktası URL**'si de göreceksin. + +### Botunu yapılandırmak + +Şimdiyse uygulamanın [bot kullanıcısını](#DOCS_TOPICS_OAUTH2/bot-vs-user-accounts) yapılandırarak onun da tıpkı diğer sunucu üyeleri gibi görünmesini ve hareket etmesini sağlayacağız. + +Sol taraftaki kenar çubuğunda **Bot**'a tıkla. Bu sayfada botun [ayrıcalıklı amaçlarını](#DOCS_TOPICS_GATEWAY/privileged-intents) veya diğer kullanıcılar tarafından yüklenip yüklenemeyeceği gibi ayarları yapılandırabilirsin. + + +Amaçlar, bir [Ağ Geçidi API bağlantısı](#DOCS_TOPICS_GATEWAY) oluştururken Discord'un uygulamana hangi olayları göndereceğini belirler. Örneğin, kullanıcılar bir mesaja tepki eklediğinde uygulamanın bir şey yapmasını istiyorsan `GUILD_MESSAGE_REACTIONS` (`1 << 10`) amacını gönderebilirsin. + +Bazı amaçlar [privileged'tir](#DOCS_TOPICS_GATEWAY/privileged-intents), yani uygulamanın hassas olarak kabul edilebilecek verilere (mesajların içeriği gibi) erişmesine izin verir. Privileged intent'ler uygulamanın ayarlarındaki **Bot** sayfasında görünür ve açılıp kapatılabilir. Standart, privileged intent dışındakiler herhangi bir ek izin veya yapılandırma gerektirmez. + +Amaçlar hakkında daha fazla bilgi ve mevcut amaçların tam listesi, ilişkili olaylarıyla birlikte [Ağ Geçidi dokümantasyonunda](#DOCS_TOPICS_GATEWAY/gateway-intents) bulunmaktadır. + + +![Ayarlardaki bot sekmesi](app-add-bot.png) + +**Bot** sayfasında, botunun token'ını kopyalamana ve sıfırlamana olanak tanıyan bir **Token** bölümü de vardır. + +Bot token'ları, API isteklerini yetkilendirmek için kullanılır ve bot kullanıcısının izinlerini taşır, bu da onları *son derece hassas* hâle getirir. Token'ını *asla* paylaşmadığından veya herhangi bir versiyon kontrol sisteminde kontrol etmediğinden emin ol. + +Şimdi token'ı kopyala ve onu örneğin parola yöneticisi gibi güvenli bir yerde sakla. + +> uyarı +> Token'ını yeniden oluşturmadığın sürece tekrar görüntüleyemezsin, bu nedenle güvenli bir yerde sakladığından emin ol. + +### Bot izinlerini ve kapsamlarını ekleme + +Uygulamalar, Discord'da eğik çizgi komutu oluşturmak veya sunucu üyelerinin listesini almak gibi eylemler gerçekleştirmek için yükleme yapan kullanıcıların onayına ihtiyaç duyar. Uygulamayı yüklemeden önce istek atılacak birkaç kapsam ve izin seçelim. + + +Kapsamlar ve izinler, bir uygulama oluştururken uygulamanın Discord sunucularında neler yapabileceğini ve nelere erişebileceğini belirler. + +- [OAuth2 Kapsamları](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes), uygulamanın yükleme yapan veya yetki veren bir kullanıcı adına hangi verilere erişebileceğini ve eylemleri gerçekleştirebileceğini belirler. +- [İzinler](#DOCS_TOPICS_PERMISSIONS/permission-overwrites), Discord'daki diğer kullanıcıların sahip olduğu gibi bot kullanıcıya verilmiş detaylı izinlerdir. Bunlar, yükleyen kullanıcı tarafından onaylanabilir veya daha sonra sunucu ayarlarında veya [izinlerin üzerine yazarak](#DOCS_TOPICS_PERMISSIONS/permission-overwrites) güncellenebilir. + + +Sol kenar çubuğunda **OAuth2**'ye tıkla, ardından **URL oluşturucuyu** seç. + +> bilgi +> URL oluşturucu, uygulaman için seçtiğin kapsamlara ve izinlere göre bir yükleme bağlantısı oluşturur. Bağlantıyı, uygulamayı kendi sunucuna yüklemek için kullanabilir veya yükleyebilmeleri için başkalarıyla paylaşabilirsin. + +Şimdilik iki kapsam ekleyelim: +- `applications.commands`, uygulamanın [komutlar](#DOCS_INTERACTIONS_APPLICATION_COMMANDS) oluşturmasını sağlar. +- `bot`, bot kullanıcını ekler. `bot`'u seçtikten sonra botun için farklı izinler de seçebilirsin. Şimdilik sadece **Mesaj Gönder** seçeneğini işaretleyelim. + +Dokümantasyonda tüm [OAuth2 kapsamlarının](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes) bir listesine bakabilir veya [izinler](#DOCS_TOPICS_PERMISSIONS) hakkında daha fazla bilgi edinebilirsin. + +### Uygulamanı yüklemek + +Kapsamları ekledikten sonra uygulamanı yüklemek için kopyalayabileceğin bir URL göreceksin. + +![URL oluşturucu ekran görüntüsü](url-generator.png) + +> bilgi +> Uygulama geliştirirken uygulamanı başkaları tarafından aktif olarak kullanılmayan bir sunucuda oluşturmalı ve test etmelisin. Hâlihazırda kendi sunucun yoksa [ücretsiz bir tane oluşturabilirsin](https://support.discord.com/hc/articles/204849977-How-do-I-create-a-server-). + +URL'yi yukarıdan kopyala ve tarayıcına yapıştır. Kurulum süreci sana rehberlik edecektir; bu süreçte uygulamanı geliştirebileceğin ve test edebileceğin bir sunucuya yüklediğinden emin olmalısın. + +Uygulamanı yükledikten sonra sunucuna gidebilir ve uygulamanın sunucuna katıldığını görebilirsin ✨ + +Hadi yapılandırılmış ve yüklenmiş uygulamanı geliştirelim. + +--- + +## Adım 2: Uygulamanı çalıştırmak + +Örnek uygulamada kullanılan tüm kodlar [GitHub deposunda](https://github.com/discord/discord-example-app) bulunabilir. + +Uygulama, geliştirmeyi daha basit hâle getirmek için tipler ve yardımcı fonksiyonlar sağlayan [discord-interactions](https://github.com/discord/discord-interactions-js) kullanır. Başka dilleri veya kütüphaneleri kullanmayı tercih ediyorsan [Topluluk Kaynakları](#DOCS_TOPICS_COMMUNITY_RESOURCES) dokümantasyonlarına göz atabilirsin. + +### Projeyi remikslemek + +Bu rehber, tarayıcında klonlama ve geliştirme yapmanı sağlayan Glitch'i kullanır. Uygulamanı yerel olarak geliştirmeyi tercih edersen, [README](https://github.com/discord/discord-example-app#running-app-locally) dosyasından ngrok kullanımıyla ilgili talimatlara ulaşabilirsin. + +> bilgi +> Glitch, geliştirme ve test için harika olsa da [teknik kısıtlamalara sahiptir](https://help.glitch.com/hc/en-us/articles/16287495313293-Technical-Restrictions/), bu nedenle bitmiş uygulamalar için diğer barındırma sağlayıcıları düşünmekte fayda vardır. + +Başlamak için **[Glitch projesini 🎏 remiksle (veya klonla)](https://glitch.com/edit/#!/import/git?url=https://github.com/discord/discord-example-app.git)**. + +Projeyi remikslediğinde yeni bir Glitch projesine ulaşacaksın. + + +![Glitch projesine genel bakış](glitch-project.png) + +- **Proje ismin**, projenin sol üst köşesinde görünen benzersiz ismidir +- **`.env`**, uygulaman için tüm kimlik bilgilerinin saklanacağı dosyadır +- **Loglar**, projenin çıktısının bulabileceğin dosyalardır; uygulamanın çalışıp çalışmadığını görmek veya uygulamanın karşılaştığı hatalar hakkında bilgi almak için yararlıdır +- Sağ üst köşedeki **Paylaş** butonu, bu rehberin ilerleyen bölümlerinde etkileşimi ayarlamak için ihtiyaç duyacağın canlı proje URL'sini bulacağın yerdir + + +#### Proje yapısı + +Projenin tüm dosyaları Glitch projenin sol tarafında bulunmaktadır. Aşağıdaki görselde ana klasörlere ve dosyalara genel bir bakış mevcut: + +``` +├── examples -> kısa, özelliklere has örnek uygulamalar +│ ├── app.js -> bitmiş app.js kodu +│ ├── button.js +│ ├── command.js +│ ├── modal.js +│ ├── selectMenu.js +├── .env -> kimlik bilgilerin ve kimliklerin +├── app.js -> uygulaman için ana giriş noktası +├── commands.js -> eğik çizgi komutları payload'ları (yükler) ve yardımcılar +├── game.js -> Taş-kâğıt-makas için özel mantık +├── utils.js -> yardımcı fonksiyonlar ve enum'lar +├── package.json +├── README.md +└── .gitignore +``` + +### Kimlik bilgilerini eklemek + +`app.js` dosyanda zaten bazı kodlar var ancak istekte bulunmak için uygulamanın token'ına ve kimliğine ihtiyacın olacak. Tüm kimlik bilgilerin doğrudan `.env` dosyasında saklanabilir. + +İlk olarak, önceden oluşturduğumuz bot kullanıcısının token'ını kopyala ve `.env` dosyandaki **`DISCORD_TOKEN`** değişkenine yapıştır. + +Ardından uygulamanın **Genel Bakış** sayfasına git, sonrasında **Uygulama Kimliğini** ve **Ortak Anahtarı** kopyala. Değerleri `.env` dosyana **`APP_ID`** ve **`PUBLIC_KEY`** olarak yapıştır. + +Kimlik bilgilerin yapılandırıldıktan sonra eğik çizgi komutlarını yükleyelim ve işleyelim. + +### Eğik çizgi komutlarını yükleme + +> bilgi +> Eğik çizgi komutlarını yüklemek için uygulama [`node-fetch`](https://github.com/node-fetch/node-fetch) kullanır. Yükleme implementasyonunu `utils.js`'de `DiscordRequest()` fonksiyonu içinde görebilirsin. + +Proje, `commands.js` dosyasının altında tanımlanan `ALL_COMMANDS` içerisindeki komutları yüklemek için kullanabileceğin bir `register` komut dosyası içerir. HTTP API'sinin [`PUT /applications//commands`](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/bulk-overwrite-global-application-commands) uç noktasını çağırarak komutları global komutlar olarak yükler. + +Komutlarını özelleştirmek veya ilave komutlar eklemek istersen [komutlar dokümantasyonundaki](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-structure) komut yapısına başvurabilirsin. + +Glitch projenin altındaki **Terminal**'e tıklayarak ve aşağıdaki komutu yapıştırarak `register` komut dosyasını çalıştır: + +``` +npm run register +``` + +Komutu çalıştırmak için enter tuşuna bas. + +Sunucuna geri döndüğünde eğik çizgi komutlarının göründüğünü göreceksin. Ancak bunları çalıştırmayı denersen uygulaman Discord'dan herhangi bir istek almadığı veya işlemediği için hiçbir şey olmayacaktır. + + +Discord, uygulamalar oluşturmak için bir araya getirebileceğin iki API'ye sahiptir: + +- **[HTTP API](#DOCS_REFERENCE/http-api)**, Discord'da veri gönderme, veri güncelleme veya bir kaynak hakkında veri alma gibi genel işlemler için kullanılan REST benzeri bir API'dir. +- **[Ağ Geçidi API](#DOCS_REFERENCE/gateway-websocket-api)**, durumu korumak veya Discord sunucusunda gerçekleşen olayları dinlemek için yararlı, WebSocket tabanlı bir API'dir. Bu rehberde bunu kullanmayacağız ancak bir Ağ Geçidi bağlantısının nasıl oluşturulacağı hakkında ve dinleyebileceğin farklı olaylar hakkında daha fazla bilgi [Ağ Geçidi dokümantasyonunda](#DOCS_TOPICS_GATEWAY) bulunmaktadır. + + +--- + +## Adım 3: Etkileşimi işlemek + +Uygulamanın eğik çizgi komut isteklerini (ve diğer etkileşimleri) almasını sağlamak için Discord'un bunları göndermek üzere genel bir URL'ye ihtiyacı vardır. Bu URL, uygulamanın ayarlarında **Etkileşim Uç Noktası URL'si** olarak yapılandırılabilir. + +### Etkileşim uç noktası URL'si ekleme + +Glitch projeleri varsayılan olarak herkese açık bir URL'ye sahiptir. Sağ üst köşedeki **Paylaş** butonuna tıklayarak projenin URL'sini kopyala, ardından minik pencerenin alt kısmındaki "Canlı site" proje bağlantısını kopyala. + +> bilgi +> Yerel olarak geliştirme yapıyorsan, [GitHub README'de](https://github.com/discord/discord-example-app#running-app-locally) istekleri yerel ortamına tünellemek için talimatlara ulaşabilirsin. + +Bağlantı kopyalandıktan sonra [geliştirici portalından](https://discord.com/developers/applications) uygulamanın ayarlarına git. + +Uygulamanın **Genel Bilgiler** sayfasında, uygulamanın URL'sini yapıştırabileceğin ve içerisine `/interactions` ekleyebileceğin bir **Etkileşimli Uç Nokta URL'si** seçeneği vardır. Express uygulamasının istekleri dinlemek için yapılandırıldığı yer de bu Etkileşimli Uç Nokta URL'sidir. + +![Uygulama ayarlarında etkileşimler uç nokta URL'si](interactions-url.png) + +**Değişiklikleri Kaydet**'e tıkla ve uç noktanın başarıyla doğrulandığından emin ol. + +Örnek uygulama, doğrulamayı iki şekilde ele alır: +- `PUBLIC_KEY` ve [discord-interactions paketini](https://github.com/discord/discord-interactions-js#usage) [Express'in `verify` arayüzüne](http://expressjs.com/en/5x/api.html#express.json) uygun hâle getiren bir wrapper fonksiyonla (`utils.js` içerisinden içe aktarılır) birlikte kullanır. Bu, uygulamana gelen her istekte çalıştırılır. +- Gelen `PING` isteklerine yanıt verir. + +Uygulamanı etkileşim almaya hazırlama hakkında daha fazla bilgiyi [etkileşimler dokümantasyonunda](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/receiving-an-interaction) bulabilirsin. + +### Eğik çizgi komut isteklerini işleme + +Uç nokta doğrulandıktan sonra projenin `app.js` dosyasına git ve `/test` komutunu işleyen kod blokunu bul: + +```javascript +// "test" komutu +if (name === 'test') { + // Komutun tetiklendiği kanala bir mesaj gönderir + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Bir yardımcı fonksiyondan göndermek için rastgele bir emoji alır + content: 'hello world ' + getRandomEmoji(), + }, + }); +} +``` + +Yukarıdaki kod, gelen etkileşime meydana geldiği kanaldaki bir mesajla yanıt veriyor. Modal ile yanıt vermek gibi mevcut tüm yanıt türlerini [dokümantasyonda](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-response-object-interaction-callback-type) bulabilirsin. + +> bilgi +> `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE`, [`discord-interactions`'dan dışa aktarılmış](https://github.com/discord/discord-interactions-js/blob/main/src/index.ts#L33) bir sabittir. + +Sunucuna git ve uygulamanın `/test` eğik çizgi komutunun çalıştığından emin ol. Bunu tetiklediğinde, uygulaman "hello world" kelimelerini takip eden rastgele bir emoji içeren bir mesaj göndermelidir. + +Aşağıdaki bölümde, taş-kâğıt-makas oyununu oluşturmak için eğik çizgi komut seçeneklerini, butonları ve seçme menülerini kullanan ek bir komut ekleyeceğiz. + +--- + +## Adım 4: Mesaj bileşenlerini ekleme + +Taş-kâğıt-makas tarzı oyunumuz `/challenge` komutuyla başlatılacaktır. Komut tetiklendiğinde uygulama kanala mesaj bileşenleri gönderecek ve bu da kullanıcıları oyunu tamamlamaları için yönlendirecektir. + +### Seçenekli bir komut ekleme + +`commands.js`'de `CHALLENGE_COMMAND` olarak adlandırılan `/challenge` komutu bir dizi `options`'a sahiptir. Uygulamamızda seçenekler, kullanıcının taş-kâğıt-makas oynarken seçebileceği farklı şeyleri temsil eden nesnelerdir ve `game.js`'deki `RPSChoices` anahtarları kullanılarak oluşturulmuştur. + +Komut seçenekleri ve bunların yapısı hakkında daha fazla bilgiyi [dokümantasyonlardan](#DOCS_INTERACTIONS_APPLICATION_COMMANDS/application-command-object-application-command-option-structure) edinebilirsin. + +> bilgi +> Bu rehber `game.js` dosyasına fazla değinmeyecek olsa da sen onu kurcalayabilir, komutları veya komutlardaki seçenekleri çekinmeden değiştirebilirsin. + + + +`/challenge` komutunu işlemek için `if name === “test”` if blokundan sonra aşağıdaki kodu ekle: + +```javascript +// "meydanoku" komutu +if (name === 'challenge' && id) { + const userId = req.body.member.user.id; + // Kullanıcının nesne seçimi + const objectName = req.body.data.options[0].value; + + // Oyun kimliği olarak mesaj kimliğini kullanarak aktif oyun oluşturur + activeGames[id] = { + id: userId, + objectName, + }; + + return res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + content: `Rock papers scissors challenge from <@${userId}>`, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.BUTTON, + // Daha sonra kullanmak üzere oyun kimliğini ekler + custom_id: `accept_button_${req.body.id}`, + label: 'Accept', + style: ButtonStyleTypes.PRIMARY, + }, + ], + }, + ], + }, + }); +} +``` + + +> bilgi +> Kodu nereye yapıştıracağından emin değilsen, kodun tamamını Glitch projesindeki `examples/app.js` dosyasında veya [GitHub'daki](https://github.com/discord/discord-example-app/blob/main/app.js) kök `app.js` dosyasında bulabilirsin. + +Yukarıdaki kod birkaç şey yapıyor: +1. Eğik çizgi komutunu tetikleyen kullanıcının kimliğini (`userId`) ve seçtiği (`objectName`) seçeneği (nesne seçimi) almak için istek gövdesini ayrıştırır. +2. Etkileşim kimliğini kullanarak `activeGames` nesnesine yeni bir oyun ekler. Etkin oyun `userId` ve `objectName`'i kaydeder. +3. Kanala, `custom_id`'si `accept_button_` olan bir buton ile bir mesaj gönderir. + +> uyarı +> Örnek kod, bellek içi depolama alanı olarak bir nesne kullanır ancak bitmiş uygulamalar için bir veri tabanı kullanman gerekir. + +[Mesaj bileşenleriyle](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/what-is-a-component) bir mesaj gönderirken, tekil payload'lar bir `components` dizisine eklenir. Eyleme geçirilebilir bileşenlerin (butonlar gibi) kod örneğinde görebileceğin bir [eylem satırının](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/action-rows) içinde olması gereklidir. + +Mesaj bileşenleriyle birlikte gönderilen benzersiz `custom_id`'ye dikkatli bakalım. Şu anki durumda `accept_button_` aktif oyunun kimliğiyle birlikte eklendi. Bir `custom_id`, birisi bileşenle etkileşime girdiğinde Discord'un sana gönderdiği istekleri işlemek için kullanılabilir, bunu birazdan göreceğiz. + +Artık `/challenge` komutunu çalıştırdığında ve bir seçenek belirlediğinde, uygulaman bir **Kabul Et** butonu içeren bir mesaj gönderecektir. Butona basmayı işlemek için kod ekleyelim. + + + + + +Kullanıcılar bir mesaj bileşeniyle etkileşime girdiğinde, Discord [etkileşim türü](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/interaction-object-interaction-type) `3` (veya `discord-interactions` kullanılırken `MESSAGE_COMPONENT`) değeri olan bir istek gönderecektir. + +Buton için bir işleyici ayarlamak üzere, etkileşimin `type`'ını kontrol edeceğiz ve ardından `custom_id` ile eşleştireceğiz. + +Aşağıdaki kodu `APPLICATION_COMMAND` için tip işleyicisinin altına yapıştır: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id mesaj bileşeni gönderilirken payload'da ayarlanır +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // ilişkili oyun kimliğini alır + const gameId = componentId.replace('accept_button_', ''); + // İstek gövdesinde token bulunan mesajı siler + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Bir yardımcı fonksiyondan göndermek için rastgele bir emoji alır + content: 'What is your object of choice?', + // Geçici bir mesaj olacağını belirtir + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Oyun kimliğini ekler + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Önceki mesajı siler + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } +} +``` + +Yukarıdaki kod: +1. Başlangıçta gönderdiğimizle eşleşen bir `custom_id` olup olmadığını kontrol eder (bu durumda, `accept_button_` ile başlar). Özel kimliğe aktif oyun kimliği de eklenmiştir, bu yüzden bunu `gameID`'de saklarız. +2. `node-fetch` kullanarak bir webhook çağıran ve istek gövdesinde benzersiz etkileşim `token`'ı ileten [orijinal mesajı siler](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/delete-original-interaction-response). Bu, kanalı temizlemek için yapılır ve böylece diğer kullanıcılar butona tıklayamaz. +3. Oyun için nesne seçeneklerini içeren bir seçim menüsü içeren bir mesaj göndererek isteğe yanıt verir. Payload, `options` dizisi ve [mesajın geçici olduğunu gösteren](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/create-followup-message) `flags: 64` belirteci haricinde önceki payload'a epey benzer görünmelidir. + +`options` dizisi, `game.js`'deki `getShuffledOptions()` metodu kullanılarak doldurulur ve bu metot `RPSChoices` değerlerini [mesaj bileşeni seçeneklerinin](#DOCS_INTERACTIONS_MESSAGE_COMPONENTS/select-menu-object-select-option-structure) şekline uyacak şekilde değiştirir. + + + + + +Eklenecek son şey, seçim menüsü etkileşimlerini işleyecek ve oyunun sonucunu kanala gönderecek koddur. + +Seçim menüleri sadece başka bir mesaj bileşeni olduğundan, etkileşimlerini işleyen kod, buton kodlarının neredeyse aynısı olacaktır. + +Seçim menüsünü işlemek için yukarıdaki kodu değiştir: + +```javascript +if (type === InteractionType.MESSAGE_COMPONENT) { +// custom_id mesaj bileşeni gönderilirken payload'da ayarlanır +const componentId = data.custom_id; + + if (componentId.startsWith('accept_button_')) { + // ilişkili oyun kimliğini alır + const gameId = componentId.replace('accept_button_', ''); + // İstek gövdesinde token bulunan mesajı siler + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + try { + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { + // Bir yardımcı fonksiyondan göndermek için rastgele bir emoji alır + content: 'What is your object of choice?', + // Geçici bir mesaj olacağını belirtir + flags: InteractionResponseFlags.EPHEMERAL, + components: [ + { + type: MessageComponentTypes.ACTION_ROW, + components: [ + { + type: MessageComponentTypes.STRING_SELECT, + // Oyun kimliğini ekler + custom_id: `select_choice_${gameId}`, + options: getShuffledOptions(), + }, + ], + }, + ], + }, + }); + // Önceki mesajı siler + await DiscordRequest(endpoint, { method: 'DELETE' }); + } catch (err) { + console.error('Error sending message:', err); + } + } else if (componentId.startsWith('select_choice_')) { + // ilişkili oyun kimliğini alır + const gameId = componentId.replace('select_choice_', ''); + + if (activeGames[gameId]) { + // Yanıt veren kullanıcı için kullanıcı kimliğini ve nesne seçimini alır + const userId = req.body.member.user.id; + const objectName = data.values[0]; + // Yardımcı fonksiyondan gelen sonucu hesaplar + const resultStr = getResult(activeGames[gameId], { + id: userId, + objectName, + }); + + // Oyunu bellekten kaldırır + delete activeGames[gameId]; + // Mesajı istek gövdesinde token ile günceller + const endpoint = `webhooks/${process.env.APP_ID}/${req.body.token}/messages/${req.body.message.id}`; + + try { + // Sonuçları gönderir + await res.send({ + type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE, + data: { content: resultStr }, + }); + // Geçici mesajı günceller + await DiscordRequest(endpoint, { + method: 'PATCH', + body: { + content: 'Nice choice ' + getRandomEmoji(), + components: [] + } + }); + } catch (err) { + console.error('Error sending message:', err); + } + } + } +} +``` + +Daha önceki koda benzer şekilde, yukarıdaki kod etkileşim isteğinden kullanıcı kimliğini ve nesne seçimini alır. + +Bu bilgi, orijinal kullanıcının kimliği ve `activeGames` nesnesinden yapılan seçimle birlikte `getResult()` fonksiyonuna aktarılır. `getResult()` kazananı belirler, ardından kanala geri göndermek için okunabilir bir karakter dizisi oluşturur. + +Ayrıca, bu kez silinemediği için [takip eden geçici mesajı güncellemek](#DOCS_INTERACTIONS_RECEIVING_AND_RESPONDING/edit-followup-message) için başka bir webhook çağırıyoruz. + +Son olarak, sonuçlar kanalda `CHANNEL_MESSAGE_WITH_SOURCE` etkileşim yanıt tipi kullanılarak gönderilir. + + + +...işte bu kadar 🎊 Durma, uygulamanı test et ve her şeyin çalıştığından emin ol. + +--- + +## Sonraki adımlar + +Tebrikler, ilk Discord uygulamanı geliştirdin! 🤖 + +Umarız Discord uygulamaları, nasıl yapılandırılacakları ve nasıl etkileşimli hâle getirilecekleri hakkında biraz bilgi edinmişsindir. Buradan uygulamanı oluşturmaya devam edebilir veya başka nelerin mümkün olduğunu keşfedebilirsin: +- API özellikleri hakkında derinlemesine bilgi için **[dokümantasyonları](#DOCS_INTRO)** oku +- Daha küçük, özelliğe has kod örnekleri için bu projedeki `examples/` klasörüne göz at +- Topluluk üyeleri tarafından yürütülen kodlama diline özgü araçlar için **[topluluk kaynaklarına](#DOCS_TOPICS_COMMUNITY_RESOURCES)** göz at +- Discord uygulamalarını [Cloudflare Workers](#DOCS_TUTORIALS_HOSTING_ON_CLOUDFLARE_WORKERS) üzerinde barındırma hakkındaki eğitimimizi oku +- API hakkında sorular sormak, Discord API ekibi tarafından düzenlenen etkinliklere katılmak ve diğer geliştiricilerle etkileşim kurmak için **[Discord Geliştiricileri sunucusuna](https://discord.gg/discord-developers)** katıl