#!/bin/pozorny_ctenar :-) Systém pro CBS zobrazování fotek nahraných přes SVN =================================================== 1. Z pohledu uživatele ---------------------- Pro nahrávání fotek byl vytvořen SVN repozitář na URL svn+ssh://svn.orcave.com/Longredi. Veškeré fotky a adresáře se tedy ukládají tam. Tak jako ve všech repozitářích na svn.orcave.com, platí i tady osvědčené pravidlo: !!! Nepoužívat v názvech souborů a adresářů mezery, diakritiku, interpunkci a podobná zvěrstva !!! Po commitu může uživatel své fotky vidět na http://www.orcave.com/ v sekci "Podpora -> Fotodokumentace". K jejich prohlížení musí být přihlášen a mít příslušné ACL právo ("photos"). V levé části webu je stromeček adresářů a v pravé části náhledy fotek v akt. adresáři. Jednotlivým adresářům lze přidělovat atributy. Stačí do adresáře vložit soubor ".attrs" a do něj vepsat atributy ve tvaru "atribut:hodnota", na každý řádek jeden. Na základě hodnot atributů lze pak adresáře vyhledávat. Adresáři lze přidělit atributy libovolných názvů, ale v potaz se berou jen ty, které podporuje webová aplikace. 2. Z pohledu CBS ---------------- Kopie repozitáře (resp. SVN working copy) je uložena na IO serveru jako normální adresářová struktura se soubory. Každý adresář navíc obsahuje podadresář ".thumbs", kde jsou uloženy zmenšené náhledy fotek příslušného adresáře. O jejich vytváření se automaticky stará skript volaný při SVN commitu (viz TODO). Aby CBS mohlo z této struktury číst soubory a adresáře, byla vytvořena speciální knihovna: Modules\www\renderer_libs\StlcTpl_locfiles.lib.php Podstata této knihovny je taková, že ve filesystému na serveru lze některé adresáře označit aliasem a pak s nimi pracovat. Tyto aliasy a jim příslušející adresáře se definují v CbsOptions.php. Potom stačí se k adresáři přes alias "připojit" a pracovat v rámci jeho vnitřní struktury. Knihovna nijak neřeší práva pro přístup k těmto adresářům, to si musí programátor obstarat sám na úrovni TPL. Knihovna exportuje TPL příkazy: * locfiles.root alias Otevře se přístup do adresáře pod daným aliasem pro další práci. Ostatní příkazy lze používat až po zavolání locfiles.root, jinak by nevěděly, nad jakým adresářem pracovat. Není potřeba přístup po skončení práce jakkoli "uzavírat". Vrací 1 při úspěchu, jinak 0. * locfiles.dir tablename path [options] Přečte obsah adresáře 'path' (za kořen se považuje adresář otevřený příkazem locfiles.root) a uloží ho do TBL tabulky 'tablename' s několika sloupci: 'name' - obsahuje název souboru bez cesty 'mime' - mime-type souboru, u adresářů obsahuje nedefinovanou hodnotu 'type' - pro adresář má hodnotu 'd', pro soubor 'f' Parametr 'option' obsahuje kombinaci písmen 'd', 'f', 'a' (výchozí kombinace je 'df'): d - 'directories' - načtou se adresáře f - 'files' - načtou se ne-adresáře a - 'all' - načtou se i soubory začínající '.', které se jinak nenačítají Vrací 1 při úspěchu, jinak 0. * locfiles.dirTree tablename path [options] Přečte adresářovou strukturu s kořenem v 'path' a sestaví z ní tabulku, která je připravena k vytvoření TPL stromu, čili obsahuje sloupce 'node', 'parent', nicméně ještě to není TPL strom (aby bylo možno tabulku před vytvořením stromu filtrovat). Obsahuje sloupce 'name' (jméno adresáře) a 'full' (/celá/cesta). Parametr 'options' je podobný jako v locfiles.dir, ale písmena 'd' a 'f' nemají význam, čtou se vždy adresáře. * locfile.dirTreePrepare tablename Přidá do tabulky vytvořené fcí dirTree potřebné sloupce, aby tabulka mohla být zpracovávána jako TPL strom. * locfiles.fetch path Převede okamžitě na výstup obsah daného souboru a pošle HTTP hlavičku 'content-type' se správným MIME. Pozor, tato funkce posílá výstup i když nejsme v runlevelu 'render' v WWW modulu (právě kvůli nutnosti poslat HTTP hlavičku)! * locfiles.fetchTo path Vrátí obsah zadaného souboru. Nepřevádí ho okamžitě na výstup jako fce 'fetch', neřeší mime-type. Pro práci s atributy adresářů byla vytvořena knihovna: Modules\www\renderer_libs\StlcTpl_tablefilter.lib.php Tato knihovna umožňuje obecně odstraňovat z tabulky řádky, které obsahují určité atributy určitých hodnot. Co je to atribut? Do tabulky je přidán nový sloupec, který obsahuje v každém řádku vnořenou tabulku. Vnořená tabulka obsahuje sloupec 'attr' s názvem atributu a 'value' s jeho hodnotou. Tedy například: [id] | [jmeno] | [prijmeni] | [atributy] -------------------------------------------------------- 12 | Roman | Hocke | [attr] [value] | | | ---------------- | | | iq 157 | | | sex ano -------------------------------------------------------- 16 | Britney | Spears | [attr] [value] | | | ---------------- | | | iq ne -------------------------------------------------------- ... | ... | ... | ... Knihovna umí vyřazovat řádky, nesplňující v daném atributu danou hodnotu. T.j. lze například vyřadit všechny řádky, které v atributu 'oblibene-ovoce' neobsahují 'jablko'. Obsahovat znamená mít jako podřetězec, tedy například atribut 'oblibene-ovoce' s hodnotou 'jabka a hrušky' obsahuje 'jabka', obsahuje 'hru', obsahuje 'a a' a podobně. V praxi tedy například při hledání záznamu podle atributu 'ulice' lze vyfiltrovat např. na slovo 'palm' jak ulici 'Na palmovce', tak i 'Pod palmovkou' (ale taky třeba 'napalm' :-). Filtrování se skládá z několika kroků: 2.1. Řádkům tabulky se přidělí atributy. Atributy i s hodnotami jsou definovány v textovém řetězci, který vypadá např. takto: ?12 iq:157 sex:ano ?16 iq:ne ... V textu jsou dva druhy řádků: Řádky začínající '?' obsahují klíč, podle kterého se pozná, ke kterému řádku tabulky patří následující záznamy (který sloupec tabulky klíč představuje, si povíme za chvíli). Ostatní řádky textu obsahují dvojice 'atribut:hodnota'. Přiřazení hodnot se provádí příkazem: * tf.attributes table text id-column attr-column 'table' je název tabulky, jejímž řádkům chceme atributy přiřazovat, 'text' je textový blok, jehož syntaxe je popsána výše, 'id-column' je název sloupce, který slouží jako klíč pro přiřazování atributů z textového bloku (viz výše), 'attr-column' je název nově vytvořeného sloupce, do nějž se budou ukládat vnořené tabulky s hodnotami atributů. Tedy pro vytvoření výše uvedeného příkladu voláme: tf.attributes table text id atributy 2.2. Provádí se filtrování. To probíhá tak, že se vytvoří speciální sloupec, do kterého systém ukládá 1 nebo 0 podle toho, zda má být sloupec odstraněn. 1 nebo 0 ukládá na základě příkazu: * tf.filter table attr-column attr value 'table' je název filtrované tabulky, 'attr-column' je název sloupce, obsahujícího vnořené tabulky s atributy, 'attr' je název atributu, podle nějž filtrujeme a 'value' je hodnota, kterou musí atribut obsahovat, aby řádek nebyl vyřazen. Pokud řádek vůbec neobsahuje daný atribut, bude označen k vyřazení. Pokud daný atribut obsahuje, ale jeho hodnota neobsahuje hledaný výraz, bude řádek opět označen k vyřazení. Pokud je atribut dané hodnoty nalezen, nebude řádek nijak ovlivněn (to znamená, že pokud byl už z předchozího filtrování označen k vyřazení, zůstane vyřazen i nadále). Více filtrů za sebou na stejnou tabulku tedy probíhá AND-stylem, přežijí pouze řádky, které splňují všechny filtry. Pokud tabulka představuje strom, je potřeba zachovat konzistenci stromu. To znamená, že pokud nějaký řádek přežije filtrování, měli by zůstat zachováni i jeho rodiče a potomci. Rodiče proto, že bez nich by se potomek vůbec nezobrazoval (kde bychom byli bez rodičů... :-) a potomci proto, že když hledáme (proto filtrujeme) nějaký uzel, zřejmě nás zajímá jeho obsah, tedy jeho potomci. K této opravě stromu slouží funkce: * tf.filterTreeRepair table Tato funkce je poměrně náročná a proto se volá jen jednou jedinkrát po provedení všeho filtrování. 2.3. Nyní jsou tedy řádky tabulky rozděleny správně na ty, které mají zůstat a ty, které mají být vyřazeny. Tabulka však stále obsahuje řádky *všechny*, jako na začátku. Nyní je třeba odstranit odfiltrované řádky. To se provede funkcí: * tf.filterApply table Po provedení se smažou označené řádky. Jde-li o strom (tabulka obsahuje sloupec 'parent'), pak se automaticky provede 'prepair', který doplní tabulku o správné 'stromové' údaje (Ticons, Tchildren atd.) Tím je filtrování hotovo a s tabulkou či stromem lze dál normálně pracovat, jako by se nechumelilo. 3. Z pohledu WWW modulu ----------------------- Do webu Orcave byly přidány templaty: * Menu.Menu_photobucket - vykresluje strom adresářů * Photobucket.Filter - formulář pro filtrování záznamů * Photobucket.Main - vykresluje náhledy fotek v daném adresáři * Photobucket.Lister - vykresluje zvolenou fotku v plné velikosti a odkaz na předchozí / další * Workarea.photobucket - kostra layoutu * Getfile - slouží k zobrazení lokálního souboru přes web (locfiles.fetch) Také je dobré mít na webu přilinkován CSS styl 'share.design.style.photobucket'. 4. Z pohledu SVN a IO serveru ----------------------------- Uživatel provede commit na SVN server. Tento commit se zpracuje a je spuštěn post-commit hook, který přes SSH volá na IO serveru skripty, které zajistí vytvoření potřebných náhledů obrázků, smazání náhledů již neexistujících obrázků a podobně: I. SVN: commit II. SVN: post-commit hook volá přes SSH: III. IO: /home/photo/svn_post_commit, z něj se volá: IV. IO: /var/www/data/photos/update.sh Jádrem všeho je posledně jmenovaný skript update.sh. Ten obstará několik věcí: A. Provede update repozitáře z SVN do working copy na /var/www/data/photos/data/Longredi. V této working copy se v následujících krocích budou vytvářet náhledy obrázků v adresářích '.thumbs'. B. Z výstupu příkazu 'svn update' zjistí, ve kterých adresářích došlo ke změnám a tudíž v nich bude možná potřeba vygenerovat nové náhledy nebo smazat staré. C. K adresářům zjištěným v bodě B přidá ještě podadresáře těch adresářů, které byly zrovna z SVN smazány. Ty se totiž ve skutečnosti z working copy nevymazaly, neboť obsahují adresář '.thumbs' s náhledy (již neexistujících souborů) a ten není vůbec verzován (nenachází se v repozitáři, pouze ve working copy). Ty je samozřejmě také třeba smazat (viz E). D. Pro každý adresář z bodů B a C se zavolá skript /var/www/data/photos/thumbs.sh, který zajistí, že v daném adresáři bude adresář '.thumbs' s aktuálními náhledy. Vygeneruje tedy chybějící náhledy a smaže přebytečné (viz C), případně aktualizuje zastaralé. E. Smažou se všechny prázdné adresáře. To je potřeba jako úklid po adresářích, které se z SVN smazaly, ale z working copy dosud ne (viz C). F. Vygenerují se atributy jednotlivých adresářů. Co to znamená: Každý adresář může obsahovat soubor '.attrs', ve kterém jsou nějaké metainformace k adresáři ve tvaru 'atribut:hodnota' na řádcích pod sebou. Do kořene working copy se na základě těchto souborů vytvoří soubor '.attrs-tree', který shrnuje atributy všech adresářů na jediném místě ve tvaru: ?/cesta/k/adresari1 atribut:hodnota atribut:hodnota atribut:hodnota ?/cesta/k/adresari2 atribut:hodnota ?/a/tak/dale Dále je tu podpůrný skript /var/www/data/photos/checkout.sh, který se použije v případě, že by bylo potřeba celou working copy smazat a opět ji checkoutovat z SVN serveru. Vytvoří i potřebné náhledy. Po ní je třeba spustit ./reown.sh. Na IO serveru existuje účet 'photo', pod kterým všechny tyto SVN operace běží. Je tedy třeba, aby měl přístup pro čtení a zápis nad všemi soubory ve working copy, je proto nastaven jako jejich vlastník. K SVN serveru se připjuje s klíčem /home/photo/keys/key.