arrow-left

Only this pageAll pages
gitbookPowered by GitBook
1 of 28

Liman Eklenti Geliştirme

Loading...

Başlangıç

Loading...

Loading...

Genel Bilgiler

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Geliştirme

Loading...

Loading...

Loading...

Loading...

Arayüz Elemanları

Loading...

Loading...

Loading...

Loading...

İleri Seviye

Loading...

Loading...

Loading...

Loading...

Hoşgeldiniz!

BT süreçlerinizde bulunan bütün bileşenleri uzaktan, kararlı, güvenli ve genişletilebilir yöntemler ile merkezi olarak yönetmenizi sağlar.

hashtag
Liman MYS nedir?

Liman MYS'nin kurulumundan yapılandırılmasına ve açık kaynak ve kurumsal çeşitli eklentilerin kullanımı ile ilgili hazırlanan rehberdir.

Liman Merkezi Yönetim Sistemi BT süreçlerinizde bulunan bütün bileşenleri uzaktan, kararlı, güvenli ve genişletilebilir yöntemler ile merkezi olarak yönetmenizi sağlar.

Açık kaynak göç projelerinde Linux çekirdeğine sahip işletim sistemlerini ve diğer platformları Liman MYS ile yönetebilirsiniz.

Liman MYS

Modal

Liman eklentileri üzerinde kolay bir biçimde modal (açılır pencere) oluşturmanın yolları.

hashtag
Modal componenti nedir?

Modal Componenti

Modal componenti, karmaşık akışları kolaylaştırmak ve sayfa içinde görünmesini istemediğimiz yapılar için kullanılabilecek bir bileşendir.

  • Kullanıcıdan girdi alınması

  • Kullanıcıya veri detayı gösterilmesi

hashtag
Nasıl kullanılır?

hashtag
Modal açmak

hashtag
Modal düğmesi

Modal düğmesi componentini kullanarak oluşturduğunuz modalları açabilirsiniz. Aşağıdaki şekilde kullanılabilmektedir.

hashtag
Javascript ile modal açmak

Modallar düğme ile açılabildiği gibi sizin belirlediğiniz özel Javascript eventleri, fonksiyonları ile de açılabilmektedir.

hashtag
Modal oluşturmak

Örnek bir modal oluşturmak için aşağıdaki yapıyı kullanabilirsiniz. @component ve @endcomponent tagları içerisinde kalan kısma checkbox, radio button, input, selectbox ve diğer tüm HTML elementlerini istediğiniz gibi yerleştirerek modal içeriğini oluşturabilirsiniz.

hashtag
Modaldan değer almak

Yukarıdaki örnekte iki adet input tanımlamıştık. Bir tanesinde kullanıcı adı, diğerinde ise şifre isteniyordu. Bunları kullanıcı tarafından alarak üzerinde nasıl işlem yaparız gelin bakalım.

footer

Modal içerisindeki düğmelerin bulunduğu alt kısım.

footer->class

Düğmeye ait class değeri. (Renkler için kullanıyoruz)

footer->onclick

Tıklandığında gerçekleştirilecek işlem.

footer->text

Butonda görünecek yazı.

Parametre

Açıklama

text

Modal açma düğmesinin üzerinde yazacak yazı

class

Düğmeye ait olan class parametresi

target_id

Açılması istenilen modalın id değeri

Parametre

Açıklama

Veri Tipi

id

Modala ait olan id değeri. Benzersiz şekilde belirlenmelidir.

title

Modalda görünecek başlık değeri.

notSized

Boyut geniş mi dar mı olacak belirlediğimiz değer.

modalDialogClasses

Modal üzerine eklenmek istenen class değerleri.

@include("modal-button", [
    "text" => "Örnek Modal Aç",
    "class" => "btn-primary",
    "target_id" => "exampleModalWindow"
])
// Modal göster
$("#<MODAL_IDSI>").modal("show");

// Modal gizle
$("#<MODAL_IDSI>").modal("hide");
@component("modal-component", [
    "id" => "exampleModalWindow",
    "title" => "Örnek Modal",
    "notSized" => true,
    "modalDialogClasses" => "classExample",
    "footer" => [
        "class" => "btn-danger",
        "onclick" => "modalDialogEvent()",
        "text" => "What to do"
    ]
])    
    <input type="text" name="username" id="username_field" class="form-control">
    <small>Eklemek istediğiniz kullanıcı adını giriniz</small>

    <div class="mb-3"></div>
    
    <input type="password" name="password" id="password_field" class="form-control">
    <small>Kullanıcı şifresini giriniz</small>
@endcomponent
function modalDialogEvent() {
    showSwal("{{__('Yükleniyor...')}}", 'info');
    let data = new FormData();
    // exampleModalWindow modalının içerisinden username_field idsine sahip
    // inputtan değeri alıyor ve gönderdiğimiz requestin içerisine ekliyoruz.
    data.append("username", $("#exampleModalWindow").find("#username_field").val());
    // benzer bir işlemi şifre için de yapıyoruz
    // bu gönderdiğimiz değişkenlere controller tarafında 
    // request() yardımcı fonksiyonu ile erişeceğiz.
    // örnek: request("password");
    data.append("password", $("#exampleModalWindow").find("#password_field").val());

    request("{{API('add_user')}}", data, function(response){
        // işlem yapıldıktan sonra modal penceresini gizle.
        $("#exampleModalWindow").modal("hide");
        // Yükleniyor mesajını işlem bittiği için kapatıyoruz.
        Swal.close();
        // modal içerisindeki input değerlerini eski haline getiriyoruz.
        $("#exampleModalWindow").find("input").val("");
        response = JSON.parse(response);
        // Başarılı olduğuna dair 2.5 saniyelik bir mesaj gösteriyoruz.
        showSwal(response.message, 'success', 2500);
    }, function(error){
        error = JSON.parse(error);
        showSwal(error.message, 'error');
    });
}

Paket Bağımlılığı Eklemek

Geliştirdiğiniz eklentiyi çalıştırmak için Liman sunucusuna paket kurmanız gerekiyorsa, bu paketleri Liman'a nasıl otomatik kurdurabileceğinizi öğreneceğiz.

Bazı durumlarda eklentinizin bağımlılıkları olabilir, örneğin postgresql eklentisi geliştiriyorsanız php7.3-pgsql paketine ihtiyacınız olabilir. Liman eklentilerinde bu bağımlılıklarınızı db.json dosyanızdan veya Liman eklenti geliştirici arayüzünden tanımlayabilirsiniz.

  • Sol menüden Sistem Ayarları ikonuna tıklanır.

  • Eklentiler sekmesine geçilir ve eklentiye tıklanır.

  • Paket bağımlılıkları alanına paket isimleri araya boşluk bırakılarak yazılır.

  • Kaydet butonuna basılır.

Eklenti ilk defa Liman sistemine eklendiğinde paketler otomatik olarak kurulacaktır.

Composer

Eklentilere Composer yardımı ile kütüphane kurup kullanmayı öğreneceğiz.

OOP şablonu ile ile geliştirdiğiniz eklentilerde Composer ile paket kurup kullanabilirsiniz.

hashtag
Paket Kurulumu

Eklentinizin bulunduğu klasörde terminal açtıktan sonra composer require PAKET_ISMI komutuyla istediğiniz PHP paketini kurup kullanmaya başlayabilirsiniz.

Paket listesine ulaşmak için:
Eklenti Geliştirici Arayüzü
https://packagist.org/arrow-up-right

Yeni Eklenti Oluşturma

Bu başlık altında yeni eklenti oluşturma yollarından ve eklenti şablonlarından bahsedilecektir.

hashtag
Eklenti Oluşturmak

Liman MYS üzerinde eklenti oluşturmak için izlenmesi gereken adımlar şu şekildedir.

hashtag
Gerekli Ayarların Gerçekleştirilmesi

  • Sol alttaki sistem ayarları ikonuna tıklanarak ayarlar sayfası açılır.

  • Ayarlar sayfasındaki sekmelerden "İnce Ayarlar" sekmesi seçilir.

  • Gelişmiş sekmesi seçilir.

hashtag
Eklenti Sayfası ve Yeni Eklenti Oluşturmak

  • Bu işlemlerin ardından Eklentiler sekmesine girilir.

  • Yeni düğmesine tıklanır

  • Eklentimizin ismini gireriz. İsim sadece harflerden oluşmalıdır ve boşluk içermemelidir. Eklenti isminde Türkçe karakter de kullanılamaz fakat eklenti oluşturulduktan sonra eklentinin görünen adı istenildiği gibi değiştirilebilir. Bu kısımdan da bahsedeceğiz.

  • Eklentinin şablonu seçilir. Şablonlarımızdan daha detaylı bahsedeceğiz.

  • Seçilmesi gereken şablon "PHP 7.3 + OOP Training" seçeneğidir, eğer bu konuda bilgiliyseniz diğer seçenekleri de seçebilirsiniz.

hashtag
Yeni Eklenti Ayarları

Eklentiyi oluşturduktan sonra eklenti ayarları sayfasına otomatik yönlendirilir.

Bu kısımda gelin alanları birlikte inceleyelim.

  • Anahtarı Zorunlu Kıl: Bu alan lisanslı eklentileriniz için gereklidir.

  • Destek Email'i: Eklentinin içerisindeki destek düğmesinin gideceği e-posta adresini göstermektedir.

  • Logo (Font awesome): Sol menüde eklentinin gözükeceği ikonu ifade eder. (ör. fas fa-bolt)

Aşağıdaki örnekte görüldüğü üzere; bir sunucuya eklenti ekleme kısmında, eklentiyi oluştururken verilen Eklenti Adı değil de sonrasında eklenti ayarlarında ayarlanılan Eklenti Görünen Adı belirmektedir.

hashtag
Eklenti Şablonları

hashtag
PHP 7.3

Bu seçenek ile geliştirilen eklentilerde nesne yönelimli yapı bulunmamaktadır. Kod okunulabilirliği ve bakımı açısından zordur ancak geliştirmeyi en kolay bu şablon ile yapabilirsiniz.

hashtag
PHP 7.3 + OOP

Sizler için temel şablonların oluşturulmadığı, komponent örneklerinin bulunmadığı saf eklenti yapısıdır.

hashtag
PHP 7.3 + OOP Training

Bu eklenti yapısı Liman'ı yeni öğrenecekler için tasarlanmıştır. Tüm komponentlerin örneklerinin bulunduğu, dosyalamanın kod bakımı ve okunulabilirliği açısından en iyi formudur. Bu eklentileri geliştirirken JavaScript ve nesne yönelimli PHP bilgisine ihtiyaç duyulmaktadır.

Kontrolcüler

Eklentiler üzerinde kontrolcülerin kullanımından ve nasıl çalıştıklarından bahsedilecektir.

hashtag
Kontrolcü Nedir?

Controller, MVC’de projenin iç süreçlerini kontrol eden bölümdür. Bu bölümde View ile Model arasındaki bağlantı kurulur. Kullanıcılardan gelen istekler (request) Controller’larda değerlendirilir, isteğin detayına göre hangi işlemlerin yapılacağı ve kullanıcıya hangi View’ın döneceği veya JSON response belirtilir.

hashtag
Eklentilerde Kontrolcüler

Kontrolcüler, MVC yapısındaki ingilizce ismiyle Controller yapısıdır. MVC yapısına aşina olanlar bilecektir ki arka yüz işlemlerini kontrolcüler ile gerçekleştiriyoruz. Gelin birlikte temel bir kontrolcüyü inceleyelim.

Gördüğümüz üzere kontrolcü aslında bir PHP nesnesidir. Bu nesne içinde fonksiyon/fonksiyonlar saklamaktadır. Bu fonksiyonları daha sonra rotalar ile birlikte işlerimiz için kullanacağız.

Kontrolcümüzün fonksiyonları içerisinde çalıştırılması gereken arka yüz işlemlerini yapabiliriz. Daha spesifik bir örnek vermemiz gerekirse Liman ile sisteme bir kullanıcı ekleme işlemini şu şekilde gerçekleştirebiliriz.

Yukarıdaki kod bloğunda görebileceğimiz üzere UserController nesnemizin içerisinde add() fonksiyonu bulunmaktadır. Bu fonksiyon daha sonra bahsedeceğimiz Liman Toolkitini kullanarak sistem üzerinde bir komut çalıştırmaktadır. Çalıştırdığı komutların ardından işlemin başarılı olduğuna dair bir yanıt döndürmektedir.

Liman eklentilerinde kontrolcüler genelde POST requestlerine yanıt vermek için kullanılır. Nadir durumlarda view döndürülmektedir.

Kontrolcülerde tanımladığımız fonksiyonları daha sonra rotalar ile çağırarak yardımcı fonksiyonlar sekmesinde göreceğimiz request() fonksiyonumuz ile kullanacak, işlemlerin çalıştırılmasını sağlayacağız.

Kontrolcülerin yaşam döngüsü Liman üzerinde aşağıdaki şekilde kullanmayı tercih ediyoruz. İsterseniz View/Controller ve sayfalı yapı da oluşturabilirsiniz ancak biz daha çok REST API olarak kullanmayı tercih ettik.

Daha önceden index kontrolcüsü tarafından render edilmiş interaktif öğeleri kullanarak bir request gönderimi yaparız. Ardından kontrolcümüz bu requestleri alarak yönetilen sistemde veya başka bir işlem için kullanarak değişiklikler yapar. Ardından kontrolcü işlemin durumuna göre başarılı veya başarısız diye bir yanıt gönderir. Yanıt, arayüz tarafından alındıktan sonra kontrolcünün yaşam döngüsü tamamlanmıştır.

Protokol Bağlantıları (LDAP, SMB)

Liman eklentilerinizde belirli protokole nasıl bağlanabileceğinizi öğreneceğiz.

Liman sisteminde eklenti geliştirirken belirli protokollerle çalışmanız gerekebilir. Böyle bir durumda ek bir kütüphane veya destekliyorsa doğrudan php'nin fonksiyonlarını kullanabilirsiniz.

hashtag
Örnek LDAP Bağlantısı

LDAP protokolünü PHP diliyle kütüphaneye gerek olmadan kullanabilirsiniz. Fakat eklentinize php7.3-ldap debian paketini bağımlılık olarak eklemelisiniz.

Paket Bağımlılığı Eklemekchevron-right

LDAP protokolüyle bind olabilmek için kullanıcıdan kullanıcı adı ve şifre gibi bilgileri istemeniz gerekebilir. Eklenti veritabanı ile bu bilgileri kullanıcıdan isteyebilirsiniz.

Sonrasında ise bağlantı açıp istenilen veriler alınmaya başlanabilir.

Detaylı bilgi için:

hashtag
Örnek SMB Bağlantısı

SMB bağlantısı için icewind/smb kütüphanesini kullanabilirsiniz. Bu kütüphaneyi kullanmak için de bazı php debian modüllerini kurmanız gerekebilir. php-smbclient ve smbclient debian paketlerini eklentinizin bağımlılıklarına ekleyebilirsiniz.

  • Paket kurulumu için aşağıdaki komutu eklenti dizininizde çalıştırabilirsiniz.

  • Paketi kurduktan sonra kütüphaneyi kullanmaya başlayabilirsiniz.

Daha fazla bilgi için:

Dosya ve Dizin Yapısı

Liman eklentilerinin dizin yapısından ve klasörlerin ne işe yaradığını öğreneceğiz.

  • routes.php Controller rotalarımızı tanımladığımız dosya.

  • composer.json Composer ile paket yükleyebilmek için bulunması gereken dosya.

Veritabanı Mantığıchevron-right
https://www.php.net/manual/tr/ref.ldap.phparrow-up-right
Composerchevron-right
https://github.com/icewind1991/SMBarrow-up-right
db.json Eklentinizin veritabanı kullanması için gereken konfigürasyon dosyası.
  • app Eklentimizin arka yüzünü bulunduran klasör.

    • Controllers Kontrolcülerimizi bulunduran klasör. Arka yüzde çalışan işlemlerin hepsi bu klasör içerisindeki dosyalarda yazılır.

    • Helpers/Helper.php Yardımcı fonksiyonlarınızı bu kısıma yazarsınız. Örneğin bir portun açık olup olmadığını kontrol eden fonksiyon.

    • Tasks Görevleri oluşturduğumuz ve çalıştıracağı komutları belirlediğimiz klasör.

  • lang Yerelleştirme dosyalarını bulunduran bir klasör.

  • public Eklentinin içinde kullanılacak, tüm eklenti genelinde yüklenmesini istediğimiz JavaScript ve CSS dosyalarını ekleyebileceğimiz klasör. Örnek kullanım eklenti şablonunda mevcuttur.

  • scripts Bu klasöre runScript ile sistem üzerinde çalıştırmak istediğimiz betikleri koyarız. Örneğin sambaOlustur.py ve enableWinrm.ps1 gibi.

  • vendor Composer dosyalarını ve class autoloader içeren klasör. Bu klasörde düzenleme yapmayacağız.

  • views Bu klasörde açılan alt klasörler sekmeli eklenti yapısının her bir sekmesi içindir. Bu klasörler de içerisinde main.blade.php ve scripts.blade.php içermektedir. Scriptlerin Javascript yerine blade ile eklenmesinin sebebi yerelleştirme, dinamik rotalar ve PHP ile çıktı alınması gereken bazı kısımların varlığındandır.

    • index.blade.php & scripts.blade.php index dosyamız içerisinde sekmelerimizi oluştururuz ve sekmelerin alt viewlarını include ederiz. Scripts dosyamızda ise tüm tablar geneli çalışmasını istediğimiz PHP bağımlı Javascript kodlarımızı yazabiliriz.

  • $connection = ldap_connect('ldaps://' . server()->ip_address); //eklentinin eklendiği sunucunun ip adresi ile LDAPS protokolünü kullanarak bağlantı açıyoruz.
    ldap_bind($connection, extensionDb('clientUsername'), extensionDb('clientPassword')); //eklenti veritabanına yazdığımız keylere göre kullanıcının LDAP kullanıcı adı ve şifresiyle bind oluyoruz.
    $result = ldap_search($connection, "DC=baran,DC=lab", "(cn=*)"); //base dn'e göre arama yapıyoruz.
    $data = ldap_get_entries($connection, $result); //arama sonuçlarını alıyoruz.
    dd($data); //dönen sonuçları debug etmek için dd helperını kullanıyoruz. 
    composer require icewind/smb
    $options = new Options();
    $options->setTimeOut(5);
    $serverFactory = new ServerFactory($options);
    $auth = new BasicAuth(extensionDb('clientUsername'), 'workgroup', extensionDb('clientPassword'));
    $server = $serverFactory->createServer(server()->ip_address, $auth);
    $share = $server->getShare('SYSVOL');
    dd($smb->read('ORNEK_PATH'));
    liman@pardus:/liman/extensions/ornekeklentim$ tree
    ├── routes.php
    ├── composer.json
    ├── db.json
    ├── app
    │   ├── Controllers
    │   ├── Helpers
    │   └── Tasks
    ├── lang
    ├── public
    │   ├── css
    │   └── js
    ├── scripts
    ├── vendor
    └── views
        ├── hostname
        ├── layouts
        ├── runscript
        ├── sandbox
        ├── systeminfo
        ├── taskview
        ├── index.blade.php
        └── scripts.blade.php
    Eklenti geliştirici modu "Aktif" hale getirilir.

    Paket bağımlılıkları: Eklentinin çalışması için gereken paketleri bu kısımda belirtiriz. (ör. dnsutils php7.3-ldap php-smbclient)

  • Versiyon: Eklentinin versiyon kodudur.

  • Ayar Doğrulama Fonksiyonu/Betiği: Çalıştırılacak doğrulama fonksiyonu belirtilir.

  • Gerekli Minimum Liman Sürüm Kodu: Eklentinin çalışacağı Liman sürümünü belirleriz.

  • Servis Adı ya da Kontrol Portu: Eklentinin çalışması için açık olması gereken port veya servisi bu kısımda belirtiriz.

  • SSL Sertifikası Eklenecek Portlar: Portlardan Liman'a SSL sertifikası eklenerek bağlantı işlemi sağlanmaktadır. (ör. LDAP 636 portu ve sertifikası)

  • Eklenti Görünen Adı: Eklentinin arayüzde (sunucuya eklenti eklerken vs.) görünecek adıdır. Bu kısımda eklenti adında bulunan karakter kısıtlamaları geçerli değildir. Türkçe karakter, boşluk veya özel karakter kullanılabilir. Yukarıdaki resimde görüldüğü gibi tüm Türkçe alfabeyi ve bazı özel karakterlerle boşluğu içeren bir isim verilebilmiştir.

  • Eklenti Geliştirici Modu
    Eklentiler sayfası
    Yeni Oluşturulmuş Eklenti
    <?php
    namespace App\Controllers;
    
    class HomeController
    {
    	public function index()
    	{
    		return view('index');
    	}
    }
    Liman Eklenti Kontrolcüsü Yaşam Döngüsü

    Toolkit Kullanımı

    Toolkit, Liman eklentilerinin geliştirilmesini kolaylaştırmak için çeşitli yardımcılar ve sınıflar sağlayan bir kütüphanedir.

    hashtag
    Örnekler

    hashtag
    Distro

    use Liman\Toolkit\OS\Distro;

    hashtag
    Command

    hashtag
    Formatter

    hashtag
    Validation

    Yerelleştirme

    Liman eklenti paketlerinizde farklı dil desteği sağlamak için yapmanız gereken işlemler.

    hashtag
    Yerelleştirme nedir?

    Yerelleştirme, yazılım geliştirme sürecinde, içeriklerin (kitaplar, filmler, Ağ Sayfaları), süreçlerin, ürünlerin ve özellikle bilgisayar yazılımlarının (Software) belirli bir coğrafyaya ya da etnik topluluğa özgü pazar ya da coğrafi bölgede (ülke, bölge ya da etnik gruplar) geçerli yerel dilsel ve kültürel özelliklere uyarlanmasıdır.

    Bu sözcüğün İngilizcesi olan localization (Amerikan İngilizcesi) ya da localisation (İngiltere) yazılım geliştiriciler tarafından L10N şeklinde kısaltılmıştır. 10 rakamı L ile N harfleri arasında kalan harflerin sayısını gösterir. Yerelleştirmenin karşıt anlamına gelen I18N ise internationalization için kullanılır.)

    hashtag
    Nasıl yapılır?

    Liman üzerinde yerelleştirme yapabilmek için sağladığımız yardımcı fonksiyonlar mevcuttur. Bu yardımcı fonksiyon diğer PHP projelerinizden de hakim olabileceğiniz üzerine double underscore fonksiyonudur. __() şeklinde tanımlanır.

    hashtag
    Blade içerisinde yerelleştirme

    Blade viewları üzerinde yerelleştirme yaparken yukarıdaki görüntüyü kullanırız. Çifte süslü parantez kullanımının içerisinde yerelleştirme fonksiyonunu çağırabiliriz.

    hashtag
    Javascript üzerinde yerelleştirme

    Liman eklentileri üzerinde yerelleştirmeyi sağlayabilmek ve PHP'den gelen veriye göre değişken script gösterimi yapabilmek için yine Blade kullanıyoruz. Örnek eklentimizde görebileceğiniz üzere her tab için ayrı bir scripts.blade.php dosyası tanımlanmaktadır. Yine de bizim temel olarak "Yükleniyor..." yazısında kullandığımız örneği görelim.

    hashtag
    Çevirileri oluşturma

    Çeviriler için eklenti klasörünüzdeki lang klasörünü kullanmaktayız. Türkçe girdiğimiz stringler için en.json dosyası üzerinde key olarak Türkçe stringin kendisini, diğer tarafa da İngilizce çevirisini eklemeliyiz. Örnek olarak kendi eklentiniz içerisindeki en.json dosyasını inceleyebilirsiniz.

    PHP Yardımcı Fonksiyonları

    Liman üzerinde eklentilerle kullanabileceğiniz PHP yardımcı fonksiyonların listesi.

    hashtag
    checkPort

    checkPort fonksiyonu bizim için bir portun açık olup olmadığını kontrol etmekte buna göre bir boolean yanıtı döndürmektedir. Fonksiyonu kullanabilmek için iki adet argüman sağlamanız gerekmektedir.

    Bileşen Mantığı

    Geliştirdiğiniz eklentiye Liman anasayfasına eklenebilen bir bileşen entegre etmeyi öğreneceğiz.

    Liman sisteminin anasayfası eklentiler tarafından özelleştirilebilen bir yapıya sahiptir. Eklentinizi entegre ettiğinizde Bileşenler sayfasından anasayfaya eklenip çıkarılabilen bileşenler elde edebilirsiniz.

    hashtag
    Bileşen Tanımlama

    <?php
    namespace App\Controllers;
    
    use Liman\Toolkit\Shell\Command;
    
    class UserController
    {
    	public function add()
    	{
    		 $command = Command::runSudo("useradd -p $(echo @{:password} | openssl passwd -1 -stdin) -s /bin/bash -g users @{:username}", [
             "username" => request("username"),
             "password" => request("password")
         ]);
    
         Command::runSudo("mkhomedir_helper @{:username}", [
             "username" => request("username")
         ]);
    
         return respond(__("Başarıyla eklendi"), 200);
    	}
    }
    Distro::debian('apt install nano -y')
        ->centos('yum install nano -y')
        ->runSudo();
    Distro::debian("echo 'debian'")
        ->centos("echo 'centos'")
        ->centos6("echo 'centos6'")
        ->centos7("echo 'centos7'")
        ->pardus19("echo 'pardus19'")
        ->pardus192("echo 'pardus19.2'")
        ->pardus193("echo 'pardus19.3'")
        ->ubuntu("echo 'ubuntu'")
        ->ubuntu1804("echo 'ubuntu18.04'")
        ->ubuntu2004("echo 'ubuntu20.04'")
        ->ubuntu2010("echo 'ubuntu20.10'")
        ->default("echo 'Hiçbiri değil'")
        ->run();
    use Liman\Toolkit\Shell\Command;
    Dökümantasyonarrow-up-right

    $ip

    IP adresi yazmanız gerekmektedir.

    String

    $port

    Port numarası belirtmeniz gerekmektedir.

    Integer

    (Return)

    Fonksiyonun geri döndürdüğü değer

    Boolean

    hashtag
    Request

    PHP tarafındaki request fonksiyonu bizim kontrolcümüze POST ile gönderilmiş değişkenleri yakalamamızı sağlar. Örneğin bir inputtan clientHostname isimli bir veri gönderdiysek bunu PHP tarafında request("clientHostname") olarak kolayca yakalayabiliriz.

    Argüman

    Açıklama

    Veri Tipi

    $name

    Attığınız requestteki key ismi

    String

    hashtag
    server, user, extension

    Bu helperlar Laravel tarafındaki server, user, extension modellerini getirmektedir. server()->name örnek bir kullanımdır. Detaylarını anlayabilmek için eklenti kodlarınızda dump(server()) tarzı bir kullanım yaparsanız içeriğini görüntüleyebilirsiniz.

    hashtag
    Respond

    Yanıt döndürme fonksiyonudur. İki argüman almaktadır. JSON olarak karşıya veri getirir, dönen verinin örnek tipi aşağıdaki gibidir.

    Anlaşılacağı üzere fonksiyon da iki adet argümanı mesaj ve durum kodu olarak almaktadır. Yukarıdaki yanıtı alabilmek için fonksiyonu aşağıdaki gibi çalıştırırız.

    Argüman

    Açıklama

    Veri Tipi

    $message

    Mesajınızı veya döndürmek istediğiniz PHP, HTML herhangi bir veriyi gönderirsiniz.

    Auto

    $status

    HTTP durum kodlarından birini istediğiniz şekilde gönderiniz. 200 başarılı anlamına gelmektedir.

    Integer

    hashtag
    View

    View fonksiyonu controlleriniz üzerinden bir view dosyasını renderlamanızı sağlamaktadır. Örnek olarak aşağıdaki gibi görebiliriz.

    hashtag
    Validate

    Validate fonksiyonu Laravel üzerindeki gibi çalışmaktadır. Genel kurallarına ve örnek kullanıma Validation - Laravel Docsarrow-up-right kısmından ulaşabilirsiniz.

    Kullanım şekli olarak Laravel ile birebir uyuşmasa da kuralların yazıldığı kısım birebir uyuşmaktadır. Gelin bir örnek kullanıma bakalım.

    validate fonksiyonu bir kontrolcü fonksiyonunun başında çağırılır. Aldığı tek argüman kurallar listesidir. Kuralların kullanımında örnek kullanım yukarıdaki gibidir. Örnek olarak listenin ilk elemanından bahsedelim. Bize form data ile gönderilmiş olan username verisi request("username") ile eşleşmektedir. Bu eşleşme uyduğunda doğrulayıcı fonksiyonumuz value olarak verdiğimiz required|string kurallarına göre request("username") verisini doğrulayacaktır. Eğer doğrulanamazsa da kontrolcü fonksiyonunun çalışması durdurulup, mesaj olarak doğrulanamadığına dair hata mesajı dönecektir.

    Argüman

    Açıklama

    Veri Tipi

    $rules

    Kuralların olduğu liste.

    Array

    circle-info

    Validation - Laravel Docsarrow-up-right sayfasından validation fonksiyonunun detaylı dokümanına ulaşabilirsiniz.

    hashtag
    Laravel Helpers

    Liman eklenti sandboxu üzerinde Laravel Helpers paketi çalışmaktadır. Bu paket ile Array ve Object manipülasyonları, dosya yolu yardımı, string manipülasyonları, fluent string manipülasyonları, URL işlemleri ve çeşitli ek fonksiyonlar (dump, abort, retry, response, bcrypt, view...) yer almaktadır. Bu paketin yer alması neredeyse Laravel üzerinde çalışan çoğu fonksiyonu eklentilerinizde de kullanabileceğiniz anlamına gelmektedir.

    circle-info

    https://laravel.com/docs/8.x/helpersarrow-up-right adresinden detaylı dokümana ulaşabilirsiniz.

    hashtag
    Kendi Helperlarınızı Geliştirin

    Kendi özel helperlarınızı geliştirmek için eklenti klasörünüz içerisinde app/Helper/Helpers.php içerisinde daha önce tanımladığımız checkPort fonksiyonuna bakarak tanımlama yapabilirsiniz, daha önceden topluluk tarafından geliştirilmiş Helper dosyalarını incelemek için Liman Market'ten indirdiğiniz açık kaynaklı eklenti kodlarına da göz atabilirsiniz. zekiahmetbayar/liman-sambahvlarrow-up-right örnek eklentisinde sistemdeki sertifika kontrolleri için ve LDAP bağlantı kontrolü için de yardımcı fonksiyonlar geliştirilmiştir.

    Argüman

    Açıklama

    Veri Tipi

    echo Command::run('hostname');
    Command::runSudo('hostnamectl set-hostname @{:hostname}', [
        'hostname' => request('hostname')
    ]);
    use Liman\Toolkit\Shell\SSHEngine;
    SSHEngine::init(
        request('ipAddress'),
        request('username'),
        request('password')
    );
    Command::bindEngine(SSHEngine::class);
    echo Command::run('hostname');
    use Liman\Toolkit\Formatter;
    echo Formatter::run('hostnamectl set-hostname @{:hostname}', [
        'hostname' => request('hostname')
    ]);
    
    //output: hostnamectl set-hostname pardus
    validate([
        'hostname' => 'required|string'
    ]);
    main.blade.php
    {{ __("Türkçe string") }}
    scripts.blade.php
    showSwal("{{__('Yükleniyor...')}}", 'info', 2000);
    en.json
    {
        "Sandbox Elemanları": "Sandbox Components",
        "Kullanıcı Ayarları": "Kullanıcı Ayarları",
        "Grup Ayarları": "Grup Ayarları",
        "Merhaba Dünya!": "Hello World!",
        "Hostname Değiştir": "Change Hostname",
        "Durdur": "Stop",
        "Task çalıştırılıyor...": "Running task...",
        "Görev İşleniyor": "Executing Task"
    }
    {"message": "pardus", "status": 200}
    return respond("pardus", 200);
    return view("table", [
        "value" => $files,
        "title" => ["İsim", "İzinler", "Sahip", "Grup", "Dosya Boyutu", "Son Değiştirilme"],
        "display" => ["name", "permissions", "user", "group", "size", "date"]
    ]);
    validate([
        'username' => 'required|string',
        'password' => 'required|string'
    ]);
    Sol menüdeki Ayarlar menüsüne tıklanır.
  • Eklentiler sekmesine geçilir ve eklentiye tıklanır.

  • Bileşenler sekmesine geçilir.

  • Bileşenler Ekranı
    • Yeni bir bileşen eklemek için Widget Ekle butonuna basılır.

    Alan

    Tip

    Açıklama

    Değerler

    Widget Adı

    string

    Bileşenler sayfasında gösterilecek isim.

    -

    İkon

    string

    Bileşen render edildiğinde gösterilecek ikon.

    Türü

    hashtag
    Fonksiyon Tanımlama

    Bileşeninizin verilerini sağlayan fonksiyonu tanımlamak için WidgetController adında bir Kontrolcü oluşturup bu kontrolcü sınıfının içerisinde bir fonksiyon oluşturabilirsiniz.

    Ardından routes.php dosyasından bir önceki aşamada Çalışacak Fonksiyon alanına yazdığımız isimde bir Rota oluşturmalıyız.

    Artık Bileşeniniz kullanıma hazır.

    hashtag
    Bileşeni Liman'a Eklemek

    • Üst bardaki Bileşenler ikonuna tıklayın.

    Bileşenler Ekranı
    • Bileşen Ekle butonuna tıklayın.

    Bileşen Ekleme Ekranı
    • Sunucu ve Eklenti seçimi yaptıktan sonra yeni eklediğiniz Bileşeni seçebilirsiniz.

    • Bileşen Ekle butonuna bastığınızda Liman anasayfasında bileşeniniz görünecektir.

    Örnek Bileşen Görüntüsü

    JS Yardımcı Fonksiyonları

    Arayüzde işlemler yaparken kullanabileceğiniz genel Javascript yardımcı fonksiyonlarından bahsedeceğiz.

    hashtag
    showSwal

    showSwal fonksiyonu Sweetalert2 için kullandığımız yardımcı fonksiyondur. Hızlı ve basit bir şekilde Swal ateşlemenizi sağlar. Örnek kullanımı aşağıdaki gibidir.

    Argüman

    Açıklama

    hashtag
    API

    Bu fonksiyon hem Javascript, hem de PHP tarafımızda bulunmaktadır. Bu fonksiyona Rotalar sayfasında girdiğimiz isim değişkenini verdikten sonra bize request atacağımız url'yi döndürmektedir. Örnek kullanım aşağıdaki gibidir.

    hashtag
    Request

    Request fonksiyonu Liman eklentilerinde kullandığımız en önemli fonksiyonlardan biridir. Controllerlar veya dış kaynak bir API üzerinden veri almamızı sağlar. Gelin örnek bir request fonksiyonunu inceleyelim.

    Bu fonksiyon belirlediğimiz url'ye bir POST requesti göndermektedir. Bu requestin sonucunda dönen veriye response, hata alırsak dönen veriye de error denmektedir. Gelin argüman listesi ve detaylarına bakalım.

    hashtag
    jQuery Fonksiyonları

    Liman üzerinde jQuery kullanıldığı için istediğiniz tüm jQuery işlemlerinden faydalanabilirsiniz.

    Veritabanı Mantığı

    Geliştirdiğiniz eklentilerde kullanıcıdan veri alıp, bu veriyi nasıl kullanacağımızı öğreneceğiz.

    Liman sisteminde eklenti geliştirirken, kullanıcı adı ve şifre gibi bazı bilgileri kullanıcıdan almanız gerekebilir. Bu durumda eklenti veritabanı yapısını kullanabilirsiniz.

    hashtag
    Alan Tanımlama

    • Sol menüdeki Sistem Ayarları ikonuna tıklayalım.

    • Eklentiler sekmesinden eklentinize tıklayıp detay sayfasına girelim.

    • Eklenti Veritabanı sekmesine geçelim.

    • Mevcut tanımlanmış alanları bu ekrandan görüp düzenleyebilir veya silebilirsiniz.

    • Yeni bir alan eklemek için Veri Ekle butonuna basalım.

    • Formdaki gerekli alanları doldurduktan sonra Veri Ekle butonuna basarak kaydedebilirsiniz.

    • İlk veritabanı ayarını eklediğinizde eklentiye girdiğinizde Liman sistemi sizi eklenti ayarları sayfasına yönlendirecek ve sizin belirlediğiniz alanları doldurmanızı isteyecektir.

    hashtag
    Alanın Değerine Erişmek

    Geliştirdiğiniz eklentide kullanıcıdan aldığınız verilere erişmek için extensionDb helper fonksiyonunu kullanabilirsiniz. Bir önceki aşamada alanı tanımlarken girdiğiniz Variable Adı bu aşamada kullanılmaktadır.

    DB Kütüphanesi

    Veritabanı işlemleri için kullanabileceğiniz illuminate/database kütüphanesinin entegrasyonunu öğreneceğiz.

    Eklentinizde bir veritabanına bağlanıp işlem yaptırmanız gerekiyor ise illuminate/database kütüphanesini entegre edebilirsiniz. Bu kütüphane gelişmiş sql builder'ı ile okunaklı ve güvenli sql komutları çalıştırmanızı sağlar.

    hashtag
    Gerekli Paketlerin Kurulumu

    Gerekli paketleri kurduktan sonra app/Helpers klasöründe DB.php adında bir dosya oluşturuyoruz. Dosyanın içeriği aşağıdaki gibi olabilir.

    <?php
    
    namespace App\Controllers;
    
    class WidgetController
    {
        public function exampleWidget()
        {
            return respond(5);
        }
    }
    <?php
    
    return [
        "index" => "HomeController@index",
        "verify" => "HomeController@verify",
        "load" => "HomeController@load",
    
        "example_widget" => "WidgetController@exampleWidget"
    ];
    showSwal("Yükleniyor...", "info", 2500);

    Function

    Veri Tipi

    message

    Göstermek istediğiniz mesaj.

    String

    type

    Gösterilen Swal'ın türü. (info, danger, error...)

    String

    time

    Ne kadar süre gösterilecek (ms bazında)

    Integer

    Argüman

    Açıklama

    Veri Tipi

    url

    İstek gönderilmesini istediğimiz endpoint.

    String

    data

    POST requestte göndereceğimiz ek veriler.

    FormData

    response

    Yanıt geldiğinde yapılacak işlemlerin fonksiyonu

    Function

    error

    Hata oluştuğunda yapılacak işlemlerin fonksiyonu

    Sınıfımızı tanımladıktan sonra veritabanı işlemi yapacağımız kontrolcülerde şu şekilde kullanabiliriz:
    • Öncelikle use anahtar sözcüğü ile sınıfımızı import etmeliyiz.

    Sonrasında kontrolcü sınıfımızın herhangi bir yerinde DB sınıfını çağırıp işlemlerimizi yaptırabiliriz.

    DB::database('') ifadesi bizim sınıfımıza özel dinamik olarak farklı veritabanlarına bağlanmayı sağlayan bir fonksiyondur. DB sınıfımız illuminate/database kütüphanesindeki Capsule sınıfından türetilmiştir. Dolayısıyla Laravel database dökümanındaki tüm özellikleri DB sınıfıyla kullanabilirsiniz.

    Detaylı bilgi için: https://laravel.com/docs/8.x/queries#select-statementsarrow-up-right

    composer require illuminate/database
    composer require illuminate/events
    composer require doctrine/dbal
    API("get_files")
    let data = new FormData()
    request("url", data, function(response) {
        console.log(response);
    }, function(error) {
        console.log(error);
    });
    showSwal("{{__('Yükleniyor...')}}", 'info');
    let data = new FormData();
    request("{{API('list_files')}}", data, function(response){
        $("#filesTable").html(response).find("table").dataTable(dataTablePresets("normal"));
        Swal.close();
    }, function(response){
        response = JSON.parse(response);
        showSwal(response.message, 'error');
    });
    <?php
    namespace App\Helpers;
    
    use Illuminate\Container\Container;
    use Illuminate\Database\Events\StatementPrepared;
    use Illuminate\Database\Capsule\Manager as Capsule;
    use Illuminate\Events\Dispatcher;
    use Illuminate\Pagination\Paginator;
    use Illuminate\Pagination\LengthAwarePaginator;
    use PDO;
    
    class DB extends Capsule
    {
    	private static $customContainer;
    	private static $capsule;
    	private static $initialized = false;
    
    	public static function init()
    	{
    		self::$customContainer = new Container();
    		self::$capsule = new self(self::$customContainer);
    		self::$capsule->addConnection([
    			'driver' => 'pgsql',
    			'port' => extensionDb('postgrePort'),
    			'host' => extensionDb('postgreHost'),
    			'username' => extensionDb('postgreUsername'),
    			'password' => extensionDb('postgrePassword'),
    			'charset' => 'utf8',
    			'collation' => 'utf8_unicode_ci',
    			'prefix' => ''
    		]);
    		self::$capsule->setEventDispatcher($dispatcher = new Dispatcher());
    		$dispatcher->listen(StatementPrepared::class, function ($event) {
    			$event->statement->setFetchMode(PDO::FETCH_ASSOC);
    		});
    		self::$capsule->setAsGlobal();
    		self::$initialized = true;
    	}
    
    	public static function database(string $dbName)
    	{
    		if (!self::$initialized) {
    			self::init();
    		}
    		$connections = self::$customContainer['config']['database.connections'];
    		$connections['default']['database'] = $dbName;
    		self::$customContainer['config']['database.connections'] = $connections;
    		return self::$capsule;
    	}
    
    	public function __call($method, $parameters)
    	{
    		return self::$capsule::connection()->$method(...$parameters);
    	}
    
    	public static function __callStatic($method, $parameters)
    	{
    		return self::$capsule::connection()->$method(...$parameters);
    	}
    }
    
    use App\Helpers\DB;
    $users = DB::database('example_application')->table('users')->get();
    dd($users);

    Kaydedilen veriye yazılımsal olarak erişebilmek için gerekli anahtar adı.

    -

    Zorun Alan

    checkbox

    Bu alan işaretlendiğinde kullanıcı bu alanı boş bırakamaz.

    -

    Alan

    Tip

    Açıklama

    Değerler

    Adı

    string

    Kullanıcıya gösterilecek isim.

    -

    Türü

    string

    Oluşturulacak input'un tipi.

    text password certificate extension server

    Variable Adı

    Eklenti Veritabanı Sekmesi
    Yeni Veri Ekleme Ekranı
    Örnek Eklenti Ayarları Sayfası

    string

    selectbox

    Bileşenin tipi.

    Sayı Grafik

    Çalışacak Fonksiyon

    string

    Eklenti içerisinde tanımlanmış ve bileşen verisini geriye döndüren fonksiyonun adı.

    -

    https://fontawesome.com/v5.15/icons?d=gallery&m=freearrow-up-right

    Görev (Task)

    Paket yükleme&kaldırma ve benzeri tüm uzun süren işlemleri arkaplanda çalıştırıp arayüzde çıktıları göstermeyi kolaylaştıran Task(Görev) componentini öğreneceğiz.

    Eklentinizde bazı durumlarda uzun süren işlemler yaptırmanız gerekebilir. Bu gibi durumlarda Task componentini kullanabilirsiniz.

    hashtag
    Task Soyut Sınıfından Türeyen Bir Sınıf Oluşturmak

    • OOP eklenti klasör yapısında öncelikle app klasöründe Tasks isminde bir klasör oluşturuyoruz ve InstallPackage.php dosyası oluşturuyoruz.

    • Task soyut sınıfındaki değişkenleri yaptıracağımız işe göre override ediyoruz.

    hashtag
    Görevleri Çalıştırmak

    • Controller içerisinde bir fonksiyon tanımlıyoruz ve routes.php içerisinde gerekli tanımlamaları yapıyoruz.

    • Bu fonksiyon geriye task componentini çalıştırmanız için gerekli HTML verisini döndürür.

    • Birden fazla task tasks dizisi içerisinde tanımlanabilir böyle bir durumda görevler kuyruklanır ve sırayla çalıştırılır.

    hashtag
    Blade İçerisinde Task Componentinin Kullanımı

    • Tercihe bağlı olarak Görev componenti bir Modal içerisinde gösterilebilir.

    • Bu şekilde bir modal tanımlanabilir.

    • Görevi başlatmak için de bu şekilde javascript ile ajax çağrısı yapılır ve Task modal'ının içerisine eklenir.

    Dosya Yükleme, İndirme

    Eklentinin eklendiği sunucuya dosya yüklemeyi veya sunucudan dosya indirmeyi öğreneceğiz.

    Eklentinin eklendiği sunucudan Liman sunucusuna dosya indirmenin veya Liman sunucusundan karşı sunucuya dosya yüklemenin gerekli olduğu durumlarda kullanılabilecek iki fonksiyon Liman sisteminde tanımlanmıştır.

    hashtag
    putFile

    Bu fonksiyon Liman sunucusundan karşı sunucuya dosya yükler.

    hashtag
    getFile

    Bu fonksiyon ise karşı sunucudan Liman sunucusuna dosya indirir.

    echo extensionDb('username');

    Argüman

    Açıklama

    Veri Tipi

    $localPath

    Liman sunucusundaki dosyanın konumu.

    string

    $remotePath

    Karşı sunucuda dosyanın yükleneceği yol.

    string

    Argüman

    Açıklama

    Veri Tipi

    $localPath

    Liman sunucusunda indirilecek dosyanın yolu.

    string

    $remotePath

    Dosyanın karşı sunucudaki konumu.

    string

    İşlemin bitip bitmediğini anlamak için gerekli grep kontrol deseni.

    $attributes

    array

    Komut metninde değişken kullandıysanız değişkenlerin değerlerinin tanımlanması gereken dizi. (opsiyonel)

    $checkCommand

    string

    İşlemin başarıyla bitip bitmediğinin kontrolünü sağlayan komut. (opsiyonel)

    Değişken

    Tip

    Açıklama

    $command

    string

    Çalıştırılacak komut metni.

    $logFile

    string

    Komutun çıktılarının saklanacağı konum.

    $sudoRequired

    boolean

    Sudo gerekli ise true olmalıdır. (opsiyonel)

    $control

    string

    <?php
    namespace App\Tasks;
    
    use Liman\Toolkit\Formatter;
    use Liman\Toolkit\RemoteTask\Task;
    
    class InstallPackage extends Task
    {
        protected $command = "DEBIAN_FRONTEND=noninteractive apt install @{:package} -qqy";
        protected $sudoRequired = true;
        protected $control = "apt\|dpkg";
    
        public function __construct(array $attributes = []){
            if(!isset($attributes["package"])){
                throw new \Exception("Package name is required");
            }
            $this->attributes = $attributes;
            $this->logFile = Formatter::run(
                "/tmp/install-package-{:package}.txt", 
                ["package" => $attributes["package"]]
            );
            $this->checkCommand = Formatter::run(
                "apt list --installed | grep {:package}", 
                ["package" => $attributes["package"]]
            );
        }
    }
    	public function installPackage()
    	{
    		validate([
    			'package_name' => 'required|string',
    		]);
    		return respond(
    			view('task', [
    				'tasks' => [
    					0 => [
    						'name' => 'InstallPackage',
    						'attributes' => [
    							'package' => request('package')
    						]
    					]
    				]
    			]),
    			200
    		);
    	}
    @component('modal-component',[
        "id" => "taskModal",
        "title" => "Görev İşleniyor",
    ])
    @endcomponent
        function installPackage(package_name){
            showSwal('{{__("Yükleniyor...")}}', 'info');
            let formData = new FormData();
            formData.append("package_name", package_name);
            request("{{API('install_package')}}", formData, function(response){
                $('#taskModal').find('.modal-body').html(JSON.parse(response).message);
                $('#taskModal').modal("show"); 
                Swal.close();
            }, function(response){
                let error = JSON.parse(response);
                showSwal(error.message, 'error', 2000);
            });
        }

    Geliştirme Ortamı Kurulumu

    Liman üzerinde eklenti geliştirme ortamının kurulumundan bahsedilecektir.

    hashtag
    Liman Kurulumu

    Eklenti geliştirebilmek için öncelikle Liman sunucusuna ihtiyacımız var 😁 Kurulum dokümantasyonuna adresinden ulaşabilir, adımları takip edebilirsiniz.

    hashtag

    Rotalar

    Eklentilerde rotaların görevi tam olarak nedir, ne yapar?

    hashtag
    Rota Nedir?

    Routing, request işlemlerinde kullanılabilecek, karmaşık kuralları kolaylıkla yönetebilme özelliği (GET, POST gibi HTTP methods, middleware gibi) ile öne çıkar. Routing işleminde işlemler route’lar (path) üzerinden yürütülür. Bu sayede URL eşleştirme işlemleri farklı amaçlarla gerçekleştirilebilmektedir. Bu işlem farklı bir şekilde ele alınsa da (client request) kullanıcılar/ziyaretçiler ve arama motorları URL’lerdeki gibi web sitesinde ve/veya uygulamasında anlamlı sonuçlara (endpoint) ulaşabilirler. Örneğin, /inbox/1/msg/2 gibi bir URL’de ilk path /inbox sonrası ise bu path’in iç yapıları olarak (routing tree) nitelendirilebilirler.

    Biz Liman içerisinde rota işlemlerine bu kadar karmaşık yaklaşmıyoruz. Gelin nasıl incelediğimize bakalım.

    hashtag
    Eklentilerde Rotalar

    Biz eklentilerde rotalara daha çok REST mantığıyla baktığımızdan ve kod karmaşıklığını düşürmek istediğimizden Laravel'deki gibi kodu uzatmamaktayız.

    Liman eklentilerinde rotalar sadece iki argüman alır.

    • Endpoint

    • Kontrolcü ismi @ Çağırılacak fonksiyon

    Gelin örnek bir rota dosyasını inceleyelim.

    Görüleceği üzere eklenti rotalarımız POST, GET, PUT, DELETE... gibi argümanlar almamaktadır. Eklentilerde kontrolcüleri API mantığı ile kullandığımız için ihtiyaç duymadık.

    Bir rota tanımlamak için aşağıdaki gibi bir tanımlama yapmanız gerekmektedir.

    Yukarıdaki tarzda tanımlama yaptığınızda bunu Javascript yardımcı fonksiyonlarımızdan request ile API("<ROTA_ISMI>") şeklinde çağırabilir. Bu çağrıdan sonra sorunsuz şekilde response alacaksınız ve bunu Javascript ile kullanarak ister bir içeriği manipüle edebilir, ister başka bir içerik oluşturabilirsiniz.

        "<ROTA_ISMI>" => "<CONTROLLER_ISMI>@<CAGIRILACAK_FONKSIYON>"
    PHP Yardımcı Fonksiyonlarıchevron-right
    routes.php
    return [
        "index" => "HomeController@index",
        
        // Hostname Settings
        "get_hostname" => "HostnameController@get",
        "set_hostname" => "HostnameController@set",
    
        // Systeminfo
        "get_system_info" => "SystemInfoController@get",
        "install_lshw" => "SystemInfoController@install",
    ];
    Linux Ayarları

    hashtag
    Kullanıcıya Şifre Eklemek

    Liman'ın işletim sisteminde kendine ait bir kullanıcısı olduğundan izin problemleri yaşamamak için sistem üzerindeki "liman" kullanıcısını kullanılabilir hale getirmeliyiz.

    hashtag
    Varsayılan Shell Değiştirmek

    Bu işlemin ardından liman kullanıcısını kullanabilmemiz için varsayılan shell ayarını bash olarak seçmeliyiz. Bu işlemi aşağıdaki komut ile gerçekleştirebiliriz

    hashtag
    Visual Studio Code Kurulumu

    Bu tercihimizin altında yatan sebep Remote SSH eklentisi bulunması sebebiyle direkt sunucu üzerinde geliştirme yapabilmemiz.

    https://code.visualstudio.com/arrow-up-right adresine giderek kurulumu gerçekleştiriyoruz. Kurulum işleminin ardından Remote SSH eklentisini kurmamız gerekmektedir.

    Remote SSH Eklentisi

    Resimdeki gibi eklentinin kurulumunu sağladıktan sonra ekranın sol alt köşesinde bağlantı butonumuz çıkacaktır. Ona tıklayarak SSH bağlantı menüsünü açıyoruz.

    SSH Bağlantı İkonu

    İkona tıklayıp menüyü açtıktan sonra aşağıdaki gibi bir görüntü bizi bekleyecek. Buradan "Connect to Host..." seçeneğini seçmemiz gerekmektedir.

    Connect to Host...

    Connect to Host seçeneğini çıktıktan sonra bizi bu tarz bir ekran karşılayacaktır. Bu ekranda "+ Add New SSH Host..." seçeneğini seçiyoruz.

    SSH Kullanıcıları

    Bu kısımda en önemli şey SSH bağlantı cümleciğimizi doğru şekilde girmemiz. Format olarak alttaki formatta cümleciği yazmaktayız.

    SSH Bağlantı Cümleciği

    Ardından gelen listede herhangi bir ayarı seçebilirsiniz. Bağlantı başarıyla eklendikten sonra tekrar "Connect to Host..." seçeneğini seçince eklediğimiz sunucu IP adresi ile görünecektir. Tıkladığımızda sunucu şifremizi soracaktır, girdikten sonra bağlantı başarılı olunca artık klasörümüzü açabiliriz.

    Klasör Açma Adımları

    Klasör açma adımları yukarıdaki resimde gösterilmiştir. Open Folder düğmesine tıklandıktan sonra kutucuğa /liman/extensions/ yazılır, ardından OK tıklandığında eklentilerin düzenlenebilmesi sağlanmaktadır.

    Bu adımdan sonra Yeni Eklenti Oluşturma işlemlerini takip edebilirsiniz.

    https://docs.liman.dev/kullanim-kilavuzu/liman-kurulumu/kurulumarrow-up-right
    Yeni Eklenti Oluşturmachevron-right

    Tablo

    Liman eklentileri üzerinde kolay bir biçimde tablo oluşturma yolu.

    hashtag
    Tablo componenti nedir?

    Tablo Componenti

    Tablo componenti, PHP ile gönderdiğiniz verilerin kolayca DataTables olarak oluşturulmasını sağlar. Ayrıca içerisinde birden çok özellik bulundurmaktadır.

    • Satıra tıklayınca bir işlem yapılması

    • Satıra sağ tıklayınca sağ klik menüsünün açılması

    • Sayfalama fonksiyonu

    • Arama fonksiyonu

    • Sütunlar içerisinde sıralama işlemi yaptırtmak

    hashtag
    Nasıl kullanılır?

    Liman içerisinde Blade Render Engine kullanıldığından viewları yukarıdaki şekilde sayfamıza dahil edebiliriz. Formatı anladıysak gelin birlikte değişkenlere bakalım.

    hashtag
    Value

    Value değişkeni yukarıdaki kod bloğunun yapısında olmalı, diğer veriler de sonradan bu hale getirilerek gönderilmelidir.

    Yapı olarak kendisi bir Array veri tipindedir. Liste içerisinde listelerden oluşmaktadır. Liste içerisindeki her bir liste bir satırı temsil etmektedir. Yukarıdaki örnek veri tipinde iki adet satırımız vardır ve çıktısı aşağıdaki gibi olacaktır.

    Eklenen her veride zorunlu olarak key değerleri aynı olmalıdır. Aksi halde tablo componenti başarılı şekilde renderlanamayacaktır.

    hashtag
    Display

    Display değişkeninde value arrayinde aldığımız listeden gösterilmesini istediğimiz keyleri yazmaktayız. Burada dikkat edilmesi gereken tek özel kullanım id:id kullanımıdır. Bu kullanımın sebebi ise gizli şekilde göstermek istediğimiz verilerdir. Title kısmında da bu özel kullanımın diğer adımını göreceğiz.

    Verileri gizli göstermek istememizin sebebi JavaScript ile yakalama imkanı oluşturmaktır. Örneğin sağ klik işlemine sil isimli bir fonksiyon tanımladığımızı düşünelim. Eğer ID değişkenini JavaScript tarafına gönderebilirsek kolayca request atarak silme işlemini tamamlayabiliriz.

    hashtag
    Title

    Title değişkeni display değişkeninde aldığımız keyleri görüntüsü güzel bir hale getirir. name yerine İsim yazmanızı sağlar. Burada dikkat edilmesi gereken en önemli kısım ise *hidden* kısmının display kısmındaki gizlemek istediğimiz key ile eşleşmesi, orada da keyin id:id formatında kullanılması gerekliliğidir.

    hashtag
    Onclick

    Tablodaki satıra tıklandığında çalıştırılacak JavaScript fonksiyonunu tanımlarız. Nasıl kullanıldığını anlamak için gelin beraber bir örnek inceleyelim.

    Yukarıda göreceğimiz üzere node argümanı bizim için o satırın JavaScript selectorunu döndürmektedir. Bu selectoru kullanarak ister ES6, ister jQuery ile kolayca işlerimizi halledebiliriz. Liman altyapısında jQuery bulunduğu için örnekte ben jQuery kullanmayı tercih ettim.

    hashtag
    Menu

    Sağ klik menüsü açabilmemiz için gereken veri türüdür. Bu veri türünü oluşturmak için isim, JavaScript fonksiyonu ve bir font awesome ikonuna ihtiyacımız var. Gelin örnek bir menü tanımlayalım.

    Yukarıdaki biçimi kullanarak örnek bir menü tanımlaması gerçekleştirebiliriz. En dikkat edilmesi gereken detay ise target kısmında bulunan eventlerin JavaScript ile tanımlanmasıdır. Bu tanımlamaları yapmazsak düzgün çalışmayacaktır. Gelin kullanıcı silmek için örnek bir tanımlama yapalım.

    Tanımladığımız fonksiyon aynı onclick fonksiyonundaki gibi bir argüman almaktadır. Node isimli selector ile kullanıcı adını yakalayarak Liman üzerinde hazır tanımlanmış Request fonksiyonuna veriyi ekliyor ve bu fonksiyon aracılığı ile POST olarak gönderimi yapıyorum. Dönen cevabı ise showSwal yardımcı fonksiyonum ile ekranda gösteriyorum.

    hashtag
    Requestten tablo çekmek

    Yukarıda göreceğimiz kod bloğunda bir dizin üzerinden dosya listesini çekip, parse işlemi yaptıktan sonra response olarak bir tablo viewi gönderdim. Bu tablo viewini de Javascript kullanarak bir HTML elemanının içeriğine yazdırmalıyım ki tablom görünsün. Gelin o işlemi de nasıl yapabileceğimizi inceleyelim.

    Bu fonksiyona çağrı atacağınız yeri sizin seçmeniz gerekmektedir, aynı zamanda tablonun çıkmasını istediğiniz yerde filesTable id değerine sahip bir de div oluşturmalısınız.

    hashtag
    Tabloyu dataTable yapmak

    Requestten aldığımız tablo HTML kodunu koyduğumuzda tabloda arama, sayfalama işlemleri yapılamamaktadır. Bunu çözmek JS yardımcı fonksiyonumuz olan dataTablePresets fonksiyonunu aşağıdaki gibi kullanabiliriz.

    sudo passwd liman
    sudo usermod --shell /bin/bash liman
    ssh liman@<SUNUCU_IP_ADRESINIZ>

    String

    menu

    Satıra sağ tıklandığında çıkacak içerik menüsü

    Array

    menu/target

    Sağ tık menüsünde tıklama yapıldığında çağırılacak fonksiyon

    String

    Veri

    Açıklama

    Veri Tipi

    value

    Tablonun içeriğini oluşturur

    Array

    title

    value verisinden alınan girdilerin viewda gösterilen halidir

    Array

    display

    value verisinden gösterilmesini istediğimiz keyler

    Array

    onclick

    JS Yardımcı Fonksiyonlarıchevron-right
    Örnek Value Değişkeni

    Satır üzerine tıklandığında çağırılacak JS fonksiyonu

    Dosya Yükleme

    Liman eklentileri üzerinde dosya yükleme formu oluşturmanın anlatımı.

    Dosya Yükleme

    hashtag
    Nasıl kullanılır?

    @include("file-input", [
        "title" => "Örnek File Input",
        "id" => "example-file",
        "callback" => "fileUploadEvent"            
    ])

    Parametre

    Açıklama

    title

    Dosya yükleme formunun başlığı.

    Detaylı kullanımı için aşağıdaki linke bakabilirsiniz.

    @include("table", [
        "value" => $exampleTableData,
        "display" => ["name", "surname", "email", "phone", "id:id"],
        "title" => ["İsim", "Soyisim", "Eposta", "Telefon", "*hidden*"],
        "onclick" => "rowOnClickEvent",
        "menu" => [
            "Example Right Click" => [
                "target" => "exampleRightClickEvent",
                "icon" => "fa-file-export"
            ],
        ]
    ])
    $exampleTableData = [
        [
            "id"      => "1",
            "name"    => "Havelsan",
            "surname" => "Aciklab",
            "email"   => "aciklab.org",
            "phone"   => "00000000"
        ],
        [
            "id"      => "2",
            "name"    => "Havelsan",
            "surname" => "Pardus",
            "email"   => "pardus.org",
            "phone"   => "00000000"
        ]
    ];
    "display" => ["name", "surname", "email", "phone", "id:id"]
    "title" => ["İsim", "Soyisim", "Eposta", "Telefon", "*hidden*"]
    function lineOnClickEvent(node) {
        // node satır için bize gönderilen JavaScript seçicisidir(selector)
        console.log(node)
    
        // satırımızdaki gizli olan id sütununun içeriğini almak
        console.log($(node).children("#id").html())
        
        // bu id ile örnek bir işlem gerçekleştirmek
        Swal.fire(`${$(node).children("#id").html()} idli elemente tıkladınız!`)
    }
    "menu" => [
        "Kopyala" => [
            "target" => "copyEvent",
            "icon" => "fa-copy"
        ],
        "Kes" => [
            "target" => "cutEvent",
            "icon" => "fa-cut"
        ],
        "Yapıştır" => [
            "target" => "pasteEvent",
            "icon" => "fa-paste"
        ],
    ]
    function deleteUser(node) {
        showSwal("{{__('Yükleniyor...')}}", 'info');
        let data = new FormData();
        data.append("username", $(node).find("#user").html());
        request("{{API('delete_user')}}", data, function(response){
            Swal.close();
            response = JSON.parse(response);
            showSwal(response.messsage, "success", 2500);
            getUsers();
        }, function(response){
            response = JSON.parse(response);
            showSwal(response.message, "error");
        });
    }
    public function list()
    {
        $command = Command::runSudo("ls -lah /home/liman");
        $files = explode("\n", $command);
        array_splice($files, 0, 1);
        
        foreach ($files as &$file) {
            $file = preg_replace('/\s+/', ' ', $file);
            $file = explode(" ", $file);
            $file = [
                "permissions" => $file[0],
                "user" => $file[2],
                "group" => $file[3],
                "size" => $file[4],
                "date" => $file[5] . " " . $file[6] . " " . $file[7],
                "name" => $file[8]
            ];
        }
        
        return view("table", [
            "value" => $files,
            "title" => ["İsim", "İzinler", "Sahip", "Grup", "Dosya Boyutu", "Son Değiştirilme"],
            "display" => ["name", "permissions", "user", "group", "size", "date"]
        ]);
    }
    function listFiles() {
        showSwal("{{__('Yükleniyor...')}}", 'info');
        let data = new FormData();
        request("{{API('list_files')}}", data, function(response){
            $("#filesTable").html(response).find("table").dataTable(dataTablePresets("normal"));
            Swal.close();
        }, function(response){
            response = JSON.parse(response);
            showSwal(response.message, 'error');
        });
    }
    $("#exTable").html(response).find("table").dataTable(dataTablePresets("normal"));

    id

    Request yönetimi yapılacak id değeri

    callback

    Yükleme işlemi yapıldığında yapılacak işlemlerin Javascript fonksiyonu (argüman olarak 1 argüman alır, veri o argümanda yakalanır)

    Dosya Yükleme, İndirmechevron-right

    Sunucuda Komut Çalıştırmak

    Eklentinizi eklediğiniz sunucu üzerinde nasıl komut çalıştırır ve çıktılarını nasıl alırsınız detaylıca bahsedeceğiz.

    hashtag
    Standart Komut Çalıştırmak ve Çıktı Almak

    Sistem üzerinde komut çalıştırabilmek için Liman Toolkit içerisinden Command classını kullanmaktayız. Limanda en çok kullanılan şey olduğu için ayrı bir başlıkta anlatma gereği duyduk. Gelin şimdi nasıl çalıştırırız bakalım.

    hashtag
    Toolkiti çağırmak

    Controller dosyamızı açtığımızda namespace satırının hemen altına bu komutu ekliyoruz. Bu sayede dosyamızda Liman Toolkitin Command classını kullanabilir hale geleceğiz.

    hashtag
    Komut çağırmak

    Yukarıdaki kodu çalıştırdığımızda bize sistem üzerinde hostnamekomutunu çalıştıracaktır. $command değişkenini respond yardımcı fonksiyonumuz ile kullanarak döndürdüğümüzde hostname bilgisini problemsiz şekilde elde edebiliriz. kısmındaki eklenti şablonunda bu kullanımların örneği mevcuttur.

    hashtag
    Sudo olarak komut çağırmak

    Aslında yukarıdaki kullanımın benzerini gerçekleştireceğiz. Sadece run komutu yerine runSudo şeklinde değiştirdiğimizde yetkili kullanıcı kullanılarak çalıştırılacaktır.

    hashtag
    Dış requestler ve escaping kullanımı

    Command classı üzerinde güvenlik için dış inputlara escaping kullanımı mevcuttur. Aynı zamanda validation yardımcı fonksiyonu da bulunduğundan dış komutlarda ister regexp, ister tür, isterseniz de uzunluk kontrolü yapabilirsiniz. Birlikte dış requestlerin kullanıldığı bir senaryoyu inceleyelim.

    hashtag
    Escaping kullanımı

    Yukarıdaki runSudo fonksiyonunun ilk argümanında göreceğimiz üzere @{:filename} tarzı bir kullanım mevcuttur. Bu kullanım escaping işlemi gerçekleştirmektedir. Escaping işleminin önem sebebi güvenliktir. Dışarıdan düşük yetkili bir kullanıcı sistemi yönetirken bu boşluğa ; rm -rf * şeklinde bir girdi gönderirse tüm klasör içeriği silinecektir. Burada escaping işlemi ile gönderim sağlarsak ; işareti işlevini kaybedecektir ve sistemimiz daha güvenli bir şekilde kullanıcı girdilerine açık hale gelecektir.

    run ve runSudo fonksiyonları normalde tek argümana ihtiyaç duymaktadır ancak escaping yapıldığında ikinci argüman olarak bir array gönderimi de yapmalıyız.

    Escaping yapabilmek için @{:degiskenAdi} şeklinde bir kullanım yapmalıyız. Burada degiskenAdi kısmı göndereceğiniz parametrelerin ismine göre değişmeli, ikinci argüman olan arrayinizde bu isimleri key olarak kullanmalısınız.

    hashtag
    Dış requestler

    Dış requestlerden girdi alabilmemiz için ilk önce escaping yapmamız gerekiyordu. Bu adımı gerçekleştirdikten sonra ikinci argüman olarak kullanılan arrayimizde gönderdiğimiz verinin ismini request() PHP yardımcı fonksiyonu ile alabiliriz. Aldıktan sonra yukarıdaki kod bloğunda görülebileceği üzere key olarak escape edilen değişken adını, değerine ise request fonksiyonumuzdan aldığımız değeri göndermekteyiz.

    Bu değerleri gönderebilmek için ise sayfamızda bulunan fonksiyonunun detaylarını inceleyip, siz de kendi sayfanızdan request gönderimi yapabilirsiniz.

    hashtag
    Fonksiyon Kullanım Parametreleri

    Parametre

    Açıklama

    Veri Tipi

    $command

    Karşı sunucuda çalıştırılması gereken komut.

    String

    $variables

    Eğer $command parametresi escape edilen kısımlar barındırıyorsa gönderilmesi gereken liste. (Opsiyonel)

    Array

    Eklenti şablonları
    OOP Training
    JS Yardımcı Fonksiyonları
    request
    PHP Yardımcı Fonksiyonlarıchevron-right
    JS Yardımcı Fonksiyonlarıchevron-right
    use Liman\Toolkit\Shell\Command;
    $command = Command::run("hostname");
    $command = Command::runSudo("cat /etc/network/interfaces");
    Command::runSudo("touch /home/liman/@{:filename}", [
        "filename" => request("filename")
    ]);

    Sunucuda Betik Çalıştırmak

    Sunucu üzerinde Python, Bash ve Powershell betiklerini çalıştırma yöntemleri.

    hashtag
    runScript fonksiyonu

    Sunucumuzda betik çalıştırmak için runScript yardımcı fonksiyonumuzu kullanmaktayız. Bu fonksiyon eklentinin eklendiği sistem üzerinde Python, Bash ve Powershell betiklerini çalıştırmamızı sağlamaktadır.

    hashtag
    Gerekli Ortamı Hazırlama

    runScript fonksiyonunun çalışabilmesi için eklenti dizininiz altında bir scripts klasörü oluşturmamız ve betikleri bu klasörün içerisine yüklememiz gerekmektedir.

    hashtag
    Kullanım Örneği

    runScript fonksiyonunu kullanabilmek için bir controller oluşturmamız gerekmektedir. Bu controlleri doğru şekilde oluşturup rota tanımlamasını doğru şekilde yaptığımızı varsayalım.

    hashtag
    Örnek Python Kullanımı

    Controllerda tanımlamalarımızı yapıp ardından JavaScript tarafında request yardımcı fonksiyonumuz ile çağrımızı yaptığımızda betik çıktımızı alabiliriz.

    Bu Python betiğini yukarıdaki şekilde controller kısmında çağırıp önyüz çağrısı sonucu şu tarz bir çıktı almaktayız.

    Bu örneği PHP 7.3 + OOP Training eklenti şablonunda bulabilirsiniz.

    Parametre

    Açıklama

    Veri Tipi

    Birinci Parametre

    scripts klasörü altındaki dosya adını alır

    String

    İkinci Parametre

    scripte göndereceğimiz argümanlar

    String

    Üçüncü Parametre

    sudo olarak mı çalıştırılmalıdır?

    Boolean

    Betiklerin Bulunduğu Klasör
    Betik Çıktısı
    public function run()
    {
        // runScript function
        // 1st parameter: filename under scripts folder STRING
        // 2nd parameter: parameters STRING
        // 3nd parameter: run as sudo BOOL
        $script = runScript("example.py", "", false);
        return respond($script, 200);
    }
    #!/usr/bin/python3
    print("Hello world!")