Tutorial Step 3 - Adding Admin Functionalities

This tutorial step should show us how to create basic administrator functionalities with adding new items, editing the existing ones and deleting them.

Deleting items

Having the adding items functionality ready we should feel that other features, such as deleting and updating should not be very hard to implement.

Let's start from the dispatcher rules. Add the following entry to the dispatch.conf file:

   1 {dynamic, "^/item/delete/(?<id>[0-9]+)$", {item_admin, delete}}.

And then edit the item_admin.erl created in the previous step:

   1 -export([delete/1]).
   2 
   3 ...
   4 
   5 delete(Args) ->
   6     Id = list_to_integer(proplists:get_value(id, Args)),
   7     wtype_item:delete(Id),
   8     
   9     {redirect, "/item/all"}.

Great! That's all - the service should be ready for handling the delete requests.

Assume we had three items in our shop:

all1.png

The last item (Form generated one) had an ID = 3. We went to http://localhost:8080/item/delete/3, controller deleted the item and redirected us to /item/all:

all2.png

Editing items

Our shop is getting better and better, but we still do not have the possibility to edit the particular items. If we made a mistake during the description of an item (or the item became unavailable) we have to remove it from the service and enter the same (but corrected) data once again. Unfortunately, its ID will be different since it is automatically assigned during the save phase (it is true only when we are passing the record with its first field set to undefined atom - otherwise the ID set by user will remain the same).

To change it, at first edit the dispatcher configuration file:

   1 {dynamic, "^/item/edit/(?<id>[0-9]+)$", {item_admin, edit}}.
   2 {dynamic, "^/item/do_edit$", {item_admin, do_edit}}.

Then add the following functions to the item_admin.erl controller:

   1 -export([edit/1, do_edit/1]).
   2 
   3 ...
   4 
   5 edit(Args) ->
   6     Id = list_to_integer(proplists:get_value(id, Args)),
   7     wpart:fset("__edit", wpart_db:build_record_structure(item, wtype_item:read(Id))),
   8     wpart:fset("__primary_key", Id),
   9     
  10     {template, "item/edit.html"}.
  11 
  12 do_edit(_Args) ->
  13     case validate_tool:validate_cu(item, create) of
  14         {ok, Item} ->
  15             wtype_item:update(Item),
  16             {redirect, "/item/all"};
  17         {error, _Reason} ->
  18             %% Make sure to set the primary key of this item
  19             wpart:fset("__primary_key", list_to_integer(wpart:fget("post:__primary_key"))),
  20             wpart:fset("__edit", wtype_item:prepare_validated()),
  21             {template, "item/edit.html"}
  22     end.

And at the end we should prepare item/edit.html template file:

<html>
<head>
  <title>Editing an item</title>
  <link rel="stylesheet" type="text/css" href="/style.css" />
</head>
<body>
  <h1>Editing an item</h1>
  <wpart:form type="item" action="/item/do_edit" />
</body>
</html>

As you have probably noticed, both do_add}} - {{{do_edit and add.html - edit.html looks very but very similar - they differs only in the actions they call - the structure remains the same.

The editing functionality has been split in the two parts: in the first one, when we enter the address /item/edit/N we have to load the entry from the database and initialize the form with its fields' values. In the second step we save the modified content.

The result of our work could be seen when we enter e.g. http://localhost:8080/item/edit/2:

edit1.png

Let's make this item available and change its price to 12.5. After successful validation we should have been redirected to the all items page and notice there is no longer "NOT AVAILABLE" marker next to the second item. When we enter to its address we will see the modified entry:

edit2.png

Gathering all admin functionalities in one place

So far we have written three functionalities that modifies the content of the database: create, edit and delete item functionalities. In order to avoid the mess in our project we should separate the admin features from the normal, ordinary services, such as displaying an item description or listing all items.

As a first step we should separate the admin dispatcher entries from the normal user ones. Dispatcher configuration file allows us to delegate some kind of entries to the other files (see dispatcher wiki page - delegate entry type). We should then create an additional folder inside the config directory - let it be config/dispatcher and add there a new file: admin.conf:

   1 {static, "add$", "item/add.html"}.
   2 {dynamic, "do_add$", {item_admin, do_add}}.
   3 {dynamic, "delete/(?<id>[0-9]+)$", {item_admin, delete}}.
   4 {dynamic, "edit/(?<id>[0-9]+)$", {item_admin, edit}}.
   5 {dynamic, "do_edit$", {item_admin, do_edit}}.

All of the corresponding entries in the dispatch.conf file should be shrink into one delegate entry:

   1 {dynamic, delegate, "^/item/admin/", "config/dispatcher/admin.conf"}.

From now, all the URLs that start from /item/admin/ will be matched against the rules held in config/dispatcher/admin.conf file.

There will be then five classes of admin URLs:

We should then change the URLs that are bound to the actions in the HTML files (from /item/do_add to /item/admin/do_add in add.html and from /item/do_edit to /item/admin/do_edit in edit.html).

Download

This tutorial step is over, the package containing the sources of the application can be downloaded from here.

Tutorial/Step3_AdminPanel (last edited 2009-10-19 02:02:27 by JustinHenzie)