Archive for August, 2008

CakePHP and ExtJS EditorGridPanel

Here’s another basic tutorial combining CakePHP and ExtJS, this time using grid editor. For this tutorial I assume that you have the basic knowledge cakephp, using bake utilities.
here’s the online demo

Grid Editor

table we need, based on my previous tutorial

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL DEFAULT '',
  `password` varchar(255) NOT NULL,
  `firstname` varchar(255) NOT NULL,
  `lastname` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `gender` enum('Male','Female') NOT NULL DEFAULT 'Male',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1

than using bake utilities create the model, controller and the view.
here’s my Users controllers :

class UsersController extends AppController {
 
var $name = 'Users';
	var $helpers = array('Html', 'Form', 'Javascript');
	var $components = array('RequestHandler');
 
	function index() {
		if($this->RequestHandler->isAjax()) {
			//$this->User->recursive = 0;
			$this->layout = 'Ajax';
			$count = $this->User->find('count');
			$dump  = $this->User->find('all');
			$users = Set::extract($dump, '{n}.User');
 
			$this->set('total', $count);
			$this->set('users',$users);
		} else {
 
		}
	}
 
	function add() {
		$this->layout = 'Ajax';
 
		if (!empty($this->data)) {
			$this->User->create();
			if ($this->User->save($this->data)) {
				$this->set('success', '{success:true}');
			} else {
				$this->set('success', '{success:false}');
			}
		}
	}
 
	function edit($id = null) {
		$this->layout = 'Ajax';
 
		if (!$id && empty($this->data)) {
			$this->set('success', '{success:false}');
		}
		if (!empty($this->data)) {
			if ($this->User->save($this->data)) {
				$this->set('success', '{success:true}');
			} else {
				$this->set('success', '{success:false}');
			}
		}
 
	}
 
	function delete($id = null) {
		$this->layout = 'Ajax';
		if($this->RequestHandler->isAjax()) {
			if (!$id) {
				$this->set('success', '{success:false}');
			}
			if ($this->User->del($id)) {
				$this->set('success', '{success:true}');
			}
		}
	}
 
}

then index.ctp view would be

<?php
	if(isset($total) and isset($users)) {
		echo '{"total":'.$total.', "users":'.$javascript->Object($users).'}';
	} else {
 
 
?>
<select name="gender" id="gender" style="display:none;">
	<option value="Male">Male</option>
	<option value="Female">Female</option>
</select>
 
<form id="submitgrid"></form>
 
<div id="usergrid" style="overflow: hidden;"></div>
 
<?php
	}
?>

last the javascript code

Ext.BLANK_IMAGE_URL = '/kelinci/css/extjs/images/default/s.gif';
 
var UGrid = function () {
	var userDS;
	var userCM;
	var userGrid;
 
	function setDS() {
		userDS = new Ext.data.JsonStore({
			url: '/kelinci/users/getUserList',
			root: 'users',
			id: 'id',
			totalProperty: 'total',
			fields: ['id','username','password','firstname','lastname','email','gender']
		})
		userDS.load();
	}
 
	function getColModel() {
		userCM = new Ext.grid.ColumnModel(
			[
				new Ext.grid.RowNumberer(),
				{
					header: 'id',
					hidden: true,
					width: 30,
					sortable: true,
					dataIndex: 'id'
				},
				{
					header: 'Username',
					hidden: false,
					width: 120,
					sortable: true,
					dataIndex: 'username',
					editor: new Ext.grid.GridEditor(
							new Ext.form.TextField(
							 	{
									allowBlank: false
								}
							)
					)
				},
				{
					header: 'Password',
					hidden: false,
					width: 120,
					sortable: true,
					dataIndex: 'password',
					editor: new Ext.grid.GridEditor(
							new Ext.form.TextField(
							 	{
									allowBlank: false
								}
							)
					)
				},
				{
					header: 'First Name',
					hidden: false,
					width: 120,
					sortable: true,
					dataIndex: 'firstname',
					editor: new Ext.grid.GridEditor(
							new Ext.form.TextField(
							 	{
									allowBlank: false
								}
							)
					)
				},
				{
					header: 'Last Name',
					hidden: false,
					width: 120,
					sortable: true,
					dataIndex: 'lastname',
					editor: new Ext.grid.GridEditor(
							new Ext.form.TextField(
							 	{
									allowBlank: false
								}
							)
					)
				},
				{
					header: 'Email',
					hidden: false,
					width: 100,
					sortable: true,
					dataIndex: 'email',
					editor: new Ext.grid.GridEditor(
							new Ext.form.TextField(
							 	{
									allowBlank: false
								}
							)
					)
				},
				{
					header: 'Gender',
					hidden: false,
					width: 50,
					sortable: true,
					dataIndex: 'gender',
					editor: new Ext.grid.GridEditor(
						new Ext.form.ComboBox(
						 	{
								typeAhead:true,
								triggerAction:'all',
								lazyRender:true,
								transform:'gender'
							}
						)
					)
				}
			]
		);
 
		return userCM;
	}
 
	function createGrid() {
		userCM = getColModel();
		userGrid = new Ext.grid.EditorGridPanel(
			{
				renderTo: 'usergrid',
				title: 'Grid Editor with CakePHP',
				ds: userDS,
				cm: userCM,
				autoSizeColumns: true,
				stripeRows: true,
				loadMask: true,
				width: 700,
				height: 300,
				selModel: new Ext.grid.RowSelectionModel({singleSelect:true}),
				viewConfig: {
	        		forceFit:true
	    		},
				tbar:
				[
				{
	        		text:'Add',
	        		tooltip:'Add new user',
	        		iconCls:'add',
	        		handler: function() {
	        			var gridForm = new Ext.BasicForm(
							Ext.get("submitgrid"),
							{
								baseParams: {
									'data[User][username]': 'username',
									'data[User][password]':'password',
									'data[User][firstname]': 'firstname',
									'data[User][lastname]': 'lastname',
									'data[User][email]':'user@email.com',
									'data[User][gender]':'Male'
								},
								url:'/kelinci/users/add'
							}
						);
 
						gridForm.submit(
							{
								waitMsg: 'Saving, please wait...',
 
								success:function(form, action) {
									Ext.Msg.alert('Status', 'Add new record saved successfully.');
									userDS.load();
								},
								failure: function(form, action) {
									Ext.Msg.alert('Status', 'Add new record failed.');
								}
							}
						);
 
	        		}
	    		},
				{
					text:'Remove',
	        		tooltip:'Delete  user',
	        		iconCls:'remove',
					handler: function() {
            			var hd = userGrid.getSelectionModel().getSelected().data;
						if (hd) {
            				Ext.MessageBox.confirm('Confirm', 'Are you sure you want to do that?',
            				function(btn) {
            					if(btn == 'yes') {
									Ext.MessageBox.show({
									   title: 'Please wait',
							           msg: 'Deleting...',
							           progressText: 'Deleting User ...',
							           width:300,
							           progress:true,
							           closable:false
							        });
            						Ext.Ajax.request({
										url: '/kelinci/users/delete/'+hd.id,
										success:function() {
											Ext.MessageBox.hide();
								   			Ext.Msg.alert('Status','Config deleted succesfuly ');
								   			userDS.load();
								   		},
  										failure: function() {
											Ext.MessageBox.hide();
  											Ext.Msg.alert('Status','Oops something wrong with server ??');
  										}
 
									});
 
									//Ext.Ajax.on('beforerequest', this.showSpinner, this);
            					}
            				}
            				);
						}
					}
				}
				]
 
			}
 
		);
 
		userGrid.on({
			afteredit: function(e) {
 
				Ext.Ajax.request({
 
					url: '/kelinci/users/edit/'+e.record.data['id'],
					method: 'POST',
					params: {
						'data[User][id]': e.record.data['id'],
						'data[User][username]': e.record.data['username'],
						'data[User][password]': e.record.data['password'],
						'data[User][firstname]': e.record.data['firstname'],
						'data[User][lastname]': e.record.data['lastname'],
 
						'data[User][email]': e.record.data['email'],
						'data[User][gender]':e.record.data['gender']
					},
					success:function() {
			   			//userDS.load();
			   		},
					failure: function() {
						//
					}
 
				});
 
				//console.log('e.record.data[\'id\'] = ' + e.record.data['id']);
 
		  	}
		});
	}
 
	return {
		init : function () {
			setDS();
			createGrid();
		},
		getDS : function () {
			return userDS;
		}
	}
}();
 
Ext.onReady(UGrid.init, UGrid, true);

Daily backup files with rsync

When we manage a lot of server we need to make sure everything run well, and if something wrong happen, easily we can restore the configuration, data, to the last state that working.This where rsync will help

Network Diagram

create crontab

05 00 * * * /root/backup_data.sh &gt;/dev/null 2&gt;&amp;1

run the backup process by running the backup_data.sh script 5 minute after midnight
and here’s the backup_data.sh

#!/bin/bash
rsync -e 'ssh -c blowfish -ax' -avz --delete --timeout 999  /etc/ backup@192.168.1.247:/home/backup/server1/etc/
# backup mail ...
rsync -avz --delete --timeout 999 -e 'ssh -c blowfish -ax' /home/vpopmail/ backup@192.168.1.247:/home/backup/server1/vpopmail/

above script will backup all files in directory /etc recursivly, and also files on /home/vpopmail. rsync command using ssh protocol when transfering data to remote system. we need to setup a ssh key pair for using ssh without password.

create a ssh keypair,

on server we need to backup

ssh-keygen -t rsa
ssh backup@backup.server mkdir -p .ssh
cat .ssh/id_rsa.pub | ssh backup@backup.server 'cat &gt;&gt; .ssh/authorized_keys'