\title{Střední průmyslová škola elektrotechnická\\ a\,\,Vyšší odborná škola Pardubice}
\title{Střední průmyslová škola elektrotechnická\\ a\,\,Vyšší odborná škola Pardubice}
@ -178,11 +180,23 @@ Projekt je primárně cílen na anime fanoušky a\,\,ostatní znalce moderní Ja
\subsection{Administrace webu}
\subsection{Administrace webu}
Projekt má 3-úrovňovou, resp. 4-úrovňovou administraci. Jsou zde normální uživatelé, kteří jen pasivně konzumují obsah a\,\,nemají proto přístup nikam, kromě nastavení vlastního profilu. Pak zde jsou tvůrci -- uploadeři, kteří už nějak přispěli do databáze a\,\,mají tak veřejný status přispěvatele, ale navíc se jim uvolní pouze správa vlastních příspěvků v management prostředí. Dále zde jsou už zvolení moderátoři, kteří mají práva měnit příspěvky, přidávat, upravovat nebo mazat tagy a\,\,moderovat komentáře. Nemají však možnost komentáře definitivně mazat, takže uživatel má vždy možnost obsah upravit, aby komentář zase moderátor odblokoval. Admin má pak absolutní práva. Jediné jeho restrikce jsou neoprávněné změny uživatelských nastavení včetně jeho uživatelského jména.
Projekt má 3-úrovňovou, resp. 4-úrovňovou administraci. Jsou zde normální uživatelé, kteří jen pasivně konzumují obsah a\,\,nemají proto přístup nikam, kromě nastavení vlastního profilu. Pak zde jsou tvůrci -- uploadeři, kteří už nějak přispěli do databáze a\,\,mají tak veřejný status přispěvatele, ale navíc se jim uvolní pouze správa vlastních příspěvků v management prostředí. Dále zde jsou už zvolení moderátoři, kteří mají práva měnit příspěvky, přidávat, upravovat nebo mazat tagy a\,\,moderovat komentáře. Nemají však možnost komentáře definitivně mazat, takže uživatel má vždy možnost obsah upravit, aby komentář zase moderátor odblokoval. Admin má pak absolutní práva. Jediné jeho restrikce jsou neoprávněné změny uživatelských nastavení včetně jeho uživatelského jména.
\begin{figure}[h!]
\includegraphics[width=\linewidth]{usecase.png}
\caption{Use-case diagram}
\label{usecasediagram}
\end{figure}
\subsection{Databáze}\label{database}
\subsection{Databáze}\label{database}
Databáze se skládá ze 4 hlavních tabulek. Je tu tabulka \verb|user| v níž jsou uchovávány veškeré uživatelské informace, jako uživatelské jméno, email, hash hesla, jeho status oprávnění, status účtu a\,\,samozřejmě informace o jeho profilu s preferencí nejvyšší kategorie přístupnosti. Za pozornost stojí relace s tabulkou \verb|tags|, identifikující blacklist všech tagů, které uživateli nevyhovují a\,\,nechce je ve výpisu zobrazovat.
Databáze se skládá ze 4 hlavních tabulek. Je tu tabulka \verb|user| v níž jsou uchovávány veškeré uživatelské informace, jako uživatelské jméno, email, hash hesla, jeho status oprávnění, status účtu a\,\,samozřejmě informace o jeho profilu s preferencí nejvyšší kategorie přístupnosti. Za pozornost stojí relace s tabulkou \verb|tags|, identifikující blacklist všech tagů, které uživateli nevyhovují a\,\,nechce je ve výpisu zobrazovat.
Jako druhý nejhlavnější prvek tvoří tabulka \verb|post|, která má také navázáno nemalé množství relací. Obsahuje prakticky veškeré informace o nahraném obrázku jako např. md5 hash pro zajištění unikátnosti souboru, datový typ souboru, rozměry a\,\,velikost souboru jako užitečná informace pro uživatele, aby nebylo zapotřebí tyto parametry generovat během zpracování dotazu. Jako vyžadovaná informace, sloužící pro ověření pravosti a\,\,věrohodnosti během moderace příspěvku, je zde pak zdroj -- odkaz na stránku autora, nebo jinou stránku z níž mohl uživatel čerpat.
Jako druhý nejhlavnější prvek tvoří tabulka \verb|post|, která má také navázáno nemalé množství relací. Obsahuje prakticky veškeré informace o nahraném obrázku jako např. md5 hash pro zajištění unikátnosti souboru, datový typ souboru, rozměry a\,\,velikost souboru jako užitečná informace pro uživatele, aby nebylo zapotřebí tyto parametry generovat během zpracování dotazu. Jako vyžadovaná informace, sloužící pro ověření pravosti a\,\,věrohodnosti během moderace příspěvku, je zde pak zdroj -- odkaz na stránku autora, nebo jinou stránku z níž mohl uživatel čerpat.
\begin{figure}[h!]
\includegraphics[width=\linewidth]{erdiagram.png}
\caption{ER diagram}
\label{erdiagram}
\end{figure}
Jsou zde definované 3 základní kategorie přístupnosti. ,,Safe`` jako bezpečný pro všechny věkové kategorie, ,,Questionable``, pro obrázky které nevypadají úplně akceptovatelně, ale zase nepatří na 100\% do kategorie 18+ a\,\,pak ,,Explicit``, který není v žádném případě vhodný pro nezletilé osoby. Kategorie se rozlišuje subjektivně podle daného kontextu, ale vždy by se mělo dosáhnout podobného výsledku.
Jsou zde definované 3 základní kategorie přístupnosti. ,,Safe`` jako bezpečný pro všechny věkové kategorie, ,,Questionable``, pro obrázky které nevypadají úplně akceptovatelně, ale zase nepatří na 100\% do kategorie 18+ a\,\,pak ,,Explicit``, který není v žádném případě vhodný pro nezletilé osoby. Kategorie se rozlišuje subjektivně podle daného kontextu, ale vždy by se mělo dosáhnout podobného výsledku.
Každý příspěvek má svého uploadera v podobě instance typu \verb|user| a\,\,popř. approvera - moderátora, který zodpovídá za stav příspěvku. Další relace odkazuje na ,,parent`` \verb|post|, který by měl být nějakým způsobem/kompozicí příbuzný tomuto. Tímto se dostáváme k \verb|m:n| relaci (využívající vázací tabulku \verb|post_tags|) s tabulkou \verb|tags|, která definuje každý tag, který by měl daný obrázek vystihovat.
Každý příspěvek má svého uploadera v podobě instance typu \verb|user| a\,\,popř. approvera - moderátora, který zodpovídá za stav příspěvku. Další relace odkazuje na ,,parent`` \verb|post|, který by měl být nějakým způsobem/kompozicí příbuzný tomuto. Tímto se dostáváme k \verb|m:n| relaci (využívající vázací tabulku \verb|post_tags|) s tabulkou \verb|tags|, která definuje každý tag, který by měl daný obrázek vystihovat.
@ -227,8 +241,8 @@ $max-content-width: 1300px;
\cprotect\caption{Definice proměnných v \verb|main.scss|}
\cprotect\caption{Definice proměnných v \verb|main.scss|}
\end{listing}
\end{listing}
Hlavní indexová stránka obsahuje dynamicky se přizpůsobující výpis náhledů posledních nahraných obrázků, využívající speciálně postavený blok s\mintinline{css}|display: flex;| a\,\,\mintinline{css}|flex-flow: row wrap;|. Každý náhledový obrázek pak má speciální za běhu generovaný atribut \mintinline{css}|flex: * 1 *px;|\label{flexatribut} (kde \verb|*| identifikuje pixelovou šířku v poměru s minimální definovanou výškou), který zajišťuje, že se normalizuje jeho pixelová výška a\,\,budou se zobrazovat a\,\,zalamovat bez zbytečných mezer, tak jak mají.
Hlavní indexová stránka obsahuje dynamicky se přizpůsobující výpis náhledů posledních nahraných obrázků, využívající speciálně postavený blok s\,\,\mintinline{css}|display: flex;|\break a\,\,\mintinline{css}|flex-flow: row wrap;|. Každý náhledový obrázek pak má speciální za běhu generovaný atribut \mintinline{css}|flex: * 1 *px;|\label{flexatribut} (kde \verb|*| identifikuje pixelovou šířku v poměru s minimální definovanou výškou), který zajišťuje, že se normalizuje jeho pixelová výška a\,\,budou se zobrazovat a\,\,zalamovat bez zbytečných mezer, tak jak mají.
Přes veškerou snahu strávenou na tvorbě tohoto responzivního řešení, ve snaze napodobit web DeviantArt na str. \pageref{obdobne:3}, ale s využitím čistého CSS v kontrastu s jejich JavaScript řešením, tento způsob není dokonalý. Například obrázkům, postaveným na výšku, nedává vždy tolik zobrazovacího prostoru, takže jsou efektivně mnohem menší. Z toho je také odvozené, že pokud uživatel na vstupu nahraje obrázek s příliš exotickým poměrem stran, je možné, že se layout výpisu bude chovat nepředvídatelně.
Přes veškerou snahu strávenou na tvorbě tohoto responzivního řešení, ve snaze napodobit web DeviantArt (str. \pageref{obdobne:3}), ale s využitím čistého CSS v kontrastu s jejich JavaScript řešením, tento způsob není dokonalý. Například obrázkům, postaveným na výšku, nedává vždy tolik zobrazovacího prostoru, takže jsou efektivně mnohem menší. Z toho je také odvozené, že pokud uživatel na vstupu nahraje obrázek s příliš exotickým poměrem stran, je možné, že se layout výpisu bude chovat nepředvídatelně.
% SCREENSHOT - NÁHLED INDEX LAYOUTU
% SCREENSHOT - NÁHLED INDEX LAYOUTU
Aby se náhledy v posledním řádku na stránce neroztáhly na celou šířku, je tu pro jistotu přidaný pseudoelement \mintinline{css}|::after| zajišťující smrštění náhledů na levý bok.
Aby se náhledy v posledním řádku na stránce neroztáhly na celou šířku, je tu pro jistotu přidaný pseudoelement \mintinline{css}|::after| zajišťující smrštění náhledů na levý bok.
\begin{listing}[h]
\begin{listing}[h]
@ -349,13 +363,13 @@ Template \path{layout/management.html} obsahuje univerzální znovuužitelnou st
\end{listing}
\end{listing}
% MAIN INDEX
% MAIN INDEX
Hlavní template pro indexovou stránku v \path{post/index.html} obsahuje pouze jednoduchý výpis náhledů příspěvků. Adresa na zdroj obrázku je generována metodou\mintinline{python}|Post.url()|, která vždy vrátí správný formát podle \mintinline{python}|IMAGE_STORE| enumerátoru uvedeného jako argument.
Hlavní template pro indexovou stránku v \path{post/index.html} obsahuje pouze jednoduchý výpis náhledů příspěvků. Adresa na zdroj obrázku je generována metodou\break\mintinline{python}|Post.url()|, která vždy vrátí správný formát podle \mintinline{python}|IMAGE_STORE| enumerátoru uvedeného jako argument.
Výpis je v backendu limitován, proto je zde také import pro makro\mintinline{python}|render_pagination()| z \path{_includes.html}, které využije poskytnutého objektu\verb|Pagination| z dotazu na straně backendu. Implementovaný stránkovací mechanizmus umožňuje kompletní volnost v pohybu vpřed a\,\,vzad, poskytující i odkazy na sousední strany.
Výpis je v backendu limitován, proto je zde také import pro makro\break\mintinline{python}|render_pagination()| z \path{_includes.html}, které využije poskytnutého objektu\break\verb|Pagination| z dotazu na straně backendu. Implementovaný stránkovací mechanizmus umožňuje kompletní volnost v pohybu vpřed a\,\,vzad, poskytující i odkazy na sousední strany.
Stránka pro zobrazení jednoho příspěvku kromě postranního výpisu jeho parametrů a\,\,jednoduchého formuláře pro úpravu, obsahuje i komentářový výpis. Opět se zde v cyklu pro každý poskytnutý komentář volá makro ze soboru \path{_includes.html}, které tentokrát vrátí kompletní blok komentáře.
Stránka pro zobrazení jednoho příspěvku kromě postranního výpisu jeho parametrů a\,\,jednoduchého formuláře pro úpravu, obsahuje i komentářový výpis. Opět se zde v cyklu pro každý poskytnutý komentář volá makro ze soboru \path{_includes.html}, které tentokrát vrátí kompletní blok komentáře.
Stránka s formulářem pro upload příspěvků je zajímavá integrací dříve využitého tagového inputu, opět definovaného uvnitř \path{_includes.html}. Toto makro\mintinline{python}|render_tag_input()| jako argument vezme jednoduché \verb|wtforms| textové pole a\,\,přetvoří ho na přizpůsobený prvek, ovládaný skriptem \path{taginput.js}.
Stránka s formulářem pro upload příspěvků je zajímavá integrací dříve využitého tagového inputu, opět definovaného uvnitř \path{_includes.html}. Toto makro\break\mintinline{python}|render_tag_input()| vezme jako argument jednoduché \verb|wtforms| textové pole a\,\,přetvoří ho na přizpůsobený prvek, ovládaný skriptem \path{taginput.js}.
\subsection{Backend}
\subsection{Backend}
@ -392,7 +406,7 @@ Blueprint \verb|bp/auth.py| se nakonec stará o přihlášení a\,\,registrace.
\paragraph{Formuláře}
\paragraph{Formuláře}
Pro zelegantnění práce s formuláři napříč projektem využívám Python balíček \verb|wtforms|. Ten umožňuje snadnou definici univerzálních formulářů s možností validace polí a\,\,případné reportování nalezených chyb. Má také částečně integrovanou ochranu před CSRF útoky pomocí skrytého formulářového pole.
Pro zelegantnění práce s formuláři napříč projektem využívám Python balíček \verb|wtforms|. Ten umožňuje snadnou definici univerzálních formulářů s možností validace polí\break a\,\,případné reportování nalezených chyb. Má také částečně integrovanou ochranu před CSRF útoky pomocí skrytého formulářového pole.
Definici všech užitých formulářů lze nalézt v souboru \path|forms.py|
Definici všech užitých formulářů lze nalézt v souboru \path|forms.py|
\paragraph{Přístup do databáze}
\paragraph{Přístup do databáze}
Do databáze přistupuji pomocí SQLAlchemy Object Relation Mapperu. Mohu si tak definovat tabulky přímo jako třídy a\,\,manipulovat s nimi pomocí třídy SQLAlchemy. Pro jednoduchý SELECT všech záznamů modelu \verb|Post| mi postačí zavolat\mintinline{python}|Post.query.all()| (zkratka pro \mintinline{python}|db.session.query(Post).all()|) a\,\,vrátí se mi list instancí objektu \verb|Post|, s nímiž mohu dále manipulovat.
Do databáze přistupuji pomocí SQLAlchemy Object Relation Mapperu. Mohu si tak definovat tabulky přímo jako třídy a\,\,manipulovat s nimi pomocí třídy SQLAlchemy. Pro jednoduchý SELECT všech záznamů modelu \verb|Post| mi postačí zavolat\break\mintinline{python}|Post.query.all()| (zkratka pro \mintinline{python}|db.session.query(Post).all()|) a\,\,vrátí se mi list instancí objektu \verb|Post|, s nímiž mohu dále manipulovat.
Definice pomocí modelů mi umožňuje definovat vlastní metody na daném objektu pro provádění užitečných operací. Výborným příkladem je funkce generující \verb|flex| CSS atribut pro náhledy ve výpisu na hlavní stránce (na str. \pageref{flexatribut}).
Definice pomocí modelů mi umožňuje definovat vlastní metody na daném objektu pro provádění užitečných operací. Výborným příkladem je funkce generující \verb|flex| CSS atribut pro náhledy ve výpisu na hlavní stránce (na str. \pageref{flexatribut}).
%\begin{listing}[h]
%\begin{listing}[h]
@ -543,11 +557,55 @@ class EditForm(CSRFForm):
\cprotect\caption{Abstraktní třída formuláře \verb|EditForm|}
\cprotect\caption{Abstraktní třída formuláře \verb|EditForm|}
\end{listing}
\end{listing}
V endpointech pro zpracování poskytnutých dat tak lze podle jména odeslaného pole typu \verb|submit| rozhodovat, která operace se provede. Kromě užitých dekorátorů\mintinline{python}|@loginrequired| jsou i zde použity i dekorátory \mintinline{python}|@moderatorrequired| a\,\,\mintinline{python}|@adminrequired|, implementované v modulu s modely. Je zde kromě bodů pro modifikaci příspěvků, tagů a\,\,uživatelů umístěný i endpoint pro moderaci komentářů, která je však zatím dostupná pouze ze stránky příslušného příspěvku.
V endpointech pro zpracování poskytnutých dat tak lze podle jména odeslaného pole typu \verb|submit| rozhodovat, která operace se provede. Kromě užitých dekorátorů\break\mintinline{python}|@loginrequired| jsou i zde použity i dekorátory \mintinline{python}|@moderatorrequired|\break a\,\,\mintinline{python}|@adminrequired|, implementované v modulu \path{models.py}. Je zde kromě bodů pro modifikaci příspěvků, tagů a\,\,uživatelů umístěný i endpoint pro moderaci komentářů, která je však zatím dostupná pouze ze stránky příslušného příspěvku.
%\subsection{Deployment}
%\subsection{Deployment}
\section{Závěr}
\section{Závěr}
% Tento projekt byl
Tento projekt vznikl jako proof-of-concept, že lze za pomoci velice málého množství použitých frontendových knihoven napsat poměrně moderně vypadající, rychlé a spolehlivé rozhraní. Jako původní myšlenka sloužil fakt, že web v dnešní době je nezkutečně pomalý a pomalu nelze nalézt stránku, která by se zobrazila správně bez zapnutého JavaScriptu. Jako hrdý člen open-source komunity si cením svého internetového soukromí a ocením každou službu, kterou si mohu ,,zahostovat`` na vlastním hardware bez závislosti na externích poskytovatelích.
Také musím zmínit, že jsem se mnohé na tomto projektu naučil. Jde zatím o nejrozsáhlejší aplikaci, na níž jsem kdy pracoval, takže párkrát jsem poznal svou nezkušenost s Flaskem, ale i obecnou strukturizací kódu. Hodně mi dalo zabrat, než jsem se naučil převádět regulérní SQL dotazy do SQLAlchemy notace, ale nakonec jsem stejně dosáhl akceptovatelných řešení. Program pořád není dokonalý a na některých místech může být poměrně neefektivní, i přesto, že jsem se snažil o nejvyšší úroveň optimalizace.
Tyto stránky asi do budoucna už neplánuji rozšiřovat, ale díky nabraným poznatkům jsem schopen se do příště vyvarovat chybám, které jsem na designu tohoto software udělal.