Publishboard: a drupal.hu szerkesztőségi segítője

A Drupal.hu indulásakor a webhely egyik funkciója az új tartalmak beérkezése esetén az adminisztrátorok értesítése (notify) volt. Ezt egyrészt a megnövekedett link beküldés szám, másrészt pedig az akkor használt modul hátrahagyottsága (a frissítés elmaradása miatt) nem használtuk tovább. Így viszont, és a kis szerkesztőség kevés idejének is betudhatóan nem követtük a beérkező tartalmakat, sokszor külön emailben értesültünk, hogy valamilyen cikket vagy hírt most már át kellene nézni, és meg kellene jelentetni.

Amikor a drupal.hu szerkesztőségét bővítettük (mely ma már a legtöbb kiemelten aktív drupal.hu tagot magában foglalva hét tagot számlál), ez a gond még erősebben jelentkezett. Úgy döntöttünk, hogy email értesítés helyett folyamatosan szem előtt lévő összefoglalót alakítunk ki. Ennek a fejlesztését én vállaltam, s a néhány hónapja használt Publishboard modulunk meglátásom szerint beváltotta a hozzá fűzött reményeket.


A publishboard blokk megjelenése

A feladat tehát a beküldött tartalmak összefoglalása volt, hogy értesülhessünk a beküldött új tartalmakról, és minél hamarabb cselekedhessünk ezeket illetően. Természetesen belefoghattunk volna valamilyen általános modullal összevarázsolni a saját eszközünket, de az eredményként született jól kommentezve is csupán 115 soros modul karcsúbb és célratörőbb lett.

Először is természetesen szükségünk volt egy .info fájlra a modulhoz:


name = Publishboard
description = Beküldött tartalmak kezelését segíti
package = "Drupal.hu"
core = 6.x

Itt látszik, hogy a drupal.hu számára kifejlesztett moduljainkat egy csomagban fogjuk össze.

A számunkra lényeges információ az, hogy mennyi még megjelenésre váró tartalom van, illetve ezek közül mennyi új és régi. Drupal terminológiával most újnak tekintünk minden tartalmat, amit az aktuálisan belépett felhasználó még nem látott vagy amióta látta, azóta változtattak rajta. Ennek érdekében a következő összesítő kódot alakítottuk ki:

/**
* A nem olvasott tartalmak számának összesítése.
*/
function publishboard_unread_counters() {
global $user;
// Üres tömbökkel indulunk.
$unchanged = $changed = $list = $types = array();
// Az összes most nem közzétett node néhány adatára van szükség és a típusaik listájára.
$result = db_query('SELECT nid, type, changed FROM {node} WHERE status = 0');
while ($node = db_fetch_object($result)) {
$list[$node->nid] = $node;
if (!in_array($node->type, $types)) {
$types[] = $node->type;
}
}
// Ha van bármilyen nem közzétett tartalom.
if (count($types)) {
// Nézzük, hogy az éppen látogató felhasználó melyeket látta már ezekből legutóbbi
// módosításuk óta (melyek így tényleg újak a számára). Az IN() tartalma biztos számokból áll
// a fenti kód alapján, ezért azt biztonságos az SQL-ben közvetlenül használni.
$part = join(", ", array_keys($list));
$result = db_query("SELECT nid, timestamp FROM {history} WHERE uid = %d AND nid IN ($part)", $user->uid);
while($history = db_fetch_object($result)) {
if ($list[$history->nid]->changed > $history->timestamp) {
// Van róla adatunk, és régebben látta, mint amikor legutóbb változott.
$changed[$list[$history->nid]->type]++;
}
else {
// Volt róla adat, de a változás régebbi, mint a látogatás.
$unchanged[$list[$history->nid]->type]++;
}
// Kezeltük a history tábla alapján.
unset($list[$history->nid]);
}
}
// Ezeket nem találtuk meg a history táblában, azaz soha nem látta a user,
// vagy nagyon régen látta, és már a history táblában nincs benne a bejegyzés.
// Csak a limitet tudjuk alapul venni az ellenőrzéshez.
foreach ($list as $node) {
if ($list[$node->nid]->changed > NODE_NEW_LIMIT) {
$changed[$node->type]++;
}
else {
$unchanged[$node->type]++;
}
}
// A típusok listájával és a számolások eredményével térünk vissza.
return array($types, $changed, $unchanged);
}
?>

Ezekről az adatokról egy emberileg olvasható blokkban szeretnénk információkat megjeleníteni:

/**
* hook_block() megvalósítás.
*/
function publishboard_block($op = 'list', $delta = 0, $edit = array()) {
if ($op == 'list') {
// Egy blokkot biztosítunk a rendszer számára.
return array(0 => array('info' => 'Beküldött tartalmak',
'weight' => -100, 'enabled' => 1, 'region' => 'right'));
}
elseif ($op == 'view' && user_access("access administration pages")) {
// Csak adminisztrátoroknak mutatjuk meg ezt a blokkot.
$items = array();
// Emberek számára olvasható nevek praktikusabbak, mint a gépi nevek.
$names = node_get_types('names');
// Alapadatok lekérdezése.
list($types, $changed, $unchanged) = publishboard_unread_counters();
foreach ($types as $type) {
$title = '';
// Elvileg valamelyik be van állítva, de azért menjünk biztosra.
if (isset($unchanged[$type]) || isset($changed[$type])) {
if (isset($unchanged[$type])) {
$title .= $unchanged[$type] .' régi'. (isset($changed[$type]) ? ', ' : ' ');
}
if (isset($changed[$type])) {
$title .= $changed[$type] .' új ';
}
$items[] = l($title . $names[$type], 'publishboard/'. $type);
}
}
if (count($items)) {
// Vannak megjelenítendő linkek.
return array(
'subject' => 'Beküldött tartalmak',
'content' => theme('item_list', $items),
);
}
}
}
?>

A blokk funkciója természetesen nem csak az információ átadása, hanem a szerkesztőség segítése is, tehát olyan linkeket kellett kialakítani, amik az adminisztrációs felület megfelelő oldalára vezetnek. A tartalmak kezelőfelülete azonban nem linkelhető a webcímbe helyezett olyan kritériumokkal, mint, hogy adott típusú, nem publikált tartalmakra van szükségünk. Ezért kellett bevezetni az előző kódban látható publishboard címen a köztes oldalunkat, ami a megfelelő beállításokkal átirányít a tartalmak adminisztrációs oldalára.

/**
* hook_menu() megvalósítás.
*/
function publishboard_menu($may_cache) {
$items = array();
// Cached menu items
if (!$may_cache) {
$items[] = array(
'path' => 'publishboard',
'title' => 'Beküldött tartalmak',
'callback' => 'publishboard_page',
'access' => user_access("access administration pages"),
'type' => MENU_CALLBACK,
);
}
return $items;
}
?>

Itt egy menüben meg nem jelenő, a publishboard_page()-et hívó webcím kezelőt állítottunk be. Az pedig egyszerűen:

function publishboard_page($type) {
// A tartalom lista szűrése meg nem jelent $type típusú elemekre, a node.module kódja alapján.
$_SESSION['node_overview_filter'] = array(
array('status', 'status-0'),
array('type', $type),
);
// Átirányítás a céloldalra.
drupal_goto('admin/content/node');
}
?>

Ennyivel meg is oldottuk a funkcionalitást. Rendelkezésünkre áll egy blokk, ami kijelzi a meg nem jelent tartalmakat, és a linkekre kattintva az adminisztrációs felületre vezet. Bekapcsolhatjuk a blokkot akár minden felhasználó számára, hiszen maga a blokk akadályozza meg, hogy nem adminisztrátorok részére is láthatóvá válljon. Számunkra még egy fontos elem volt: emeljük ki a blokkot a többi közül, megkönnyítve a szemünk számára a blokk azonosítását. Ezt a következő egyszerű CSS szabályok sminkünkbe helyezésével értük el:


/* Publishboard */
#sidebar #block-publishboard-0 {
background-color: #ffc;
padding: 0.8em;
}
#sidebar #block-publishboard-0 .item-list ul {
margin: 0;
}
#sidebar #block-publishboard-0 a {
color: #036;
font-weight: bold;
}

Ezzel egy figyelemfelkeltő sárga háttérrel megjelenő blokkot kaptunk, mely a fent látott módon fest.