summaryrefslogtreecommitdiff
path: root/demos/blog-tutorial/protected/pages/Day3/id
diff options
context:
space:
mode:
authorkabayan <>2007-08-29 11:55:06 +0000
committerkabayan <>2007-08-29 11:55:06 +0000
commit30795649ead5b7212cad32f9d5a9ca6152beba27 (patch)
treed2cb2e60736d967d55bb7b8ef23de1149f31ae3f /demos/blog-tutorial/protected/pages/Day3/id
parent91536b68a8eee2e2849949f605d3e5428f71cd9c (diff)
Indonesian Blog tutorial day 3,4, and 5 3rd tries
Diffstat (limited to 'demos/blog-tutorial/protected/pages/Day3/id')
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/Auth.page102
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page151
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page195
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page162
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page210
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/Overview.page26
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/directories.gifbin0 -> 10329 bytes
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/output.gifbin0 -> 10006 bytes
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/output2.gifbin0 -> 9222 bytes
-rw-r--r--demos/blog-tutorial/protected/pages/Day3/id/output3.gifbin0 -> 9464 bytes
10 files changed, 846 insertions, 0 deletions
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/Auth.page b/demos/blog-tutorial/protected/pages/Day3/id/Auth.page
new file mode 100644
index 00000000..c4728cdf
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/Auth.page
@@ -0,0 +1,102 @@
+<com:TContent ID="Main">
+
+<h1>Otentikasi dan Otorisasi</h1>
+
+<p>
+Sebelum kita siap mengimplementasikan halaman pengguna, kita perlu melakukan beberapa pekerjaan guna menghidupkan <a href="http://www.pradosoft.com/demos/quickstart/index.php?page=Advanced.Auth">otentikasi dan otorisasi</a>.
+</p>
+
+<p>
+Kita menambah dua modul ke konfigurasi aplikasi seperti berikut:
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="xml">
+<modules>
+ ...TDataSourceConfig and TActiveRecordConfig modules...
+
+ <module id="auth"
+ class="System.Security.TAuthManager"
+ UserManager="users"
+ LoginPage="users.LoginUser" />
+
+ <module id="users"
+ class="System.Security.TDbUserManager"
+ UserClass="Application.BlogUser" />
+</modules>
+</com:TTextHighlighter>
+
+<p>
+Modul <a href="http://www.pradosoft.com/docs/classdoc/TAuthManager">TAuthManager</a> mengatur seluruh alur kerja otentikasi dan otorisasi. Ia menggunakan modul <tt>users</tt> sebagai manajer penggunanya (lihat di bawah). Dengan menetapkan properti <tt>LoginPage</tt>, kita menginformasikan manajer otentikasi untuk mengalihkan browser pengguna ke halaman <tt>LoginUser</tt> saat otorisasi gagal. Kami akan menjelaskan bagaimana untuk membuat <tt>LoginUser</tt> dalam subbagian berikutnya.
+</p>
+
+<p>
+Modul <tt>user</tt> adalah kelas <a href="http://www.pradosoft.com/docs/classdoc/TDbUserManager">TDbUserManager</a> yang bertanggung jawab untuk memverifikasi keabsahan pengguna dan memelihara data dasar dalam sesi PHP. Properti <tt>UserClass</tt> diinisialisasi sebagai <tt>Application.BlogUser</tt>, yang menunjukan bahwa manajer pengguna akan melihar kelas <tt>BlogUser</tt> di bawah direktori <tt>protected</tt> (ingat alias <tt>Application</tt> merujuk ke direktori <tt>protected</tt>) dan menggunakannya untuk memelihara data sesi pengguna.
+</p>
+
+<p>
+Seperti yang akan kita lihat dalam bagian nanti, dalam kontrol dan halaman, kita dapat menggunakan <tt>$this->User</tt> untuk memperoleh obyek <tt>BlogUser</tt> yang berisi informasi pengguna yang saat ini mengakses siistem.
+</p>
+
+<p>
+Di bawah ini adalah rincian implementasi dari <tt>BlogUser</tt>. Perhatikan, <a href="http://www.pradosoft.com/demos/quickstart/index.php?page=Database.ActiveRecord">Rekaman Aktif</a> digunakan untuk melakukan query DB. Sebagai contoh, kita menggunakan <tt>UserRecord::finder()->findByPk($username)</tt> untuk mencari kunci primer yang ditetapkan oleh <tt>$username</tt> dalam tabel <tt>users</tt>.
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="php">
+// Sertakan file TDbUserManager.php yang mendefinisikan TDbUser
+Prado::using('System.Security.TDbUserManager');
+
+/**
+ * BlogUser Class.
+ * BlogUser mewakili data pengguna yang perlu dijaga dalam sesi.
+ * Implementasi standar memelihara informasi aturan dan pengguna.
+ */
+class BlogUser extends TDbUser
+{
+ /**
+ * Membuat obyek BlogUser berdasarkan username yang ditetapkan.
+ * Metode ini diperlukan oleh TDbUser. Ia memeriksa database
+ * untuk melihat apakah username yang ditetapkan ada di sana. Jika ada,
+ * obyek BlogUser dibuat dan diinisialisasi.
+ * @param string username yang ditetapkan
+ * @return BlogUser obyek pengguna, null jika username tidak benar.
+ */
+ public function createUser($username)
+ {
+ // gunakan Rekaman Aktif UserRecord untuk mencari username yang ditetapkan
+ $userRecord=UserRecord::finder()->findByPk($username);
+ if($userRecord instanceof UserRecord) // jika ditemukan
+ {
+ $user=new BlogUser($this->Manager);
+ $user->Name=$username; // setel nama pengguna
+ $user->Roles=($userRecord->role==1?'admin':'user'); // setel aturan
+ $user->IsGuest=false; // pengguna bukan seorang tamu
+ return $user;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Memeriksa apakah (username, password) yang ditetapkan sudah benar.
+ * Metode ini diperlukan oleh TDbUser.
+ * @param string username
+ * @param string password
+ * @return boolean apakah username dan password sudah benar.
+ */
+ public function validateUser($username,$password)
+ {
+ // pakai Rekaman Aktif UserRecord untuk mencari pasangan (username, password).
+ return UserRecord::finder()->findBy_username_AND_password($username,$password)!==null;
+ }
+
+ /**
+ * @return boolean apakah pengguna ini adalah seorang administrator.
+ */
+ public function getIsAdmin()
+ {
+ return $this->isInRole('admin');
+ }
+}
+</com:TTextHighlighter>
+
+</com:TContent> \ No newline at end of file
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page
new file mode 100644
index 00000000..c9ee7c5a
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page
@@ -0,0 +1,151 @@
+<com:TContent ID="Main">
+
+<h1>Membuat Halaman <tt>AdminUser</tt></h1>
+
+<p>
+Halaman <tt>AdminUser</tt> menampilkan semua akun pengguna dalam sebuah daftar agar administrator dapat melakukan beberapa pekerjaan administratif. Demi kemudahan, pekerjaan administratif sistem blog kita mendukung termasuk mengedit dan menghapus akun pengguna.
+</p>
+
+<p>
+Kita akan menampilkan daftar pengguna dalam sebuah tabel. Setiap baris tabel mewakili satu akun pengguna, dan kolom berikut ditampilkan:
+</p>
+<ul>
+<li>Username - menampilkan nama pengguna. Dalam setiap sel sebuah hiperlink ditampilkan membawa ke halaman <a href="?page=Day3.CreateEditUser">EditUser</a> terkait.</li>
+<li>Email - menampilkan email.</li>
+<li>Administrator - menampilkan apakah akun pengguna adalah aturan administrator.</li>
+<li>Command - menampilkan kolom dengan tombol "Delete". Mengklik pada setiap tombol akan mengakibatkan penghapusan akun pengguna terkait.</li>
+</ul>
+
+<p>
+Kita membuat dua file <tt>protected/pages/users/AdminUser.page</tt> dan <tt>protected/pages/users/AdminUser.php</tt> masing-masing untuk menyimpan template halaman dan kelas halaman.
+</p>
+
+<h2>Membuat Template Halaman</h2>
+<p>
+Kita menggunakan <a href="http://www.pradosoft.com/demos/quickstart/?page=Controls.DataGrid">TDataGrid</a> untuk menampilkan akun pengguna. Berdasarkan pada analisis di atas, kita mengkonfigurasi empat kolom berikut:
+</p>
+<ul>
+<li><a href="http://www.pradosoft.com/docs/classdoc/THyperLinkColumn">THyperLinkColumn</a> menampilkan kolom nama pengguna. URL dibentuk berdasarkan pada ekstensi PHP yang ditetapkan dalam properti <tt>DataNavigateUrlFormatString</tt>.</li>
+<li><a href="http://www.pradosoft.com/docs/classdoc/TBoundColumn">TBoundColumn</a> menampilkan kolom email.</li>
+<li><a href="http://www.pradosoft.com/docs/classdoc/TCheckBoxColumn">TCheckBoxColumn</a> menggunakan kotak centang untuk menunjukan apakah akun pengguna adalah aturan administrator.</li>
+<li><a href="http://www.pradosoft.com/docs/classdoc/TButtonColumn">TButtonColumn</a> menampilkan kolom dengan tombol "Delete".</li>
+</ul>
+
+<p>Template halaman lengkap ditampilkan seperti berikut:</p>
+
+<com:TTextHighlighter CssClass="source" Language="prado">
+&lt;%@ Title="My Blog - Manage User Accounts" %>
+
+&lt;com:TContent ID="Main">
+
+<h1>Manage User Accounts</h1>
+
+<a href="&lt;%= $this->Service->constructUrl('users.NewUser')%>">Create New User</a>
+<br/>
+
+&lt;com:TDataGrid ID="UserGrid"
+ DataKeyField="username"
+ AutoGenerateColumns="false"
+ OnDeleteCommand="deleteButtonClicked">
+
+ &lt;com:THyperLinkColumn
+ HeaderText="Username"
+ DataTextField="username"
+ DataNavigateUrlField="username">
+ &lt;prop:DataNavigateUrlFormatString>#
+ $this->Service->constructUrl('users.EditUser',array('username'=>{0}))
+ &lt;/prop:DataNavigateUrlFormatString>
+ &lt;/com:THyperLinkColumn>
+
+ &lt;com:TBoundColumn
+ HeaderText="Email"
+ DataField="email" />
+
+ &lt;com:TCheckBoxColumn
+ HeaderText="Administrator"
+ DataField="role" />
+
+ &lt;com:TButtonColumn
+ HeaderText="Command"
+ Text="Delete"
+ ButtonType="PushButton"
+ CommandName="delete" />
+
+&lt;/com:TDataGrid>
+
+&lt;/com:TContent>
+</com:TTextHighlighter>
+
+
+<h2>Membuat Kelas Halaman</h2>
+
+<p>
+Dalam template halaman di atas, event <tt>OnDeleteCommand</tt> datagrid dengan metode <tt>deleteButtonClicked()</tt> akan kita implementasikan dalam kelas halaman. Sebagai tambahan, datagrid perlu dipopulasi dengan data akun pengguna saat halaman diinisialisasi. Oleh karena itu, kita menulis kelas halaman seperti berikut:
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="php">
+class AdminUser extends TPage
+{
+ /**
+ * Mempopulai datagrid dengan daftar pengguna.
+ * Metode ini dipanggil oleh kerangka kerja saat inisialisasi halaman
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ // ambil semua informasi data akun
+ $this->UserGrid->DataSource=UserRecord::finder()->findAll();
+ // mengikat data ke komponen antarmua
+ $this->UserGrid->dataBind();
+ }
+
+ /**
+ * Menghapus rekaman pengguna yang ditetapkan.
+ * Metode ini merespon ke event OnDeleteCommand pada datagrid.
+ * @param TDataGrid pengirim event
+ * @param TDataGridCommandEventParameter parameter event
+ */
+ public function deleteButtonClicked($sender,$param)
+ {
+ // dapatkan item datagrid yang berisi tombol hapus yang diklik
+ $item=$param->Item;
+ // dapatkan kunci primer terkait ke item datagrid
+ $username=$this->UserGrid->DataKeys[$item->ItemIndex];
+ // menghapus rekaman pengguna dengan kunci primer nama pengguna
+ UserRecord::finder()->deleteByPk($username);
+ }
+}
+</com:TTextHighlighter>
+
+<p>
+Dalam kode di atas, metode <tt>deleteButtonClicked()</tt> dipanggil kapan saja tombol "Delete" diklik. untuk menentukan baris mana pada tombol yang diklik, kita memeriksa properti <tt>Item.ItemIndex</tt> pada parameter event. Untuk selanjutnya mengidentifikasi akun pengguna mana yang akan dihapus, kita mengambil nilai kunci primer (username) melalui properti <tt>DataKeys</tt> pada DataGrid.
+</p>
+
+<com:TipBox>
+Semua kontrol <a href="http://www.pradosoft.com/docs/classdoc/TDataBoundControl">data-bound</a> mempunyai pola penggunaan yang sama. Yaitu, Setel properti <tt>DataSource</tt> dengan data dan panggil metode <tt>dataBind()</tt> untuk mengikat data ke struktur internal kontrol.
+</com:TipBox>
+
+
+<h2>Menambahkan Pemeriksaan Perijinan</h2>
+<p>
+Karena <tt>AdminUser</tt> hanya bisa diakses oleh administrator, maka kita perlu menyesuaikan file konfigurasi halaman <tt>protected/pages/users/config.xml</tt>.
+</p>
+<com:TTextHighlighter CssClass="source" Language="xml">
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <authorization>
+ <allow pages="NewUser,AdminUser" roles="admin" />
+ <deny users="?" />
+ </authorization>
+</configuration>
+</com:TTextHighlighter>
+
+<h2>Pengujian</h2>
+<p>
+Untuk menguji halaman <tt>AdminUser</tt>, kunjungi URL <tt>http://hostname/blog/index.php?page=users.AdminUser</tt>. Anda mungkin perlu masuk sebagai administrator lebih dahulu jika anda belum melakukannya. Kita akan melihat hasil seperti berikut.
+</p>
+
+<img src="<%~ output3.gif %>" class="output" />
+
+</com:TContent> \ No newline at end of file
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page
new file mode 100644
index 00000000..e15df047
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page
@@ -0,0 +1,195 @@
+<com:TContent ID="Main">
+
+<h1>Membuat Halaman <tt>EditUser</tt></h1>
+
+<p>
+Halaman <tt>EditUser</tt> sangat mirip dengan <a href="?page=Day3.CreateNewUser">NewUser</a>. Perbedaan utamanya adalah bahwa saat <tt>EditUser</tt> awalnya diminta, field input harus diinisialisasi dengan informasi pengguna yang sudah ada. Sedikit perbedaan lainnya adalah bahwa <tt>EditUser</tt> juga bisa diakses oleh pengguna normal.
+</p>
+
+<p>
+Untuk menentukan akun pengguna mana yang diedit, kita menggunakan kebijakan berikut:
+</p>
+<ul>
+<li>Jika pengguna saat ini adalah administrator, dia dapat mengedit setiap akun pengguna dengan menetapkan akun nama pengguna dalam variabel GET bernama 'username'. Sebagai contoh, <tt>http://hostname/blog/index.php?page=users.EditUser&username=demo</tt>.</li>
+<li>Jika pengguna saat ini adalah administrator dan URL tidak berisi 'username', data administrator sendiri sedang dimutakhirkan.</li>
+<li>Jika pengguna saat ini adalah pengguna normal, dia hanya bisa mengedit informasi akunnya sendiri, dan dia tidak bisa memodifikasi data aturannya.</li>
+</ul>
+
+<p>
+Kita membuat dua file <tt>protected/pages/users/EditUser.page</tt> dan <tt>protected/pages/users/EditUser.php</tt> masing-masing untuk menyimpan template halaman dan kelas halaman.
+</p>
+
+<h2>Membuat Template Halaman</h2>
+<p>
+Seperti yang telah anda tebak, template halaman <tt>EditUser</tt> sebagian besar sama seperti pada <tt>NewUser</tt>. Selain perbedaan dalam judul halaman dan judul tombol submit, ada tiga perbedaan utama.
+</p>
+<ul>
+<li>Kotak teks "username" diganti oleh kontrol <a href="http://www.pradosoft.com/demos/quickstart/?page=Controls.Label">TLabel</a> karena kita tidak membolehkan memodifikasi nama pengguna;</li>
+<li>Validator untuk input "password" dihilangkan. Ini dikarenakan jika pengguna tidak melengkapi kata sandi selama mengedit, itu berarti pengguna tidak ingin mengubah kata sandi.</li>
+<li>Input "role" dikelilingi oleh <tt>TControl</tt> yang penampakannya dihidup matikan berdasarkan aturan pengguna yang masuk saat ini. Jika pengguna bukan administrator, input "role" tidak akan ditampilkan karena pengguna normal tidak diperbolehkan untuk memodifikasi aturannya.</li>
+</ul>
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="prado">
+&lt;%@ Title="My Blog - Edit User" %>
+
+&lt;com:TContent ID="Main">
+
+<h1>Edit User</h1>
+
+<span>Username:</span>
+&lt;com:TLabel ID="Username" />
+
+<br/>
+<span>Password:</span>
+<br/>
+&lt;com:TTextBox ID="Password" TextMode="Password" />
+
+<br/>
+<span>Re-type Password:</span>
+&lt;com:TCompareValidator
+ ControlToValidate="Password"
+ ControlToCompare="Password2"
+ ErrorMessage="Your password entries did not match."
+ Display="Dynamic" />
+<br/>
+&lt;com:TTextBox ID="Password2" TextMode="Password" />
+
+<br/>
+<span>Email Address:</span>
+&lt;com:TRequiredFieldValidator
+ ControlToValidate="Email"
+ ErrorMessage="Please provide your email address."
+ Display="Dynamic" />
+&lt;com:TEmailAddressValidator
+ ControlToValidate="Email"
+ ErrorMessage="You entered an invalid email address."
+ Display="Dynamic" />
+<br/>
+&lt;com:TTextBox ID="Email" />
+
+&lt;com:TControl Visible="&lt;%= $this->User->IsAdmin %>">
+<br/>
+<span>Role:</span>
+<br/>
+&lt;com:TDropDownList ID="Role">
+ &lt;com:TListItem Text="Normal User" Value="0" />
+ &lt;com:TListItem Text="Administrator" Value="1" />
+&lt;/com:TDropDownList>
+&lt;/com:TControl>
+
+<br/>
+<span>First Name:</span>
+<br/>
+&lt;com:TTextBox ID="FirstName" />
+
+<br/>
+<span>Last Name:</span>
+<br/>
+&lt;com:TTextBox ID="LastName" />
+
+<br/>
+&lt;com:TButton Text="Save" OnClick="saveButtonClicked" />
+
+&lt;/com:TContent>
+</com:TTextHighlighter>
+
+
+<h2>Membuat Kelas Halaman</h2>
+
+<p>
+Berdasarkan pada deskripsi di atas dan template, kita perlu menulis kelas halaman yang mengawali input dengan informasi pengguna yang sudah ada. Sebagai tambahan, kelas halaman juga perlu untuk mengimplementasikan metode <tt>saveButtonClicked()</tt> yang disertakan pada event tombol "save" <tt>OnClick</tt>.
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="php">
+class EditUser extends TPage
+{
+ /**
+ * Menginisialisasi input dengan data pengguna yang sudah ada.
+ * Metode ini dipanggil oleh kerangka kerja saat halaman diinisialisasi.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ if(!$this->IsPostBack) // jika halaman awalnya diminta
+ {
+ // Ambil data pengguna yang sudah ada. Ini sama dengan:
+ // $userRecord=$this->getUserRecord();
+ $userRecord=$this->UserRecord;
+
+ // Populasikan kontrol input dengan data pengguna yang sudah ada
+ $this->Username->Text=$userRecord->username;
+ $this->Email->Text=$userRecord->email;
+ $this->Role->SelectedValue=$userRecord->role;
+ $this->FirstName->Text=$userRecord->first_name;
+ $this->LastName->Text=$userRecord->last_name;
+ }
+ }
+
+ /**
+ * Menyimpan akun pengguna jika semua input sudah benar.
+ * Metode ini merespon event OnClick pada tombol "save".
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function saveButtonClicked($sender,$param)
+ {
+ if($this->IsValid) // saat semua validasi sukses
+ {
+ // Ambil data pengguna yang sudah ada. Ini sama dengan:
+ $userRecord=$this->UserRecord;
+
+ // Ambil data input
+ $userRecord->username=$this->Username->Text;
+ // mutakhirkan kata sandi saat input tidak kosong
+ if(!empty($this->Password->Text))
+ $userRecord->password=$this->Password->Text;
+ $userRecord->email=$this->Email->Text;
+ // mutakhirkan aturan jika pengguna saat ini adalah administrator
+ if($this->User->IsAdmin)
+ $userRecord->role=(int)$this->Role->SelectedValue;
+ $userRecord->first_name=$this->FirstName->Text;
+ $userRecord->last_name=$this->LastName->Text;
+
+ // simpan ke database melalui mekanisme Rekaman Aktif
+ $userRecord->save();
+
+ // alihkan browser ke homepage
+ $this->Response->redirect($this->Service->DefaultPageUrl);
+ }
+ }
+
+ /**
+ * Mengembalikan data pengguna yang diedit.
+ * @return UserRecord data pengguna yang diedit.
+ * @throws THttpException jika data pengguna tidak ditemukan.
+ */
+ protected function getUserRecord()
+ {
+ // pengguna yang diedit adalah pengguna yang saat ini sudah masuk
+ $username=$this->User->Name;
+ // jika var GET 'username' tidak kosong dan pengguna saat ini adalah
+ // administrator, lebih baik kita menggunakan nilai var GET.
+ if($this->User->IsAdmin && $this->Request['username']!==null)
+ $username=$this->Request['username'];
+
+ // gunakan Rekaman Aktif untuk melihat nama pengguna yang ditetapkan
+ $userRecord=UserRecord::finder()->findByPk($username);
+ if(!($userRecord instanceof UserRecord))
+ throw new THttpException(500,'Username is invalid.');
+ return $userRecord;
+ }
+}
+</com:TTextHighlighter>
+
+<com:TipBox>
+Metode <tt>onInit()</tt> dipanggil oleh PRADO selama salah satu <a href="http://www.pradosoft.com/demos/quickstart/?page=Fundamentals.Pages">masa hidup halaman</a>. Metode masa hidup umum lainnya ditimpa termasuk <tt>onPreInit()</tt>, <tt>onLoad()</tt> dan <tt>onPreRender()</tt>.
+</com:TipBox>
+
+<h2>Pengujian</h2>
+<p>
+Untuk menguji halaman <tt>EditUser</tt>, kunjungi URL <tt>http://hostname/blog/index.php?page=users.EditUser&username=demo</tt>. Anda mungkin perlu masuk lebih dulu jika anda belum melakukannya. Coba masuk dengan akun berbeda (e.g. admin/demo, demo/demo) dan lihat bagaimana halaman ditampilkan secara berbeda.
+</p>
+
+</com:TContent> \ No newline at end of file
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page
new file mode 100644
index 00000000..1debbec0
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page
@@ -0,0 +1,162 @@
+<com:TContent ID="Main">
+
+<h1>Membuat Halaman <tt>LoginUser</tt></h1>
+
+<p>
+Halaman <tt>LoginUser</tt> menampilkan formulir masuk dan mengotentikasi pengguna yang mencoba untuk masuk. Seperti dijelaskan dalam <a href="?page=Day3.Auth">otentikasi dan otorisasi</a>, browser pengguna secara otomatis dialihkan ke halaman <tt>LoginUser</tt> ketika pengguna mencoba untuk mengakses halaman istimewa, seperti misalhnya halaman admin pengguna.
+</p>
+
+<p>
+Alur kerja <tt>LoginUser</tt> sangat mirip dengan halaman <a href="?page=Day1.CreateContact">Contact</a>:
+</p>
+<ol>
+<li>Ketika pengguna mengakses halaman <tt>LoginUser</tt>, formulir masuk ditampilkan;</li>
+<li>Pengguna mengisi nama pengguna dan kata sandi serta mengklik pada tombol "login";</li>
+<li><tt>LoginUser</tt> menerima event "login" dan memicu rangkaian otentikasi;</li>
+<li>Jika pengguna memasukan nama pengguna dan kata sandi yang benar, sistem menempatkan identitas yang sah dan mengalihkan browser-nya ke halaman istimewa yang diinginkan; Jika tidak, pesan "password invalid" akan ditampilkan.
+</ol>
+
+<p>
+Kita membuat dua file <tt>protected/pages/users/LoginUser.page</tt> dan <tt>protected/pages/users/LoginUser.php</tt> masing-masing untuk menyimpan template halaman dan kelas halaman.
+</p>
+
+<h2>Membuat Template Halaman</h2>
+
+<p>
+Di bawah ini kita menampilkan template untuk <tt>LoginUser</tt>. Seperti kita lihat, halaman sebagian besar berisi kotak teks untuk mengumpulkan nama pengguna dan kotak teks untuk kata sandi. Input nama pengguna diperlukan, yang dipastikan oleh <tt>TRequiredFieldValidator</tt>. Kebenaran dari input kata sandi dipastikan oleh <a href="http://www.pradosoft.com/demos/quickstart/index.php?page=Controls.Validation">TCustomValidator</a> yang memanggil metode <tt>validateUser()</tt> halaman ketika validasi dilakukan. Halaman juga mempunyai tombol "login" yang memanggil <tt>loginButtonClicked()</tt> halaman ketika itu diklik.
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="prado">
+&lt;%@ Title="My Blog - Login" %>
+
+&lt;com:TContent ID="Main">
+
+<h1>Login</h1>
+
+<span>Username:</span>
+&lt;com:TRequiredFieldValidator
+ ControlToValidate="Username"
+ ErrorMessage="Please provide your username."
+ Display="Dynamic" />
+<br/>
+&lt;com:TTextBox ID="Username" />
+
+<br/>
+<span>Password:</span>
+&lt;com:TCustomValidator
+ ControlToValidate="Password"
+ ErrorMessage="Your entered an invalid password."
+ Display="Dynamic"
+ OnServerValidate="validateUser" />
+<br/>
+&lt;com:TTextBox ID="Password" TextMode="Password" />
+
+<br/>
+&lt;com:TButton Text="Login" OnClick="loginButtonClicked" />
+
+&lt;/com:TContent>
+</com:TTextHighlighter>
+
+<h2>Membuat Kelas Halaman</h2>
+
+<p>
+Seperti halaman <a href="?page=Day1.CreateContact">Contact</a>, halaman <tt>LoginUser</tt> juga memerlukan file kelas yang sebagian besar berisi implementasi pengendali event yang disertakan dalam template halaman. Di sini, kita perlu mengimplementasikan dua metode: <tt>validateUser()</tt> dan <tt>loginButtonClicked()</tt>. Dalam <tt>validateUser()</tt>, kita menggunakan <a href="?page=Day3.Auth">manajer otentikasi</a> untuk memverifikasi apakan nama pengguna serta kata sandinya sudah benar. Jika benar, manajer otentikasi akan secara otomatis membuat sesi pengguna dengan informasi identitas pengguna terkait.
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="php">
+class LoginUser extends TPage
+{
+ /**
+ * Validates whether the username and password are correct.
+ * This method responds to the TCustomValidator's OnServerValidate event.
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function validateUser($sender,$param)
+ {
+ $authManager=$this->Application->getModule('auth');
+ if(!$authManager->login($this->Username->Text,$this->Password->Text))
+ $param->IsValid=false; // beritahu validator bawa validasi gagal
+ }
+
+ /**
+ * Redirects the user's browser to appropriate URL if login succeeds.
+ * This method responds to the login button's OnClick event.
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function loginButtonClicked($sender,$param)
+ {
+ if($this->Page->IsValid) // semua validasi sukses
+ {
+ // Dapatkan URL pada halaman istimewa yang diinginkan pengguna yang akan dikunjungi
+ $url=$this->Application->getModule('auth')->ReturnUrl;
+ if(empty($url)) // pengguna mengakses halaman masuk secara langsung
+ $url=$this->Service->DefaultPageUrl;
+ $this->Response->redirect($url);
+ }
+ }
+}
+</com:TTextHighlighter>
+
+
+<h2>Pengujian</h2>
+
+<p>
+Kita telah membuat halaman <tt>LoginUser</tt>. Kita dapat mengujinya dengan mengunjungi URL <tt>http://hostname/blog/index.php?page=users.LoginUser</tt>. Ingat dalam subbagian <a href="?page=Day2.CreateDB">Membuat Database</a>, kita sudah membuat dua akun pengguna (username/password): <tt>admin/demo</tt> dan <tt>demo/demo</tt>. Kita dapat menggunakannya untuk menguji halaman masuk kita.
+</p>
+
+<img src="<%~ output.gif %>" class="output"/>
+
+<h2>Menambahkan Link Login/Logout ke Master</h2>
+
+<p>
+Guna melengkapi cara langsung bagi pengguna untuk masuk dan keluar, kita memodifikasi sedikit kontrol master <tt>MainLayout</tt>. Dalam keadaan tertentu, kita menambahkan hiperlink "login" yang mengaitkan halaman <tt>LoginUser</tt>. Kita juga menambahkan tombol link "logout" yang mengeluarkan pengguna saat ia diklik.
+</p>
+
+<p>
+Kita memodifikasi bagian footer dari template <tt>MainLayout</tt> sebagai berikut. Penampakan "login" dan "logout" ditentukan berdasarkan status pengguna. Jika pengguna belum masuk, misalnya <tt>$this->User->IsGuest</tt> adalah true, link "login" terlihat sementara link "logout" tidak; dan begitu sebaliknya.
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="prado">
+<div id="footer">
+&lt;com:THyperLink Text="Login"
+ NavigateUrl="&lt;%= $this->Service->constructUrl('users.LoginUser') %>"
+ Visible="&lt;%= $this->User->IsGuest %>" />
+
+&lt;com:TLinkButton Text="Logout"
+ OnClick="logoutButtonClicked"
+ Visible="&lt;%= !$this->User->IsGuest %>" />
+
+<br/>
+&lt;%= PRADO::poweredByPrado() %>
+</div>
+</com:TTextHighlighter>
+
+<p>
+Karena tombol "logout" menempelkan event <tt>OnClick</tt> dengan metode yang dipanggil <tt>logoutButtonClicked()</tt>, kita juga perlu mengubah file kelas <tt>MainLayout</tt>.
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="php">
+class MainLayout extends TTemplateControl
+{
+ /**
+ * Logs out a user.
+ * This method responds to the "logout" button's OnClick event.
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function logoutButtonClicked($sender,$param)
+ {
+ $this->Application->getModule('auth')->logout();
+ $url=$this->Service->constructUrl($this->Service->DefaultPage);
+ $this->Response->redirect($url);
+ }
+}
+</com:TTextHighlighter>
+
+<p>
+Sekarang jika kita mengunjungi setiap halaman pada sistem blog kita, kita akah melihat apakah ada link di bawah halaman. Link menampilkan "Login" jika kita belum masuk dan "Logout" jika telah masuk. Jika kita mengklik pada "Logout", browser akan mengalihkannya ke homepage dan "Login" ditampilkan yang berarti kita sudah dikeluarkan.
+</p>
+
+</com:TContent> \ No newline at end of file
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page
new file mode 100644
index 00000000..905f7489
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page
@@ -0,0 +1,210 @@
+<com:TContent ID="Main">
+
+<h1>Membuat Halaman <tt>NewUser</tt></h1>
+
+<p>
+Halaman <tt>NewUser</tt> disediakan untuk pengguna administrator guna membuat akun pengguna baru. Ini perlu menampilkan sebuah formulir yang mengumpulkan informasi mengenai akun pengguna baru. Berdasarkan <a href="?page=Day2.CreateDB">definisi database</a>, kita akan perlu mengumpulkan informasi berikut:
+</p>
+
+<ul>
+<li><tt>username</tt> - string, diperlukan dan unik</li>
+<li><tt>email</tt> - string, diperlukan dan unik</li>
+<li><tt>password</tt> - string, diperlukan</li>
+<li><tt>role</tt> - integer, diperlukan (baik 0 ataupun 1)</li>
+<li><tt>first_name</tt> - string, opsional</li>
+<li><tt>last_name</tt> - string, opsional</li>
+</ul>
+
+<p>
+Kita membuat dua file <tt>protected/pages/users/NewUser.page</tt> dan <tt>protected/pages/users/NewUser.php</tt> masing-masing untuk menyimpan template halaman dan kelas halaman.
+</p>
+
+<h2>Membuat Template Halaman</h2>
+<p>
+Berdasarkan pada analisis di atas, kita menulis template halaman seperti berikut:
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="prado">
+&lt;%@ Title="My Blog - New User" %>
+
+&lt;com:TContent ID="Main">
+
+<h1>Create New User</h1>
+
+<span>Username:</span>
+&lt;com:TRequiredFieldValidator
+ ControlToValidate="Username"
+ ErrorMessage="Please provide a username."
+ Display="Dynamic" />
+&lt;com:TCustomValidator
+ ControlToValidate="Username"
+ ErrorMessage="Sorry, your username is taken by someone else. Please choose another username."
+ OnServerValidate="checkUsername"
+ Display="Dynamic" />
+<br/>
+&lt;com:TTextBox ID="Username" />
+
+<br/>
+<span>Password:</span>
+&lt;com:TRequiredFieldValidator
+ ControlToValidate="Password"
+ ErrorMessage="Please provide a password."
+ Display="Dynamic" />
+<br/>
+&lt;com:TTextBox ID="Password" TextMode="Password" />
+
+<br/>
+<span>Re-type Password:</span>
+&lt;com:TCompareValidator
+ ControlToValidate="Password"
+ ControlToCompare="Password2"
+ ErrorMessage="Your password entries did not match."
+ Display="Dynamic" />
+<br/>
+&lt;com:TTextBox ID="Password2" TextMode="Password" />
+
+<br/>
+<span>Email Address:</span>
+&lt;com:TRequiredFieldValidator
+ ControlToValidate="Email"
+ ErrorMessage="Please provide your email address."
+ Display="Dynamic" />
+&lt;com:TEmailAddressValidator
+ ControlToValidate="Email"
+ ErrorMessage="You entered an invalid email address."
+ Display="Dynamic" />
+<br/>
+&lt;com:TTextBox ID="Email" />
+
+<br/>
+<span>Role:</span>
+<br/>
+&lt;com:TDropDownList ID="Role">
+ &lt;com:TListItem Text="Normal User" Value="0" />
+ &lt;com:TListItem Text="Administrator" Value="1" />
+&lt;/com:TDropDownList>
+
+<br/>
+<span>First Name:</span>
+<br/>
+&lt;com:TTextBox ID="FirstName" />
+
+<br/>
+<span>Last Name:</span>
+<br/>
+&lt;com:TTextBox ID="LastName" />
+
+<br/>
+&lt;com:TButton Text="Create" OnClick="createButtonClicked" />
+
+&lt;/com:TContent>
+</com:TTextHighlighter>
+
+<p>
+Template tidak jauh berbeda dari template <tt>Contact</tt> dan halaman <tt>LoginUser</tt>. Sebagian besar terdiri dari kotak teks dan validator. Beberapa kotak teks, seperti nama pengguna, dikaitkan dengan dua validator karena keterlibatan aturan multipel validasi.
+</p>
+
+
+<h2>Membuat Kelas Halaman</h2>
+
+<p>
+Dari template halaman di atas, kita melihat bahwa kita perlu untuk menulis sebuah kelas halaman yang mengimplementasikan dua pengendali event: <tt>checkUsername()</tt> (disertakan ke event validator kustom <tt>OnServerValidate</tt>) dan <tt>createButtonClicked()</tt> (disertakan ke event tombol "create" <tt>OnClick</tt>). Oleh karena itu, kita menulis kelas halaman seperti berikut:
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="php">
+class NewUser extends TPage
+{
+ /**
+ * Memeriksa apakah nama pengguna sudah ada dalam database.
+ * Metode ini merespon ke event OnServerValidate pada validator kustom nama pengguna.
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function checkUsername($sender,$param)
+ {
+ // benar jika nama pengguna tidak ditemukan dalam database
+ $param->IsValid=UserRecord::finder()->findByPk($this->Username->Text)===null;
+ }
+
+ /**
+ * Membuat akun pengguna baru jika semua input benar.
+ * Metode ini merespon ke event OnClick pada tombol "create".
+ * @param mixed event sender
+ * @param mixed event parameter
+ */
+ public function createButtonClicked($sender,$param)
+ {
+ if($this->IsValid) // ketika semua validasi sukses
+ {
+ // populasikan obyek UserRecord dengan input pengguna
+ $userRecord=new UserRecord;
+ $userRecord->username=$this->Username->Text;
+ $userRecord->password=$this->Password->Text;
+ $userRecord->email=$this->Email->Text;
+ $userRecord->role=(int)$this->Role->SelectedValue;
+ $userRecord->first_name=$this->FirstName->Text;
+ $userRecord->last_name=$this->LastName->Text;
+
+ // simpan database melalui mekanisme Rekaman Aktif
+ $userRecord->save();
+
+ // alihkan browser ke homepage
+ $this->Response->redirect($this->Service->DefaultPageUrl);
+ }
+ }
+}
+</com:TTextHighlighter>
+
+<p>
+Dalam kode di atas, memanggil <tt>save()</tt> akan menyisipkan baris baru dalam tabel <tt>users</tt>. Fitur intuitif ini dihidupkan oleh <a href="http://www.pradosoft.com/demos/quickstart/?page=Database.ActiveRecord">Rekaman Aktif</a>.
+</p>
+
+<com:NoteBox>
+Untuk memudahkan, nama pengguna dalam sistem blg kita adalah tidak sensitif-huruf! Dalam banyak sistem praktis, nama pengguna mungkin perlu sensitif-huruf. Maka penanganan khusus perlu dibuat saat pembuatan akun pengguna baru dan juga <a href="?page=Day3.Auth">melakukan otentikasi</a>. Juga, ruang kosong dalam nama pengguna perlu dipotong ketika membuat akun baru dengan itu.
+</com:NoteBox>
+
+
+<h2>Pengujian</h2>
+<p>
+Untuk menguji halaman <tt>NewUser</tt>, kunjungi URL <tt>http://hostname/blog/index.php?page=users.NewUser</tt>. Kita akan melihat output halaman berikut. Coba masukan informasi berbeda ke dalam formulir dan lihat bagaimana input divalidasi. Jika semua aturan validasi memuaskan, kita akan mengharapkan akun pengguna dibuat dan browser dialihkan ke homepage.
+</p>
+
+<img src="<%~ output2.gif %>" class="output"/>
+
+
+<h2>Menambahkan Pemeriksaan Perijinan</h2>
+<p>
+Selama pengujian, anda mungkin bertanya: apakah halaman <tt>NewUser</tt> seharusnya hanya bisa diakses oleh pengguna administrator? Ya, ini disebut <a href="http://www.pradosoft.com/demos/quickstart/?page=Advanced.Auth">otorisasi</a>. Sekarang kami menjelaskan bagaimana kita menambahkan pemeriksaan perijinan ini ke halaman <tt>NewUser</tt>.
+</p>
+
+<p>
+Cara langsung pada pemeriksaan perijinan adalah dalam kelas halaman di mana kita memeriksa apakah <tt>$this->User->IsAdmin</tt> adalah true, dan jika tidak, kita mengalihkan browser ke halaman <tt>LoginUser</tt>.
+</p>
+
+<p>
+PRADO menawarkan cara lebih sistematis terhadap pemeriksaan perijinan akses halaman. Untuk melakukannyaTo , kita perlu menggunakan <a href="http://www.pradosoft.com/demos/quickstart/?page=Configurations.PageConfig">konfigurasi halaman</a>. Membuat sebuah file <tt>protected/pages/users/config.xml</tt> dengan konten seperti berikut:
+</p>
+
+<com:TTextHighlighter CssClass="source" Language="xml">
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <authorization>
+ <allow pages="NewUser" roles="admin" />
+ <deny users="?" />
+ </authorization>
+</configuration>
+</com:TTextHighlighter>
+
+<p>
+Konfigurasi halaman berisi aturan otorisasi yang berlaku untuk halaman di bawah direktori <tt>protected/pages/users</tt>. Konfigurasi di atas terbaca bahwa <tt>NewUser</tt> bisa diakses oleh para pengguna dengan aturan <tt>admin</tt> (lihat <a href="?page=Day3.Auth">BlogUser.createUser()</a> untuk alasan kenapa kata "admin"), dan menolak akses anonim (<tt>users="?"</tt> berarti pengguna tamu) untuk seluruh halaman di bawah direktori.
+</p>
+
+<p>
+Sekarang jika kita mengunjungi halaman <tt>NewUser</tt> sebagai seorang tamu, kita akan dialihkan ke halaman <tt>LoginUser</tt> terlebih dahulu. Jika kita masuk dengan sukses, kita akan mengalihkan kembali ke halaman<tt>NewUser</tt>.
+</p>
+
+<com:TipBox>
+Konfigurasi halaman dapat berisi lebih dari satu aturan otorisasi. Sebagai contoh, ia dapat menyertakan <a href="http://www.pradosoft.com/demos/quickstart/?page=Fundamentals.Modules">modul</a> seperti yang ktia lakukan dalam <a href="?page=Day2.ConnectDB">konfigurasi aplikasi</a>. Untuk aplikasi PRADO, setiap direktori halaman dapat mempunyai konfigurasi halaman yang berlaku bagi halaman dalam direktori yang sama dan seluruh subdirektorinya.
+</com:TipBox>
+
+</com:TContent> \ No newline at end of file
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/Overview.page b/demos/blog-tutorial/protected/pages/Day3/id/Overview.page
new file mode 100644
index 00000000..62c29438
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/Overview.page
@@ -0,0 +1,26 @@
+<com:TContent ID="Main">
+
+<h1>Tinjauan Manajemen Pengguna</h1>
+
+<p>
+Dalam bagian ini, kita membuat halaman yang terkait dengan manajemen pengguna. Dalam keadaan tertentu, kita mengimplementasikan fitur yang dibutuhkan ini: pengguna masuk/keluar, membuat akun pengguna baru dan memutakhirkan/menghapus akun pengguna.
+</p>
+
+<p>
+Berdasarkan kebutuhan, kita perlu membuat halaman berikut. Guna mengatur lebih baik kode kita, halaman terkait-pengguna ini akan dibuat di bawah direktori baru <tt>protected/pages/users</tt>.
+</p>
+
+<ul>
+ <li><tt>LoginUser</tt> menampilkan formulir login untuk memasukan pengguna.</li>
+ <li><tt>NewUser</tt> membuat akun pengguna baru.</li>
+ <li><tt>EditUser</tt> membolehkan pengguna teregistrasi memutakhirkan profilnya.</li>
+ <li><tt>AdminUser</tt> membolehkan administrator untuk mengatur akun pengguna, termasuk setelan tingkat perijinan dan menghapus akun pengguna.</li>
+</ul>
+
+<p>
+Setelah menyelesaikan bagian ini, kita mengharapkan bisa melihat direktori dan file berikut:
+</p>
+
+<img src="<%~ directories.gif %>" class="output" />
+
+</com:TContent> \ No newline at end of file
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/directories.gif b/demos/blog-tutorial/protected/pages/Day3/id/directories.gif
new file mode 100644
index 00000000..f59fda58
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/directories.gif
Binary files differ
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/output.gif b/demos/blog-tutorial/protected/pages/Day3/id/output.gif
new file mode 100644
index 00000000..0d812dd0
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/output.gif
Binary files differ
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/output2.gif b/demos/blog-tutorial/protected/pages/Day3/id/output2.gif
new file mode 100644
index 00000000..749255d6
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/output2.gif
Binary files differ
diff --git a/demos/blog-tutorial/protected/pages/Day3/id/output3.gif b/demos/blog-tutorial/protected/pages/Day3/id/output3.gif
new file mode 100644
index 00000000..a11ee653
--- /dev/null
+++ b/demos/blog-tutorial/protected/pages/Day3/id/output3.gif
Binary files differ