Konsol: fraktal (paralel şeritli 24-bit Mandelbrot/Julia + yakınlaşma), sudoku (geri izlemeli, canlı animasyon), fatura (JSON → terminal tablosu, PDF ve Excel). Masaüstü: hesap makinesi (işlem önceliği, canlı bağlama), odak (Pomodoro), parola atölyesi (entropi ölçer, SHA-256). Web: pano (Kanban REST API + SQLite), kisalt (302 yönlendirme, SVG istatistik), anket (adres başına tek oy, sunucuda çizilen grafik). Hepsi `kabalang calistir` ile derlenip çalışır; web uygulamaları yalnız 127.0.0.1'i dinler, SQL parametre bağlamalı, HTML çıktısı kaçırılır. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
159 lines
7.4 KiB
Plaintext
159 lines
7.4 KiB
Plaintext
# ╔══════════════════════════════════════════════════════════════════╗
|
|
# ║ PANO — KabaLang ile Kanban görev panosu ║
|
|
# ║ ║
|
|
# ║ · JSON REST API: GET · POST · PUT · DELETE /api/gorevler ║
|
|
# ║ · Kalıcı kayıt: SQLite, her sorgu PARAMETRE BAĞLAMALI ║
|
|
# ║ · Ön yüz: arayuz.html (tek sayfa, dış bağımlılık yok) ║
|
|
# ╚══════════════════════════════════════════════════════════════════╝
|
|
#
|
|
# Çalıştır: cd web/pano && kabalang calistir pano.kbl
|
|
# Aç: http://127.0.0.1:8471
|
|
|
|
kullan kaba.web
|
|
kullan kaba.json
|
|
kullan kaba.veritabani
|
|
kullan kaba.sistem
|
|
|
|
# Panoda yalnız bu üç sütun vardır. Kapalı küme → istemciden gelen
|
|
# sütun adı bu listede değilse istek reddedilir.
|
|
SUTUNLAR = ["yapilacak", "suruyor", "bitti"]
|
|
ONCELIKLER = ["dusuk", "orta", "yuksek"]
|
|
|
|
db = cevre.al("PANO_DB")
|
|
eger db == "":
|
|
db = "pano.db"
|
|
|
|
# ── Veritabanı ──────────────────────────────────────────────────────
|
|
|
|
fonksiyon hazirla(db):
|
|
veritabani.sqlite(db, "CREATE TABLE IF NOT EXISTS gorev(id INTEGER PRIMARY KEY AUTOINCREMENT, baslik TEXT NOT NULL, aciklama TEXT DEFAULT '', sutun TEXT NOT NULL, oncelik TEXT DEFAULT 'orta', olusturma TEXT);")
|
|
|
|
# İlk açılışta pano boş görünmesin: birkaç örnek kart.
|
|
eger veritabani.sqlite(db, "SELECT count(*) FROM gorev") == "0":
|
|
ornekler = [
|
|
["Giriş ekranını tasarla", "Koyu tema, mobil öncelikli", "bitti", "yuksek"],
|
|
["REST API taslağı", "GET · POST · PUT · DELETE uçları", "bitti", "orta"],
|
|
["SQLite şeması", "Parametre bağlamalı sorgular", "suruyor", "yuksek"],
|
|
["Sürükle-bırak kartlar", "Sütunlar arası taşıma", "suruyor", "orta"],
|
|
["Bildirim e-postaları", "Görev atanınca haber ver", "yapilacak", "dusuk"],
|
|
["Karanlık/aydınlık tema", "Sistem tercihine uy", "yapilacak", "orta"],
|
|
["Yük testi", "1000 eşzamanlı istek", "yapilacak", "yuksek"]
|
|
]
|
|
dongu o icinde ornekler:
|
|
veritabani.sqlite(db, "INSERT INTO gorev(baslik, aciklama, sutun, oncelik, olusturma) VALUES (?, ?, ?, ?, ?)", [o[0], o[1], o[2], o[3], zaman.simdi()])
|
|
|
|
# Bütün görevleri JSON dizi olarak verir. JSON'u SQLite'ın kendi
|
|
# json_object/json_group_array işlevleri kurar → elle kaçış yazmayız.
|
|
fonksiyon gorevler_json(db):
|
|
sonuc = veritabani.sqlite(db, "SELECT json_group_array(json_object('id', id, 'baslik', baslik, 'aciklama', aciklama, 'sutun', sutun, 'oncelik', oncelik, 'olusturma', olusturma)) FROM (SELECT * FROM gorev ORDER BY id)")
|
|
eger sonuc == "":
|
|
don "[]"
|
|
don sonuc
|
|
|
|
fonksiyon gorev_json(db, kimlik):
|
|
don veritabani.sqlite(db, "SELECT json_object('id', id, 'baslik', baslik, 'aciklama', aciklama, 'sutun', sutun, 'oncelik', oncelik, 'olusturma', olusturma) FROM gorev WHERE id = ?", [kimlik])
|
|
|
|
# ── Doğrulama ───────────────────────────────────────────────────────
|
|
|
|
fonksiyon hata_json(ileti, durum):
|
|
don web.json(json.uret({"hata": ileti}), durum)
|
|
|
|
# Kimlik yalnız rakamlardan oluşmalı; "1 OR 1=1" gibi bir değer
|
|
# zaten parametre olarak bağlanır, ama anlamsız istek erkenden döner.
|
|
fonksiyon kimlik_gecerli(k):
|
|
eger k.uzunluk() == 0 veya k.uzunluk() > 9:
|
|
don yanlis
|
|
dongu i icinde 0..k.uzunluk() - 1:
|
|
eger degil "0123456789".icerir(k.dilim(i, 1)):
|
|
don yanlis
|
|
don dogru
|
|
|
|
# ── Uçlar ───────────────────────────────────────────────────────────
|
|
|
|
hazirla(db)
|
|
|
|
arayuz = dosya.oku("arayuz.html")
|
|
eger arayuz == "":
|
|
yazdir("⚠ arayuz.html bulunamadı — programı web/pano klasöründen çalıştırın.")
|
|
|
|
fonksiyon ana_sayfa(_istek):
|
|
don web.html(arayuz)
|
|
|
|
fonksiyon listele(_istek):
|
|
don web.json(gorevler_json(db))
|
|
|
|
fonksiyon olustur(istek):
|
|
govde = istek.govde()
|
|
eger degil json.gecerli_mi(govde):
|
|
don hata_json("gövde geçerli JSON değil", 400)
|
|
baslik = json.al(govde, "baslik").kirp()
|
|
aciklama = json.al(govde, "aciklama").kirp()
|
|
sutun = json.al(govde, "sutun")
|
|
oncelik = json.al(govde, "oncelik")
|
|
eger baslik == "":
|
|
don hata_json("başlık boş olamaz", 422)
|
|
eger baslik.uzunluk() > 120:
|
|
don hata_json("başlık en çok 120 karakter", 422)
|
|
eger sutun == "":
|
|
sutun = "yapilacak"
|
|
eger oncelik == "":
|
|
oncelik = "orta"
|
|
eger degil SUTUNLAR.icerir(sutun):
|
|
don hata_json("bilinmeyen sütun: " + sutun, 422)
|
|
eger degil ONCELIKLER.icerir(oncelik):
|
|
don hata_json("bilinmeyen öncelik: " + oncelik, 422)
|
|
|
|
veritabani.sqlite(db, "INSERT INTO gorev(baslik, aciklama, sutun, oncelik, olusturma) VALUES (?, ?, ?, ?, ?)", [baslik, aciklama, sutun, oncelik, zaman.simdi()])
|
|
yeni = veritabani.sqlite(db, "SELECT max(id) FROM gorev")
|
|
don web.json(gorev_json(db, yeni), 201)
|
|
|
|
fonksiyon guncelle(istek):
|
|
kimlik = istek.parametre("id")
|
|
eger degil kimlik_gecerli(kimlik):
|
|
don hata_json("geçersiz kimlik", 400)
|
|
eger veritabani.sqlite(db, "SELECT count(*) FROM gorev WHERE id = ?", [kimlik]) == "0":
|
|
don hata_json("görev bulunamadı", 404)
|
|
govde = istek.govde()
|
|
eger degil json.gecerli_mi(govde):
|
|
don hata_json("gövde geçerli JSON değil", 400)
|
|
|
|
# Yalnız gönderilen alanlar güncellenir.
|
|
sutun = json.al(govde, "sutun")
|
|
eger sutun != "":
|
|
eger degil SUTUNLAR.icerir(sutun):
|
|
don hata_json("bilinmeyen sütun: " + sutun, 422)
|
|
veritabani.sqlite(db, "UPDATE gorev SET sutun = ? WHERE id = ?", [sutun, kimlik])
|
|
baslik = json.al(govde, "baslik").kirp()
|
|
eger baslik != "":
|
|
veritabani.sqlite(db, "UPDATE gorev SET baslik = ? WHERE id = ?", [baslik, kimlik])
|
|
oncelik = json.al(govde, "oncelik")
|
|
eger oncelik != "":
|
|
eger degil ONCELIKLER.icerir(oncelik):
|
|
don hata_json("bilinmeyen öncelik: " + oncelik, 422)
|
|
veritabani.sqlite(db, "UPDATE gorev SET oncelik = ? WHERE id = ?", [oncelik, kimlik])
|
|
don web.json(gorev_json(db, kimlik))
|
|
|
|
fonksiyon kaldir(istek):
|
|
kimlik = istek.parametre("id")
|
|
eger degil kimlik_gecerli(kimlik):
|
|
don hata_json("geçersiz kimlik", 400)
|
|
eger veritabani.sqlite(db, "SELECT count(*) FROM gorev WHERE id = ?", [kimlik]) == "0":
|
|
don hata_json("görev bulunamadı", 404)
|
|
veritabani.sqlite(db, "DELETE FROM gorev WHERE id = ?", [kimlik])
|
|
don web.yanit("", 204)
|
|
|
|
# Tek iş parçacığı: SQLite'a yazan işleyiciler sırayla koşar.
|
|
sunucu = web.sunucu(8471, "127.0.0.1", 1)
|
|
sunucu.hatalar_json()
|
|
sunucu.govde_siniri(16384)
|
|
|
|
sunucu.al("/", ana_sayfa)
|
|
sunucu.al("/api/gorevler", listele)
|
|
sunucu.gonder("/api/gorevler", olustur)
|
|
sunucu.guncelle("/api/gorevler/{id}", guncelle)
|
|
# DELETE yöntemi `sunucu.kaldir` ile bağlanır
|
|
sunucu.kaldir("/api/gorevler/{id}", kaldir)
|
|
|
|
yazdir("📋 Pano hazır — http://127.0.0.1:8471")
|
|
sunucu.basla()
|