UBIT’de son gün

Bugün 9 Aralık 2013’ten beri çalıştığım UBIT’de son günümdü. İlk işe başladığım günden bugüne kadar istisnasız herkes bir abi, abla ve kardeş edasıyla davrandığı için teşekkür etmeliyim. Yaşça genç ve tecrübesiz olmama rağmen sunduğum her düşünceye sonuna kadar değer veren insanlarla çalışmak kendini geliştirmek isteyen birisi için altın madenidir diyebilirim. 3 seneye yakın bu süreç içinde olağanüstü dostluklar, yüz güldüren anılar biriktirdiğim için çok mutluyum.

Ofiste ilk tanıştığım ve her ortamda abi olarak gördüğüm, gezgin ruhuna hayran olduğum, hayatı karikatür formatında yaşayan yıllanmış blogger Hasan Civelek’e;

İlk günden son güne tüm şakalarıma katlanan, yeri geldiğinde dertleşen yeri geldiğinde eğlenen, öğrenme sürecimde bana her türlü desteğini sunan -öğrettikten sonra bütün işleri bana kitlese de- Mustafa Alkan’a;

Tüm espri ve güzel kişiliğiyle gerek ofiste gerek sosyal hayatta bana kardeş gibi davranan Burak Özdemir’e;

Benden daha önce işten ayrılmış olsa da dostluğu ve muhabbetiyle hem iş hem okul hayatımda yanımda olan Hüseyin Kabil’e

Teknik bilgisi, araştırmaları ve tavsiyeleriyle bilgime güç katan WP gurusu Mustafa Uysal’a

Tüm iftar, halısaha organizasyonlarının yapımcısı ve ofisin eli, kolu ve daimi sesi Ercan Aldoğan’a

Sahip olduğu girişimci ruhuyla örnek teşkil eden, langırttaki baş rakibim Melih Gengönül’e

Şirinevlere taşındıktan sonra yürüme yollarında bana eşlik eden, harbi Galatasaraylı ve harbi delikanlı Mustafa Dilaver’e

Son aylarda görev aldığım STOYS projesinin zorlu adaptasyon sürecinde zaman ve sabırlarını benden esirgemeyen Burcu Balta ve Onur Şahin’e

Bir yönetici olmanın yanında herkesin abisi olan ve her zaman derdimize çözüm arayan Yusuf Önder Us, Yahya Şahin ve Erhan Şen’e

UBİT’te , UBIT’in kurucusundan daha uzun süre çalışmayı başarabilmiş, her türlü cihaz arızalarına yetişen çok yönlü yazılımcı ve balık adam Hakan Akmehmet’e

Geç buldum erken kaybettim diye hayıflandığım kısa zamanda dostluğunu gösteren Kerem Tekin, Eser Topçu ve Cansu Cebeci’ye;

Yardıma ihtiyacım olduğunda hemen masamda beliren, yaşını hiçbir zaman göstermeyen, müziğiyle bize başka dünyalardan başka duygular getiren Turgut Karahan’a

Ofisin yabancı dil çıtasını tavana çıkaran istatistiksel verileri ve gerçekçiliğiyle ofisi aydınlatan Amazon danışmanımız Salih Emre Sert’e; ( Geldik gidiyoruz bizim VPN olayı hala havada :P)

Çalışma azimleri ile herkesi etkileyen ofisin sessiz kahramanları OIS ekibine;

Bütün ofis Call Of Duty oynarken sonuna kadar ‘German’ olup beni yalnız bırakmayan, enteresan bölgelerde pusu kurabilme yeteneğine sahip, espri anlayışı, kişiliği ve hakiki dostluğuyla unutulmaz anılar bırakan kibar(_1!) kardeşim namıdiğer ‘Şehzade’ Ömer Bakırcı ve onun azimli yancısı kardeşim ve adaşım kaçak iPhone’cu Uğurcan Elveren’e;

Varlıklarıyla STOYS’a renk bize gülümseme katan Osman Yavuz ve Pınar Ece Aktan’a;

Tüm ofise bir anne şefkati gösteren Hümeyra Yücel ve Dilek Pekel’e;

Herkese de birşey bulmuş, listenin sonu yok galiba diye düşünenler yüzünden daha ismini sayamadığım tüm çalışma arkadaşlarıma birlikte çalıştığımız süreç içerisinde bana kattıkları bu çok değerli tecrübe için defalarca teşekkür ederim.

UBIT Veda Pastası

IMG_20160826_154828

IMG_20160826_175006

Laravel’de imaj boyutlandırma

Web uygulamalarının bütününde, yüklenen imajların çeşitli boyutlarda saklanması bir gereklilik olmuştur. Eski yaklaşımlarda imajlar sunucuya yüklenirken, tasarıma göre, istenen boyutlara dönüştürülüp kaydediliyordu. Imajların değiştirilmesi söz konusu olduğunda, eski imajların temizlenmesi, yerine yenilerinin yerleştirilmesi gibi problemlerin yanında tasarım değiştiğinde eski imajların yeniden boyutlandırılması gibi problemler oluşuyordu. Ancak tahmin ettiğiniz gibi bu eski bir yaklaşım. Yeni yaklaşımlarda ise bir imaj talep edildiğinde, istenen boyuta o anda dönüştürülmekte. Bu durum ilk başta çok yorucu bir işlem gibi eski yaklaşımın bir çok eksikliğini kapatıyor. İşlemini yoruculuğu ise caching yöntemleriyle azaltılabiliyor. Dolayısıyla bu yaklaşımın çok daha iyi olduğunu söyleyebiliriz.

Popüler bir geliştirme ortamı olan Laravel için bu yeni yaklaşımla bir örnek gösterelim. Öncelikle bu yapılan işlemlerin tamamı burada bulunmakta ve kullanacağımız kütüphaneyi buradan inceleyebilirsiniz.

(daha&helliip;)

Bir “Controller” nasıl olmalı?

Bu günlerde web geliştirme çatılarının (framework) neredeyse tamamı MVC (Model-View-Controller) modellemesini kullanmakta, ancak son zamanlarda incelediğim web uygulamalarında controllerın amaçları dışında aşırı yüklendiğini görüyorum ve bu konuda uzman olan kişilerden gördüklerimi, kendi deneyimlerimi paylaşmak istiyorum.

Öncelikle MVC yapısının en temel kanunu kabaca MVC’yi oluşturan tüm bileşenlerin birbirinden bağımsız alanlarda olmasıdır. Bu bize bir View içerisinde database bağlantısı yapmamak, controller içerisinde string işlemleriyle HTML, JavaScript üretmemek gerektiğini söyler. Bunlar çok abartı örnekler olmasına rağmen hala MVC destekli çatılar altında böyle davranışlar söz konusu.

Bu abartı örnekleri bi kenara bırakıp, MVC mantığına daha uygun davranılan ama yine de controllerların aşırı şiştiği durumları düşünelim ve bir controllerın nasıl şekillenmesi gerektiğine biraz eğilelim. Öncelikle web uygulamalarında bir isteğin işlenmesi genel olarak aşağıdaki aşamaları içermekte;

  • Authentication
  • Authorization
  • Validation
  • Process
  • Response

Bu aşamaların üstüne örnek bir senaryo giydirmeye çalışalım ve bir okul sisteminde öğrenci kayıt yapan bir aksiyonu düşünelim. Burada istek alındığında yapılması gereken ilk şey, “authentication” yani isteği gönderen kişinin sistem tarafından tanınıp tanınmadığı olmalıdır. Yeni nesil çatılarda bu aşama genelde controller’ların üstünde ayrı bir katman olarak tutulur. Laravel Framework’u göz önüne aldığımızda genelde bu işi “Middleware” kullanarak hallederiz.

Kişinin kim olduğunu tespit ettikten sonra asıl olan o kişinin öğrenci kaydını yapıp yapamayacağını belirlemektir. Buna yetkilendirme (authorization) denir, aslına bakılırsa çok geniş bir konudur ve ayrıca incelenmesi gerekir. Yine Laravel Framework’den örnek verirsek, çoğu durumda yine Middleware kullanarak yetkilendirme işlemini çözebiliriz. Ancak ben burada bunu bir kenara bırakıp controller içerisinde yapmayı tercih edeceğim. Dolayısıyla öğrenci kayıdı alan aksiyonumuzun içerisinde yazacağımız ilk satırların yetkilendirme için olacağını söyleyebiliriz.

class StudentController extends BaseController {
    public function save(Request $request) {
        // Authorization
        if ($request->user()->cannot("add_new_student")){
            abort(403);
        }
    }
}

Daha sonraki işlem, bu öğrenci kaydının yapılabilmesi için gerekli parametrelere sahip olup olmadığımızın kontrolüdür. Bir sistemde doğru parametrelerin, doğru şekilde(!) gönderilip gönderilmediğinin kontrol edilmesi hem güvenlik hem de veri bütünlüğü açısından önemlidir ve bu işleme doğrulama (validation) denir.

class StudentController extends BaseController {

    public function save(Request $request) {
        // Authorization
        if ($request->user()->cannot("add_new_student")){
            abort(403);
        }

        // Validation
        $this->validate($request, [
            'name' => 'required',
            'surname' => 'required',
            'email' => 'required|email'
            ...
        ]);
    }

}

Bu aşamayıda geçtikten sonra artık istenen işlemi yapmanın vakti gelmiş demektir. Ancak ne yazık ki çoğu kişinin direkt olarak burada gerekli modelin fonksiyonlarını çağırarak veritabanına kayıt eklediğini görüyoruz. Ki işler bu safhada karışıyor diyebiliriz. Burada save() aksiyonu, her ne kadar ismi çok uygunsa da, öğrenciyi kaydetmekle yükümlü bir fonksiyon olmamalıdır. Büyük projelerde direkt modeli burada kullanmak pek akıllıca olmayacaktır. Burada araya “Repository” dediğimiz bir katmanı ekliyoruz. Repository kavramını daha iyi anlamak için buradaki paylaşımı kullanabilirsiniz.

class StudentController extends BaseController {
  
    public function save(Request $request, StudentRepository $studentRepository) {
        // Authorization
        if ($request->user()->cannot("add_new_student")){
            abort(403);
        }
        // Validation
        $this->validate($request, [
            'name' => 'required',
            'surname' => 'required',
            'email' => 'required|email'
            ...
        ]);

        // Process
        $student = $studentRepository->create($request->all());
    }

}

İşlemi gerçekleştirdikten sonra tabi ki kullanıcıya bir geri dönüş yapmak zorundayız. Buradaki dönüş tamamen geliştirdiğiniz sisteme özgü olmakla birlikte, bunun bir API olduğunu farz edersek, aşağıdaki gibi bir yöntem izleyebiliriz.

class StudentController extends BaseController {

    public function save(Request $request, StudentRepository $studentRepository) {
        // Authorization
        if ($request->user()->cannot("add_new_student")){
            abort(403);
        }
        // Validation
        $this->validate($request, [
            'name' => 'required',
            'surname' => 'required',
            'email' => 'required|email'
            ...
        ]);

        // Process
        $student = $studentRepository->create($request->all());

        // Response
        if (!$student) {
            return ['status'=> false,'error_code' => xxxx, 'error' => 'Error Message'];
        }

        return ['status' => true, 'data' => $student];
    }

}

Gördüğünüz gibi bir aksiyonun yazılması için 20 satır yeterli olabiliyor. Burada yaptığınız iş sadece öğrenci kaydetmek olmayabilir. Öğrencinin veli bilgilerini farklı bir yere, sınıf bilgilerini farklı bir yere yada daha bir çok bilgiyi farklı bir yere yazıyor olabilirsiniz. Yeni bir öğrenci geldiğinde arama sistemine bir istekte bulunuyor, öğrenciye ayrıca bir sistemden mail adresi açıyor veya daha bir çok şey yapıyor olabilirsiniz. Ancak bunların hiçbiri controllerımın basit bir save fonksiyonunu ilgilendirmiyor. Bırakın bunlarla “Repository”,”Event” gibi bileşenler ilgilensin.

Keep it simple, stupid

Csv2Arff

Bir süredir üniversite çatısı altında ağı izleyip makine öğrenmesi yöntemleri kullanarak saldırıları tespit etmeyi hedefleyen bir proje üzerinde çalışıyorum ve şu an proje kapsamında ihtiyaç duyduğum ve haftasonu hazırladığım ufak bir dönüştürücüyü paylaşmak istiyorum.

Elbette makine öğrenmesi yöntemleri deyince akla ilk gelen program Weka (bkz) dosya formatı ise arff(bkz) oluyor. Ancak biz projeye başladığımızda tüm verilerimizi CSV(bkz) formatında saklamıştık. Bu verileri Weka’ya aktarmak istediğimizde Weka’nın kendi dönüştürücüsü işimizi görüyordu. Ancak tüm yaptıklarımızı bir paket haline getirmek istediğimizde komut satırı üzerinde çalışan bir dönüştürücüye ihtiyaç duyduk. Dolayısıyla Weka’nın arayüz üzerindeki çalışma prensibini takip edip kendi dönüştürücümü python kullanarak hazırladım. Konuyla ilgilenen arkadaşların ihtiyacı olursa buradan ulaşabilirler.

Yaşanmış bir yıla son not

Uzun süredir yazmadığımı göz önünde bulundurunca, yeni yılı bahane edip, hayatımdaki köklü değişikliklere şahit olan 2015 yılına son bir not düşmek istedim.

Bu yılda yaşadığım en köklü değişiklik , doğup büyüdüğüm yer olan Soğanlık/Kartal’dan Şirinevler’e zorunlu olarak taşınmamdı. Her gün Esenler-Kartal arasında İstanbul şartları altında gidip gelmekte kurtulmak hoş olsa da aile sıcaklığını ve doğup büyüdüğünüz semti bırakmak oldukça zor. İnsan kendini yerçekiminin daha az olduğu bir dünyaya alışmaya çalışırken buluyor. Tutunmak kolay olmuyor. Bkz. Tutunamayanlar

Söylemeliyim ki öğrenci evine çıkmak farklı bir duygu. 21 sene ailenizle birlikte yaşadıktan sonra bazı sorumluluklarınızın farkına varıyorsunuz. Öyle kapı arkasına attığınız çorapları kaldıran birileri olmuyor mesela ya da mucizevi bir şekilde çamaşırları yıkanmış, ütülenerek dolabınıza gelmiş bir şekilde bulamıyorsunuz. Eskiden kendimi sorumlu bir insan olarak görürdüm, ancak şimdi sorumsuzluğumla anneme bazı haksızlıklıklar ettiğimi düşünüyorum.

Ayrıca bahsedilmesi gereken bir durum ise, bir günde İstanbul metrolarında geçirdiğim sürenin 3 saat 20 dakikadan ortalama 20 dakikaya düşmesi. Bunun neticesinde kendime daha fazla zaman ayırabildiğimi sanmayın. Eskiden haftada en az 1 saat klarnet çalmaya vakit ayırırdım, 2 günde birde olsa elime bir roman alırdım, 2 günde bir kız arkadaşımın yanına veya eski dostlarımın yanına giderdim, her akşam mutlaka bloglarda veya Hacker News’de takılırdım yada mesleki yazılar okurdum. Şimdi ise tüm sosyal hayatımı hafta sonuna sığdırmaya çalışıyorum. Not: Sanırım YTÜ Bilgisayar Mühendisliği 3. Sınıf öğrencilerinin çoğu böyle hissediyor.

Tabi ki tüm bunları 2015 yılını çok kötü geçirdim gibisinden duygularla yazmıyorum. Aksine ‘Ula 2015 ne ara bitti’ duygusuyla yazıyorum. Öz abim olarak gördüğüm Erhan Nasıroğlu, bir gün “Uğur 20 yaştan sonrası çok hızlı geçiyor” demişti, haklıymış.

Tüm bu süreç içerisinde iş hayatımda önemli ilerlemeler olduğunu söyleyebilirim. Artık mesleki bakışımın daha geniş olduğunu ve bazı boşlukları doldurabildiğimi söyleyebilirim. Ayrıca öğrenci evinde bulunmanın getirdiği güzel dostlukları da yabana atmamak gerekir.

Gerçekten çok yoğun olduğum ve zaman zaman çok zorlandığım bu dönemde bana en çok yardım eden, yükümü hafifleten, hatta bu dönemi atlatmamı sağlayan en önemli kişi kız arkadaşımdır. Hayatımda köklü değişikliklerin olduğu bu dönemde, bazı şeylerin değişmeyeceğini özellikle 2015 yılı olmak üzere son 6 yılda bana her fırsatta sabırla öğrettiği için ona teşekkür ederim. İyi ki varsın.

2016 yılında gerek sosyal hayatım başta gelmek üzere herkesin olduğu gibi benim de planlarım var.
Her yeni yıla girerken söylediğimi bu yıl ve beklentilerim içinde söylüyorum.

“Hayırlısı”.

Django projenizi VPS üzerine deploy edin!

Django’nun en güzel özelliklerinden biri şüphesiz development servera sahip olması. Şahsen iş yerinde PHP kullanan biri olarak , geliştirme ortamınızı ayarlamak zorundasınız. Örneğin bir apache server ya da bir nginx server kurulumunu yapmak , gerekli PHP paketlerini yüklemek zorundasınız. Django’da ise , django kurulduktan sonra tek bir satır kod ile projeyi servis etme şansınız var.

Ancak bu durum tabi ki geliştirme süreci için geçerli. Projenizi yayına almak istediğiniz zaman elimizi biraz taşın altına sokuyoruz.

Başlamadan evvel sahip olmanız gereken şeyler ;

  • 1-VPS.
    Ben bunun için digitalocean ‘dan açtığım makineyi kullanıyorum. Fiyatı öğrenci arkadaşlar için uygundur.
  • 2-Domain
    Aslında domain sahibi olmasanız da olur , makinenizin ip adresini kullanarak da sonuçları görebilirsiniz. Ancak domain sahibiyseniz, DNS ayarlarınızın doğru olduğundan emin olun.

Bunların dışında kurulum sırasında gunicorn, supervisor, nginx ve virtualenv araçlarını kullanacağım. Ayrıca veritabanı postgresql kullanacağım. Her birini arama motorlarında aratarak kullanımlarını öğrenebilirsiniz. Ben bizim için gerekli olan kısımları açıklayacağım.

Başlamadan evvel aşağıdaki komutlarla depoları güncellemekte fayda var.

$ sudo apt-get update
$ sudo apt-get upgrade

Bu işlemden sonra postgresql’in kurulumunu yapalım.

$ sudo apt-get install postgresql postgresql-contrib

Kurulumdan sonra yeni bir kullanıcı ve veritabanı oluşturalım.

 

$ sudo su - postgres
postgres@MyDroplet:~$ createuser --interactive -P
Enter name of role to add:   django_db_user
Enter password for new role:
Enter it again:

Bu işlemden sonra size sorulan soruların tamamına hayır (n) diyebilirsiniz. Daha sonra ise yeni bir veritabanı oluşturalım.

 

postgres@MyDroplet:~$ createdb --owner django_db_user hello_django
postgres@MyDroplet:~$ logout

Bu durumda veritabanımızın kullanıcısı django_db_user , veritabanımız ise hello_django olarak ayarlanıyor.

Bu işlemden sonra virtualenv ortamını ayarlayalım. Virtualenv makine üzerine kuracağınız paketleri sanal bir ortama kurmak için kullanılır. Örnek vermek gerekirse elinizde 2 farklı Django ile yazılmış bir web projesi olduğunu ve bunların farklı sürümlerde çalıştığını hayal edin. Bu durumda iki adet virtualenv oluşturup her birine gereken sürümü yükleyebilir birbiriyle çakışmadan çalışmasını sağlayabilirsiniz.

$ sudo apt-get install python-virtualenv

Virtualenv kurduktan sonra bir tane oluşturmak için ;

$ sudo virtualenv /opt/myenv

Bu komut /opt/myenv dizinine bir virtualenv oluşturacaktır. Dediğimiz gibi makineye kuracağınız paketleri bu virtualenv ortamına kurmanız gerek. Dolayısıyla önce virtualenv ortamına geçiş yapmalısınız.
Bunun için ;

$ source /opt/myenv/bin/activate

Komutunu kullanmalısınız. Bu ortamdan çıkış yapmak için ise ;

$ deactivate

komutu yeterli olacaktır.

Virtualenv ortamına geçiş yaptıktan sonra,

$ pip install django

komutu ile django kurulumunu gerçekleştirebilirsiniz.

Bu işlemden sonra virtualenv ortamından çıkıp. Nginx kurulumunu gerçekleştirebiliriz.

$ sudo apt-get install nginx

komutu bu konuda problemlerinizi tamamıyla çözecektir.

Parçaları ayrı ayrı kurmamıza aldırmayın, birazdan bütün bu parçaları bir araya getireceğiz.
Nginx web projenizi servis etmeniz için bir konteynır biz nginx ile django projesini konuşturmak için arada gunicorn dediğimiz yazılımı kullanacağız.

Bu sebeple virtualenv ortamına geçip, gunicorn kurulumunu yapmalıyız.

$ pip install gunicorn

komutu ile gunicorn kurulumunu gerçekleştirelim.

Aslında gunicorn ile tek başına django projesini servis edebiliriz. Ancak ortada bir django projesi yok!
Öncelikle bir django projesi oluşturalım ve veritabanı bağlantısı için gerekli ayarları düzenleyelim. Tabi ki virtualenv ortamındayken – çünkü djangoyu bu virtualenv ortamında kurduk, bu ortam dışında django-admin.py’yi çalıştırmak isterseniz hata alırsınız –

$ cd /opt/myenv
$ django-admin.py startproject hello_django

 

komutları ile projemizi /opt/myenv dizini altına hello_django ismiyle oluşturalım.

Postgresql kurulumunu yaptık ancak python’un postgresql ile anlaşabilmesi için psycopg2 isimli bir kütüphaneye ihtiyacı var. Bu kütüphaneyi kurmak için de;

$ pip install psycopg2

komutunu yazıyoruz. Şimdi projenin içinde (/opt/myenv/hello_django/hello_django/) settings.py dosyasını düzenleyip veritabanı bağlantısını gerçekleştirelim.

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'hello_django',
'USER': 'django_db_user',
'PASSWORD': '********',
'HOST': 'localhost',
'PORT': '',
}

Yukardaki ayarları yaptıktan sonra tablolarımızı ilklendirebiliriz.Bunlar django ile ilgili olduğu için pek üstünde durmaya gerek yok.
$ cd /opt/myenv/hello_django
$ python manage.py syncdb

Şu ana kadar birşeyi atlamadıysanız veya bir kurulumda hata almadıysanız tablolarınız daha önceden açtığımız veritabanında işlenmiş olmalı. Postgresql dökümantasyonlarına bakarak gerekli kontrolleri yapabilirsiniz.

Söylediğim gibi aslında gunicorn ile projeyi tek başına servis edebilirsiniz. Gelin isterseniz gunicorn ile bir test yapalım.
$ cd /opt/myenv/hello_django
$ gunicorn hello_django.wsgi --bind 0.0.0.0:8000 --worker 3

komutlarıyla projenizi tıpkı

$ python manage.py runserver

der gibi servis edebilirsiniz. Şimdi makinenin ip’sini kullanarak(xxx.xxx.xx.xxx:8000 gibi) tarayıcıdan erişmeye çalışırsanız, karşınıza bir web sayfasının çıktığını görebilirsiniz. Static dosyalar görünmüyorsa , şimdilik kafanıza takmanıza gerek yok.

Ancak fark ettiyseniz projeyi gunicorn ile servis ederken bind veya worker gibi belli parametreler kullandık. Bu parametreleri komut satırı üzerinden vermek yerine bir python dosyasına yazarak verebiliriz.

Gelin bir konfigurasyon dosyası oluşturalım ve projeyi başlatmak istediğimizde hep bunu kullanalım.

$ cd /opt/myenv
$ sudo vi hello_django_gunicorn_cfg.py

command = ‘/opt/myenv/bin/gunicorn’
pythonpath = ‘/opt/myenv/hello_django’
bind = ‘127.0.0.1:8001’
workers = 3
user = nobody

Burda user yerine nobody değeri geçildi, burada user parametresi geçmeyebilirsiniz. Ancak sağlıklı bir web uygulamasının unix kullanıcısı ayrı ve hakları kısıtlıdır. Bu güvenlik açısından önemli bir noktadır. Dolayısıyla unix üzerinde bir servis kullanıcısı açmanızı , projenin dosya haklarını bu kullanıcıya vermenizi, gunicorn config dosyasına ise bu kullanıcının adını yazmanızı tavsiye ederim.

Ufak bir tüyo ile linux üzerinde şu komutla bir kullanıcı açabilirsiniz.

useradd --system --bash /bin/bash --home-dir /opt/myenv/hello_django hello_django_unix_user

Hatta daha sağlıklısı web uygulamalarının kullanıcılarını bir gruba atamak, örneğin webapps isminde bir gruba bu kullanıcıları dahil edebilir, gerekli unix yönetimini sağlayabilirsiniz. Ancak olayı şimdilik karıştırmaya gerek yok.

Üstteki işlemi yaptıysanız hello_django_unix_user ismindeki kullanıcıyı config dosyasına yazabilirsiniz.

Artık config dosyasını kullanarak projeyi başlatabilirsiniz.

Virtualenv aktif haldeyken,
$ gunicorn -c /opt/myenv/hello_django_gunicorn_cfg.py hello_django.wsgi

komutu ile daha demin yaptığımız işlemi yapabiliriz. Bind ettiğimiz nokta farklı bir nokta olduğu için tarayıcıdan erişmeniz mümkün olmayabilir. Ancak bu ayarların yanına nginx i kattığımızda gunicorn kendi içinde 8001 portunda çalışan bir sunucu gibi olacak, nginx ise ön planda durup gelen istekleri gerekiyorsa gunicorna gönderecek. Statik olan dosyaları ise nginx ile servis edeceğiz.

Nginx ayarlarını yapmadan önce statik dosyalar ile ilgili sorunlarımızı çözelim. Djangonun bu yönde güzel bir yanı var, kullandığınız bütün statik dosyaları tek bir noktaya toplayabiliyorsunuz. Bir django projesi oluşturduğunuzda admin paneli ile ilgili sayfaların dosyaları proje dosyaları içinde yer almaz, dolayısıyla projeyi taşıma esnasında sorunlar doğabilir. Bu nedenle django statik dosyaları tek bir noktaya taşımak için belirli yapılar geliştirmiş.

Öncelikle statik dosyaların nerede toplanacağını djangoya söylememiz gerekiyor. Bunun için settings.py dosyasına aşağıdaki tanımlamayı yapmalıyız.

STATIC_ROOT = '/opt/myenv/hello_django_static'

Dikkat ettiyseniz virtualenv içerisinde ama proje dosyalarının dışında bir nokta seçtim. Bu iyi bir çözümdür. Virtualenv içerisine koyarsanız başka projelerle karışmaz, proje klasoru dışarısına koyarsanız hem güvenlidir, hemde versiyon kontrol sistemlerini ignore etmekle uğraştırmazsınız. Bu tanımlamayı yaptıktan sonra;

$ cd /opt/myenv/hello_django
$ python manage.py collectstatic

komutu ile statik dosyalarınızı toparlayabilirsiniz. Bu işlemi yaptıktan sonra artık nginx ayarlarını yapmaya hazırız.

$ sudo vi /etc/nginx/sites-available/hello_django

server {
  server_name domain.com;

  location /static/ {
    alias /opt/myenv/hello_django_static;
  }

  location / {
    proxy_pass http://127.0.0.1:8001
    proxy_set_header X-Forwarded-Host $server_name;
    proxy_set_header X-Real-IP $remote_addr;
    add_header P3P ‘CP=”ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV”‘;
  }
}

$ cd /etc/nginx/sites-enabled
$ sudo ln -s ../sites-available/hello_django
$ sudo service nginx restart

Bu işlemlerden sonra

$ cd /opt/myenv/
$ gunicorn -c hello_django_gunicorn_cfg.py hello_django.wsgi

Diyerek gunicornu aktif ediyoruz ve domainimize girmeye çalışıyoruz. Bu aşamadan sonra projenizi düzgün bir şekilde görüyor olmalısınız. Ancak bir sorun var, tüm bunları runserver gibi bir komut çalıştırmadan otomatik olarak yapmak istiyorduk. Araya bir sürü yazılım soktuk ama bir adım ileri gidemedik gibi duruyor. Yapmamız gereken son iş elle yaptığımız bu tetikleme işlemini supervisor diye isimlendirilen bir yazılıma teslim etmek. Bu yazılım sayesinde kendi yazdığınız scriptleri arka planda, otomatik olarak çalıştırabilirsiniz. Bu programı kurmak için virtualenv dışında,

$ sudo apt-get install supervisor

komutunu kullanabilirsiniz. Uzun bir konfigürasyondan sonra son olarak supervisor ayarlarını da yapalım. Supervisor ayar dosyalarını /etc/supervisor/conf.d dizininde saklıyor. Dolayısıyla yapmamız gereken ;

$ cd /etc/supervisor/conf.d
$ sudo vi hello_django.conf

[program:hello_django]
command=/opt/myenv/bin/gunicorn -c /opt/myenv/hello_django_gunicorn_cfg.py hello_django.wsgi
autostart=true
autorestart=true
stderr_logfile=/var/log/long.err.log
stdout_logfile=/var/log/long.out.log

Gördüğünüz gibi elle yazdığımız komudu command parametresinin değeri olarak yapıyoruz.Daha sonra supervisoru güncellemeliyiz.
$ supervisorctl reread
$ supervisorctl update

komutlarıyla çalıştırmaya başlayabiliriz. Restart atmak için ise;
$ sudo service supervisor restart

Dikkat etmeniz gereken bir nokta ise deploy aldığınız zaman statik dosyaları güncellemeyi unutmamak ve supervisor’ı da yenilemeniz atmanız olacaktır.

Django’da lokalizasyon

Arkadaşlar merhaba,

Bugün Django’da lokalizasyon işlemlerini nasıl yaparsınız aşama aşama söylemek istiyorum.  Django bizim için neredeyse tüm dil ve lokalizasyon işlemlerini düşünmüş. Tek yapmamız gereken biraz konfigürasyon. Django ile yaptığım bir uygulamaya dil desteği eklemek istediğimde , ilk başta ayarları tam oturtmak ve bunu anlamak zor olmuştu. Dökümantasyonda kaçırdığım bir kaç nokta yüzünden biraz süre kaybettim diyebilirim. O yüzden aşama aşama neler yapılması gerektiğini buraya yazmak istedim.

(daha&helliip;)

“Nereden Başlamalısın?” Karmaşası

Üniversite derslerim ve iş yoğunluğu nedeniyle uzun süredir yazamasam da , sürekli olarak başka yazıları takip ediyordum. Bu sıralar vakit bulunca , neredeyse her yerde karşılaştığım “Nereden Başlamalıyım?” başlığına bir bakış açısı da ben kazandırmak isterim.

Kendi çevreme bakarak söyleyebilirim ki , üniversitelerin herhangi bir bölümünü kazanan bir öğrenci nereye yöneleceğini , vaktini nasıl değerlendirmesi gerektiğini gerçekten bilmiyor. İnsanlar büyük bir hevesle yazdığı bölümde ders görmeye başlayınca , özellikle mühendislik öğrencileri temel mühendislik derslerini alırken , bu hevesin yerinde yeller esiyor. Çevremdeki çoğu insan defalarca , “Ne yapacağız ki?” , “Henüz birinci sınıfız ne yapabiliriz ki?” diye sorular sormaktan kendini alamıyor.

Şu anki durumunuzun betimlemesini yaptıysak eğer , madde madde sizin için verimli bir sene geçirmenin yollarından bahsedelim.

(daha&helliip;)

jQuery’den AngularJS’e

Bundan 9-10 sene evvel jQuery ile büyük bir sıçrama yaşayan web dünyası , sanırım AngularJS ile de benzer bir sıçrama yaşayacak. Biliyorsunuz , jQuery , JavaScript ile yazılmış  ve DOM Manipülasyonunda vazgeçilmez bir kütüphane halini almıştı. Öncesinde saf JavaScript ile yapılan işlemler oldukça kısalmış ve yazılımcılara büyük kolaylık sağlanmıştı. jQuery hala yazılım geliştiriciler tarafından sürekli kullanılan bir kütüphane. Dün gece daha önce defalarca duyduğum AngularJS’ye bakma fırsatım oldu. Sonuç: Hayretler içerisindeyim.

Web uygulamalarına baktığımızda bugün hemen hemen her uygulama MVC modeline dayanarak üretiliyor. Bu model farklı işlerin birbirinden ayrılması mantığına dayanarak , yazılımcıların bir arada çalışmasını kolaylaştırıyor. İşte aynı modelin kullanıcı kısmında da vücut bulmuş hali AngularJS.

JavaScript ile yazılmış , ve bir anlamda MVC modellemesini benimsemiş bir kütüphane. Bir kaç araştırma ile gördüm ki geliştiriciye sağladığı kolaylıklardan test unitlere ve dökümantasyonlarına kadar profesyonelce hazırlanmış. Çok fazla met ettik , tabi ki bende yeni yeni araştırmaya başlıyorum burada sizlere extreme örnekler sunamam.  Önce şu , jQuery ile AngularJS arasındaki farklardan ufacık bir kısmını gösteren videoyu göstermek isterim.

 

 

Etkileyici öyle değil mi ?

MVC modellemesinden söz etmiştik , tabi videodaki tam olarak bu değil. Gelin bunu bir tık öteye taşıyalım.

Aslında AngularJS.org a baktığınızda , sizden çalışmalara başlamadan önce bir http server kurmanızı istiyor. Ama yapacağımız bu örnek için buna ihtiyacımız yok.
Buraya tıklayarak önce angularjs kütüphanesini indirelim. Daha sonra bunu html dosyamıza import edelim.

<!doctype html>
<html>
<head>
    <meta charset="utf8">
    <script type="text/javascript" src="lib/angular/angular.min.js"></script>
</head>
    <body>
       <h1>Öğrenciler</h1>
        Search : <input type="search">
        <ul>
            <li>Uğur</li>
            <li>Buğra</li>
            <li>Burak</li>
            <li>Zeliha</li>
        </ul>
        <p>Toplam öğrenci sayısı: 4</p>
    </body>
</html>

Gördüğünüz gibi burada sadece saf html kullandık. Şimdi buna AngularJS’in getirdiklerini ekliyoruz.

<!doctype html>
<html ng-app="firstApp">
<head>
	<meta charset="utf8">
    <script type="text/javascript" src="lib/angular/angular.min.js"></script>
    <script type="text/javascript" src="js/index.js"></script>
</head>
    <body ng-controller="firstCtrl">
       <h1>{{baslik}}</h1>
        Search : <input type="search" ng-model="query">
        <ul>
            <li ng-repeat="ogrenci in ogrenciler| filter:query">
                {{ogrenci.name}}
            </li>
        </ul>
        <p>Toplam Öğrenci sayısı: {{ogrenciler.length}}</p>
    </body>
</html>

Alışkın olduğumuz html dünyasına aykırı bir sürü saçmalık ekledik sanırım. Şimdi bu saçmalıklara index.js ile bir anlam kazandıralım.

 var firstApp = angular.module('firstApp',[]);



firstApp.controller('firstCtrl',function($scope){
    $scope.ogrenciler=[
        {'name':'Uğur'},
        {'name':'Buğra'},
        {'name':'Burak'},
        {'name':'Zeliha'}
    ];
    $scope.baslik = 'Öğrenciler';
});

İşte bu kadar. Gördüğünüz gibi html’den ayrı bir javascript dosyam var. Bunun içerisinde controller nesnemi yaratıyorum. Ve elementlerimi yerleştiriyorum. Yeni yeni öğrenmeye başladığım bu AngularJS hakkında , daha bir çok şey yazacağım sanırım.

Python Soket Programlama

Arkadaşlar bugün Python ile farklı bir alana değinmek istiyorum. Python çok yönlü bir dil ve biz Python ile soket programlama da yapabiliyoruz. Nedir soket programlama , en basit tabirle network programlamadır arkadaşlar , iki sistem arasında haberleşme, veri alışverişi kontrollerini programlama dersek çok yanlış olmaz.

En temel olarak bir server betiği , bir de client betiği yazarak başlayacağız . Pythonda soket programlama yapmak için gerekli kütüphanemiz , “socket”.

İlk olarak server betiğini yazmakla başlayalım. Bunu en basit olarak web serverlarını düşünebilirsiniz arkadaşlar. Tarayıcınızı açtınız , http://www.google.com yazdınız. Sunucu otomatik olarak sizi sitemizin dosyalarının oldugu makineye yönlendiriyor. Tabi ki tam olarak böyle değil ama ben sadece kafanızda bir şablon oluşması için şekillendirmek için böyle söylüyorum. Şimdi bu yönlendiğimiz makine aslında bizi kapıda bekliyor. Siz linke tıkladığınız anda sizi içeri davet ediyor. İşte ilk olarak biz kapıda bekleyen o programı yazmaya çalışacağız.

Tabi ki ilk olarak “socket” kütüphanesini import edeceğiz.

import socket

Python’da socket programlamaya başlamak için bir socket nesnesine ihtiyacınız vardır arkadaşlar. Hemen bunu nasıl oluşturacağımızı görelim.

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

Şimdi karmaşık gibi geliyor olabilir. Hani dedik ya bizi kapıda bekleyen biri var. O sizi görür görmez içeriye almayacaktır tabi ki , arada belli protokoller olmak zorunda. Burada argüman olarak verdiğimiz AF_INET , SOCK_STREAM gibi ifadeler aslında bu protokollerdir arkadaşlar. Bağlantımız sırasında hangi protokolü kullanacağımızı burada belirliyoruz. Bunları internette araştırarak daha ayrıntılı bilgi alabilirsiniz. Şu an konuyu çok saptırmadan devam etmeye çalışıyorum. Şimdi bir nesneye sahibiz. Bu nesne ile server oluşturacağız.

Server oluşturmak için bir makineye ihtiyacımız var , biz bu makineyi “localhost” , yani betiği yazmış olduğumuz makine olarak seçelim. Şimdi misafiri için evimiz var ama kapımız yok , kapımız ise portumuz olacak arkadaşlar. Herhangi bir port numarası uydurabilirsiniz , ancak 4 haneli rakam seçmeniz , sık kullanılan port numaralarıyla karışmaması açısından daha elverişli olacaktır. Makineyi localhost , port numarasını ise 8000 olarak seçtim ben.

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000

Hala bunun bir servera benzer tarafı yok , client da yazıcak olsak aynı şekilde başlayacaktık. Gelin bunu bir server haline getirelim artık. Bir makine ve o makine de bir port oluşturmak için “bind” methodu kullanılır arkadaşlar.

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000
soket.bind((HOST,PORT))
print “%s:%d server başlatıldı.” % (HOST,PORT)

Burada lütfen parantezlere dikkat edin arkadaşlar. Şimdi bind methodu ile bir makine oluşturduk ve bir port açtık. Sıra geldi misafir beklemeye. Bunun içinde listen methodunu kullanıyoruz arkadaşlar.

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000
soket.bind((HOST,PORT))
print “%s:%d server başlatıldı.” % (HOST,PORT)
print “Kullanıcı bekleniyor.”
soket.listen(1)

Burada listen içerisine verilen argüman , kaç tane misafirin kuyrukta bekleyeceğini belirliyor diyebiliriz. Şimdilik tek misafir için çalıştığımızdan bunu 1 olarak yazdım ben. Ayrıca programı bu şekilde çalıştırdığınızda program listen methodunu gördüğü anda beklemeye başlıcaktır arkadaşlar. Tıpkı input() methodunu yazdığınızda klavyeden entera basmanızı beklediği gibi. Bunun anlamı serverın kullanıcıyı içeriye almaya hazır olduğudur. Diyelim ki bir misafir geldi kapımızı çaldı. Şimdi bağlantıyı kabul edip , misafiri tanımlamalıyız.

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000
soket.bind((HOST,PORT))
print “%s:%d server başlatıldı.” % (HOST,PORT)
print “Kullanıcı bekleniyor.”
soket.listen(1)
baglanti,adres = soket.accept()
print “Bir bağlantı kabul edildi.”,adres

Evet şimdi accept methodu çıktı karşımıza. Şimdiye kadar kullandığımız bütün methodlar zaten ingilizce ,accept ise burada onaylamak anlamında ve gerçekten ne işe yaradığını ele verir nitelikte. Şimdi accept methodu bir tüp döndürür arkadaşlar. Bu tüpün birinci elemanı bağlantı nesnesini – daha sonra veri alışverişi yapmamızı sağlayan nesne- , ikinci eleman ise , kapımıza gelen misafirin kim olduğunu saklar.
Bağlantıyı aldık madem, eve gelen misafire ilk söylenen şey nedir ?
“Hoşgeldiniz efendim , hoşgeldiniz.”

Hemen söyleyelim.

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000
soket.bind((HOST,PORT))
print “%s:%d server başlatıldı.” % (HOST,PORT)
print “Kullanıcı bekleniyor.”
soket.listen(1)
baglanti,adres = soket.accept()
print “Bir bağlantı kabul edildi.”,adres
baglanti.send(“Hoşgeldiniz efendim , hoşgeldiniz.”)

Artık burada send methodunun ne işe yaradığını söylemek ayıp olur diye düşünüyorum. Herşey basit değil mi ?

Şimdi biz hoşgeldiniz dediysek , onlarda bir cevap verecektir. Verdikleri cevabı almamızı sağlayan method ise , recv() methodu. Hemen görelim.

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000
soket.bind((HOST,PORT))
print “%s:%d server başlatıldı.” % (HOST,PORT)
print “Kullanıcı bekleniyor.”
soket.listen(1)
baglanti,adres = soket.accept()
print “Bir bağlantı kabul edildi.”, adres
baglanti.send(“Hoşgeldiniz efendim , hoşgeldiniz.”)
data = baglanti.recv(1024)
print data

Burada recv methoduna verdiğimiz 1024 argümanı , veri büyüklükleriyle ilgili bir durumdur. Şimdilik kafanıza takmanıza gerek yok. Bu konuda daha ileri seviye programlar yazmak isterseniz araştırabilirsiniz.

Şimdi misafir geldi , ağırladık ettik derken uğurlamamız gerek. Bunun içinde close methodunu kullanabilirsiniz arkadaşlar. Basit olarak;

server.py ###############################################################

import socket
soket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000
soket.bind((HOST,PORT))
print “%s:%d server başlatıldı.” % (HOST,PORT)
print “Kullanıcı bekleniyor.”
soket.listen(1)
baglanti,adres = soket.accept()
print “Bir bağlantı kabul edildi.”, adres
baglanti.send(“Hoşgeldiniz efendim , hoşgeldiniz.”)
data = baglanti.recv(1024)
print data
soket.close()

şeklinde yazabilirsiniz.

İşin sunucu / server tarafını kafanızda birşeyler oluşsun diye böyle anlatmak istedim. Client kısmını daha rahat anlayabilirsiniz şimdi.

client.py
#######################################

import socket
soket = soket.socket(socket.AF_INET,socket.SOCK_STREAM)
HOST = “localhost”
PORT = 8000
soket.connect((HOST,PORT))
data = soket.recv(1024)
print data
soket.send(“Hoşbulduk!!”)
soket.close()

Kodların gerçekten anlaşılır olduğunu düşünüyorum. Ancak yine de üstünden geçelim. İlk olarak yine bir soket nesnesi oluşturduk ve server bilgilerimizi girdik. Burada server bilgilerinin her iki betikte de aynı olması gerekmektedir. Daha sonra bu server bilgilerini ve soket nesnesini kullanarak , connect methodu yardımıyla servera bağlanmak istedim. Ve serverdan gelen veriyi recv methodu ile alıp data isimli değişkene atadım. Bu değişkeni ekrana yazdırıp , aynı şekilde send methodu ile bir cevap yolladım.

Elimizde iki ayrı program oldu. Bunlardan birisi server öteki client. Öncelikle serverımızı çalıştırıp hazır hale getiriyoruz. server.py listen komutunu çalıştırdığında kendini beklemeye alacaktır. O öyle çalışır durumdayken, biz client.py betiğini çalıştırıyoruz ve yaptığımız işleri gözlemliyoruz.

Host bilgilerini 192.168.2.x şeklinde ayarlayarak isterseniz aynı modem üzerindeki iki ayrı makinede bunu deneyebilirsiniz. Bu sayede ağdaki diğer makineler üzerinde backdoor yazabilirsiniz.