# Komut izinleri

Komut izinleri, botunun komutlarını bir sunucuda kimin görüp çalıştırabileceğini ve hangi kanallarda kullanılabileceğini söyleyen kurallardır: kuralları sunucunun yöneticileri koyar, botun okur.

## Kimin işi

| Kişi | Ne yapar |
|---|---|
| Sunucu yöneticisi | Kuralları koyar, değiştirir ve kaldırır. `ManageGuild` ve `ManageRoles` izinlerinin ikisi de gerekir. |
| Geliştirici | `default_member_permissions` ile komutun varsayılanını seçer, kuralları okur ve değişince olay alır. Kural yazamaz. |

Kuralı sunucu uygular: kişinin kullanamayacağı komut ona listede gösterilmez ve çalıştırılırsa botuna hiç ulaşmaz.

## Sunucu yöneticisi için

### Nereden açılır

1. Sunucunun adına tıkla ve **Sunucu ayarları**'nı aç.
2. Soldaki **Bot komutları** sekmesine gir. Sekme yalnız `ManageGuild` ile `ManageRoles` izinlerinin ikisi birden sende varsa görünür.
3. **Bot** kutusundan bir bot seç. Altındaki **Komut izinleri** kartında önce **Tüm komutlar** satırı gelir: botun bütün komutlarına uyan kurallar. Altında her komut kendi satırındadır; satırda komutun açıklaması, kural yokken kimin kullanabildiği (`default_member_permissions`) ve bugünkü kuralların özeti yazar.
4. Satırdaki **Düzenle**'ye bas. **Rol**, **Üye** ya da **Kanal** seç, hedefi seç (aramak için yazabilirsin), **Kural ekle**'ye bas. Yeni kural **İzin ver** olarak eklenir; yanındaki kutudan **Engelle**'ye çevirebilirsin. **Varsayılan** ya da çöp kutusu kuralı kaldırır: o hedef için komutun varsayılanı geçerli olur.
5. **Kaydet**'e bas. Kaydetmeden önce kuralların özeti çıkar ("İzin ver: @Moderatör · Engelle: @herkes, #genel" gibi); onaylayınca kaydedilir. Kişilerin uygulamaları değişikliği en geç 60 saniyede görür: komut listelerinden kaybolur ve çalıştırılamaz.

Listeyi okuyan rota `ManageGuild` ister, kural değiştirmek `ManageGuild` ile `ManageRoles`'ü birlikte ister; sekme ikisi birden olmadan görünmez. Komutun istediği bir izin sende yoksa kaydederken "Bu izin sende olmadığı için bu komutu açamazsın." yazar (aşağıda **Sende olmayan yetkiyi açamazsın**). Her değişiklik denetim kaydına "Komut izni güncelleme" olarak düşer: kimin, hangi komutta, eski ve yeni kuralları.

### Kural türleri

| `type` | Hedef | `id` |
|---|---|---|
| `1` | Rol | Sunucunun bir rolünün ID'si; sunucunun kendi ID'si `@everyone` demektir |
| `2` | Üye | Sunucunun bir üyesinin kullanıcı ID'si |
| `3` | Kanal | Sunucunun bir kanalının ID'si; `0` tüm kanallar demektir |

Bir komutta ve **Tüm komutlar** satırında ayrı ayrı en çok 100 kural olur. Aynı hedef bir listede iki kez geçemez. Başka sunucunun rolü ya da kanalı, üye olmayan bir kişi `400 validation_failed` döner.

### Hangi kural kazanır

Sunucu, kişi bir komutu açınca ve çalıştırınca bu sırayla bakar:

1. Sunucunun sahibi ve `Administrator` izni olanlar her komutu her kanalda kullanır. Hiçbir kural onları durdurmaz.
2. Kişinin o kanalda `UseApplicationCommands` izni yoksa ya da zaman aşımındaysa orada hiçbir komutu kullanamaz.
3. Kanal kuralı: önce komutun kendi kuralları, orada kanal kuralı yoksa **Tüm komutlar** kuralları. İçlerinde önce o kanalın kuralı, yoksa "tüm kanallar" (`0`). Bulunan kural engelse komut o kanalda kullanılamaz. Hiç kanal kuralı yoksa her kanal açıktır.
4. Kişi kuralı: önce komutun kendi kuralları, sonra **Tüm komutlar** kuralları. Her birinde önce kişinin kendi kuralı, sonra rolleri (rollerinden biri izin veriyorsa izin, hepsi engelliyorsa engel), sonra `@everyone`. İlk bulunan karar verir. Bir istisna: **Tüm komutlar**'daki bir izin, `default_member_permissions` değeri olan komutu açmaz; o komutta 5. adıma geçilir. **Tüm komutlar**'daki engel ise her komutta geçerlidir.
5. Hiç kişi kuralı yoksa komutun `default_member_permissions` değeri karar verir.

Komutun kendi kuralı **Tüm komutlar** kuralını ezer. Örneğin **Tüm komutlar**'da `@everyone` engelli ama `/yardım`'da `@everyone` izinliyse, herkes `/yardım`'ı kullanır, botun diğer komutlarını kullanamaz.

### Dört örnek

| İstek | Nereye | Kurallar |
|---|---|---|
| Herkes kullansın ama #genel'de olmasın | Komuta ya da **Tüm komutlar**'a | Kanal `#genel`: Engelle |
| Yalnız Moderatör | Komuta | `@everyone`: Engelle; rol Moderatör: İzin ver |
| Bir kişi hariç | Komuta | O üye: Engelle |
| Yalnız yönetici | Komuta | `@everyone`: Engelle. Sahip ve `Administrator` zaten geçer |

"Bir kişi hariç" kişi kuralı olduğu için rolden önce gelir: o kişinin Moderatör rolü olsa bile engellenir. "Yalnız Moderatör"de Moderatör olmayan herkes `@everyone` kuralına düşer.

### Komutları bir kanalda tamamen kapatmak

`UseApplicationCommands` artık denetlenir. Kanalın izin ayarlarında bir rolden bu izni kaldırırsan o roldeki kişiler o kanalda hiçbir botun hiçbir komutunu görmez ve çalıştıramaz. Bütün sunucuda kapatmak için **Roller**'de `@everyone` rolünden kaldır. Yeni sunucularda `@everyone` bu izinle başlar.

### Sende olmayan yetkiyi açamazsın

Bir komutun `default_member_permissions` değeri varsa, örneğin `BanMembers`, o komutun kurallarını değiştirmek için bu izinlere senin de sahip olman gerekir; yoksa `403 command_permission_escalation` alırsın. Değeri `"0"` olan komutun kurallarını yalnızca sahip ve `Administrator` değiştirir. **Tüm komutlar** satırında bu, botun bütün komutlarının izinleri demektir. Sebep: aksi halde yalnızca `ManageGuild` izni olan biri `/ban`'ı herkese açabilirdi. Aynı sebeple **Tüm komutlar** kuralı yalnızca varsayılan izni olmayan komutları açar; bot sonradan `BanMembers` isteyen bir komut eklese de o komut kendiliğinden açılmaz. Yetki isteyen bir komutu bir role açmak için kuralı o komutun kendisine koy.

## Geliştirici için

### Varsayılan: default_member_permissions

Sunucu bir kural koyana dek komutu kimin kullanacağını [Komutlar](https://noluyo.net/gelistirici/komutlar.md#kim-kullanabilir-default-member-permissions) sayfasındaki `default_member_permissions` söyler. Bir kişi kuralı varsayılanın önüne geçer: yönetici `/ban`'ı bir role açabilir, herkese açık bir komutu bir role kapatabilir. Varsayılanı yetki isteyen komutlar için doğru seç; ama tek güvencen o olmasın.

### Bot neden kural yazamaz

Kim neyi kullanır, sunucunun kararıdır. Bot kendi komutunu herkese açabilseydi sunucu bu kararı kaybederdi. Bu yüzden kural yazma rotası yalnızca kişinin oturumuyla çalışır; bot token'ıyla `403 bot_forbidden` döner. Botun kuralları okur ve değişince olay alır.

### Kuralları okumak

```bash
curl "https://noluyo.net/api/v1/applications/$APPLICATION_ID/guilds/$GUILD_ID/commands/permissions" \
  -H "Authorization: Bot $BOT_TOKEN"
```

Yanıt, kuralı olan her komut için bir kayıttır. `id` uygulamanın ID'siyse kayıt **Tüm komutlar** kurallarıdır:

```json
[
  {
    "id": "111540000000000000",
    "application_id": "111540000000000000",
    "guild_id": "111500000000000000",
    "permissions": [{ "type": 1, "id": "111500000000000000", "allow": false }]
  },
  {
    "id": "111560000000000000",
    "application_id": "111540000000000000",
    "guild_id": "111500000000000000",
    "permissions": [
      { "type": 1, "id": "111520000000000000", "allow": true },
      { "type": 3, "id": "0", "allow": false }
    ]
  }
]
```

| Rota | Ne döner |
|---|---|
| [`GET .../guilds/{guild_id}/commands/permissions`](https://noluyo.net/gelistirici/api-commands.md#listCommandPermissions) | Botun o sunucudaki bütün kuralları; kuralı olmayan komut listede yok |
| [`GET .../guilds/{guild_id}/commands/{command_id}/permissions`](https://noluyo.net/gelistirici/api-commands.md#getCommandPermissions) | Bir komutun kuralları, yoksa boş liste; **Tüm komutlar** kuralları burada yok |

İkisi de `read` sınıfındadır. Bot o sunucunun üyesi değilse `403 missing_access` döner.

### Alanlar

| Alan | Tür | Anlamı |
|---|---|---|
| `id` | ID | Komut; **Tüm komutlar** kurallarında uygulamanın ID'si |
| `application_id` | ID | Uygulaman |
| `guild_id` | ID | Sunucu |
| `permissions[].type` | tam sayı | `1` rol, `2` üye, `3` kanal |
| `permissions[].id` | ID | Hedef; rol olarak sunucunun ID'si `@everyone`, kanal olarak `0` tüm kanallar |
| `permissions[].allow` | evet/hayır | `true` izin verir, `false` engeller |

### Değişince: APPLICATION_COMMAND_PERMISSIONS_UPDATE

Bir yönetici kuralları değiştirince botuna [APPLICATION_COMMAND_PERMISSIONS_UPDATE](https://noluyo.net/gelistirici/olaylar.md#APPLICATION_COMMAND_PERMISSIONS_UPDATE) gelir. Gövdesi yukarıdaki kayıtlardan biridir ve kümenin tamamını taşır; boş `permissions` kuralların kaldırıldığını söyler. Intent istemez, yalnızca botuna gider. Kuralları sunucu zaten uygular; olayı yalnızca bilgi için kullan, örneğin bir kayıt kanalına yazmak için.

### Tam örnek: kuralları okuyan betik

Node.js 22 veya üstü yeter, ek paket gerekmez. Betik bir sunucudaki kuralları okur ve okunur biçimde yazar:

```js title=kurallar.mjs
const API = "https://noluyo.net/api/v1";
const { BOT_TOKEN, APPLICATION_ID, GUILD_ID } = process.env;
if (!BOT_TOKEN || !APPLICATION_ID || !GUILD_ID) throw new Error("BOT_TOKEN, APPLICATION_ID ve GUILD_ID tanımlı olmalı");

const headers = { Authorization: `Bot ${BOT_TOKEN}` };
const get = async (path) => {
  for (;;) {
    const res = await fetch(API + path, { headers });
    const data = await res.json();
    if (res.status === 429) {
      await new Promise((done) => setTimeout(done, data.retry_after * 1000));
      continue;
    }
    if (!res.ok) throw new Error(`${res.status} ${data.code}: ${data.message}`);
    return data;
  }
};

const names = new Map();
for (const c of await get(`/applications/${APPLICATION_ID}/commands`)) names.set(c.id, c.name);
for (const c of await get(`/applications/${APPLICATION_ID}/guilds/${GUILD_ID}/commands`)) names.set(c.id, c.name);

const kinds = { 1: "rol", 2: "üye", 3: "kanal" };
for (const entry of await get(`/applications/${APPLICATION_ID}/guilds/${GUILD_ID}/commands/permissions`)) {
  const title = entry.id === APPLICATION_ID ? "Tüm komutlar" : `/${names.get(entry.id) ?? entry.id}`;
  console.log(title);
  for (const p of entry.permissions) {
    let target = `${kinds[p.type]} ${p.id}`;
    if (p.type === 1 && p.id === GUILD_ID) target = "@everyone";
    if (p.type === 3 && p.id === "0") target = "tüm kanallar";
    console.log(`  ${target}: ${p.allow ? "izin" : "engel"}`);
  }
}
```

Çalıştırmak için:

```bash
BOT_TOKEN='kopyaladigin_token' APPLICATION_ID='uygulama id degeri' GUILD_ID='sunucu id degeri' node kurallar.mjs
```

> **Uyarı:** İzin, komutu görmeyi ve çalıştırmayı sınırlar; işin yetkisini yine sen denetle. Bir yönetici `/ban`'ı herkese açabilir. Komut gelince etkileşimdeki `member.permissions`'a bak ve işi kişinin yetkisi varsa yap: `BanMembers` yoksa yasaklama.

## Limitler

| Konu | Değer |
|---|---|
| Kural | Komut başına 100; **Tüm komutlar** için ayrıca 100 |
| Kural yazma | Kişi ve sunucu başına dakikada 10 |
| Kural okuma | `read` sınıfı: 5 saniyede 30 istek |
| Yayılma | Kişilerin uygulamaları en geç 60 saniyede |

## Hatalar

| Kod | Ne oldu | Ne yap |
|---|---|---|
| `missing_permissions` | Kural değiştiren kişide `ManageGuild` ve `ManageRoles` birlikte yok | Kişiye iki izni de veren bir rol ver. |
| `command_permission_escalation` | Kişi komutun `default_member_permissions` bitlerine sahip değil | Kuralı o izinlere sahip biri, sahip ya da bir `Administrator` değiştirsin. |
| `validation_failed`, `permissions[0].id`: `invalid` | Hedef bu sunucunun değil, iki kez geçiyor ya da ID geçersiz | Bu sunucunun rolünü, kanalını ya da üyesini seç; tüm kanallar için `0`. |
| `validation_failed`, `permissions`: `too_long` | 100'den çok kural | Kişi kuralları yerine rol kullan. |
| `unknown_application` | Bot bu sunucuda değil ya da kapatılmış | Botu sunucuya ekle. |
| `unknown_command` | Komut yok ya da başka sunucunun komutu | Global komutu ya da bu sunucunun komutunu seç. |
| `bot_forbidden` | Bot kural yazmaya çalıştı | Bot yazamaz; sunucunun yöneticisinden iste. |
| `missing_access` | Okuyan bot o sunucunun üyesi değil | Botu sunucuya ekle. |
| `rate_limited` | Dakikada 10 değişikliği aştın | `retry_after` kadar bekle. |

## Bu sayfayı yapay zekaya verirsen

> **İpucu:** Bu sayfayı bir yapay zeka asistanına verip kod yazdırıyorsan şu kuralları da ekle:
>
> - Token koda yazılmaz, `process.env.BOT_TOKEN`'dan okunur.
> - Bot komut kuralı yazmaz; yalnızca okur. Kural yazan kod bot token'ıyla `bot_forbidden` alır.
> - Kurallar sunucuda uygulanır; bot onları yeniden uygulamaz ama yetki isteyen işte `member.permissions`'ı denetler.
> - Kanal kuralında `0` tüm kanallar, rol kuralında sunucunun ID'si `@everyone` demektir. ID'ler metindir.
> - `id` uygulamanın ID'si olan kayıt botun bütün komutlarının kurallarıdır.
> - Komut çalıştırılınca gelen etkileşime 3 saniye içinde yanıt verilir.

## Sırada ne var

- [Komutlar](https://noluyo.net/gelistirici/komutlar.md): `default_member_permissions` alanı ve komut tanımları
- [İzinler](https://noluyo.net/gelistirici/izinler.md): izin bitlerinin tam listesi ve rol hiyerarşisi
- [Hatalar](https://noluyo.net/gelistirici/hatalar.md): `command_forbidden` ve `command_permission_escalation` yanıtları
