master
Jan Kužílek 5 years ago
parent 1fdae19f0a
commit c1a7cf7f99

Binary file not shown.

@ -10,6 +10,7 @@
\usepackage{blindtext} \usepackage{blindtext}
\usepackage{listings} \usepackage{listings}
% \renewcommand\listingscaption{Blok kódu} % \renewcommand\listingscaption{Blok kódu}
\lstset{breaklines=true}
\usepackage{cprotect} \usepackage{cprotect}
\usepackage{minted} \usepackage{minted}
@ -25,7 +26,7 @@
\usepackage{url} \usepackage{url}
\author{Jan Kužílek} \author{Jan Kužílek}
\title{Střední průmyslová škola elektrotechnická\\ a Vyšší odborná škola Pardubice} \title{Střední průmyslová škola elektrotechnická\\ a\,\,Vyšší odborná škola Pardubice}
\renewcommand*\contentsname{Obsah} \renewcommand*\contentsname{Obsah}
@ -35,7 +36,7 @@
\begin{titlepage} \begin{titlepage}
\begin{center} \begin{center}
\large{Střední průmyslová škola elektrotechnická\\ a Vyšší odborná škola Pardubice} \large{Střední průmyslová škola elektrotechnická\\ a\,\,Vyšší odborná škola Pardubice}
\vspace{2cm} \vspace{2cm}
\large\textbf{STŘEDNÍ PRŮMYSLOVÁ ŠKOLA ELEKTROTECHNICKÁ} \large\textbf{STŘEDNÍ PRŮMYSLOVÁ ŠKOLA ELEKTROTECHNICKÁ}
@ -54,11 +55,11 @@
\vspace*{\fill} \vspace*{\fill}
\textit{ \textit{
,,Prohlašuji, že jsem maturitní práci vypracoval(a) samostatně a použil(a) jsem literárních pramenů, informací a obrázků, které cituji a uvádím v seznamu použité literatury a zdrojů informací a v seznamu použitých obrázků a neporušil jsem autorská práva. ,,Prohlašuji, že jsem maturitní práci vypracoval(a) samostatně a\,\,použil(a) jsem literárních pramenů, informací a\,\,obrázků, které cituji a\,\,uvádím v seznamu použité literatury a\,\,zdrojů informací a\,\,v seznamu použitých obrázků a\,\,neporušil jsem autorská práva.
} }
\textit{ \textit{
Souhlasím s umístěním kompletní maturitní práce nebo její části na školní internetové stránky a s použitím jejich ukázek pro výuku.`` Souhlasím s umístěním kompletní maturitní práce nebo její části na školní internetové stránky a\,\,s použitím jejich ukázek pro výuku.``
} }
\vspace{1cm} \vspace{1cm}
@ -66,10 +67,21 @@
V pardubicích dne {\dotfill}{\hfill}Podpis: {\dotfill} V pardubicích dne {\dotfill}{\hfill}Podpis: {\dotfill}
\pagebreak \pagebreak
\pagenumbering{arabic} \begin{figure}[h!]
\hspace{0.05\linewidth}
% \includegraphics[width=0.9\linewidth]{images/Zadani1.png}
\end{figure}
\pagebreak
\begin{figure}[h!]
\hspace{0.05\linewidth}
% \includegraphics[width=0.9\linewidth]{images/Zadani2.png}
\end{figure}
\pagebreak
\section*{Anotace} \section*{Anotace}
YaDc - Moderní ImageBoard pro moderní lidi. Sdílej a stahuj moderované obrázky a tapety s Anime/Manga tématikou. YaDc - Moderní ImageBoard pro moderní lidi. Sdílej a\,\,stahuj moderované obrázky a\,\,tapety s Anime/Manga tématikou.
Klíčová slova: imageboard, anime, manga, tapety, obrázky Klíčová slova: imageboard, anime, manga, tapety, obrázky
\pagebreak \pagebreak
@ -80,18 +92,23 @@ YaDc - Modern ImageBoard for modern people. Share and download curated Anime/Man
Keywords: imageboard, anime, manga, wallpapers, pictures Keywords: imageboard, anime, manga, wallpapers, pictures
\pagebreak \pagebreak
\tableofcontents \tableofcontents
\pagebreak \pagebreak
\pagenumbering{arabic}
\setcounter{page}{8}
\addcontentsline{toc}{section}{Úvod} \addcontentsline{toc}{section}{Úvod}
\section*{Úvod} \section*{Úvod}
Projekt umožňuje uživatelům sdílet obrázky ve formě příspěvků, které budou mít přiřazené kategoricky roztříděné tagy, věkovou přístupnost a další parametry. Před oficiálním akceptováním příspěvku bude každý obrázek patřičně zkontrolován moderátory a označen jako validní. Každý obrázek je volně přístupný ke stažení v původním formátu i zmenšené verzi formátu JPEG. Kromě toho může každý uživatel u příspěvku napsat vlastní komentář. Projekt umožňuje uživatelům sdílet obrázky ve formě příspěvků, které budou mít přiřazené kategoricky roztříděné tagy, věkovou přístupnost a\,\,další parametry. Před oficiálním akceptováním příspěvku bude každý obrázek patřičně zkontrolován moderátory a\,\,označen jako validní. Každý obrázek je volně přístupný ke stažení v původním formátu i zmenšené verzi formátu JPEG. Kromě toho může každý uživatel u příspěvku napsat vlastní komentář.
Cílem bylo vytvořit modulární moderovaný imageboard systém s filtrovatelným obsahem jednoho zaměření, které se dá dle instance přizpůsobit, s použitelným API, které umožní stavět aplikační klienty pro propojení s ostatními sociálními službami. Backend projektu je postavený na mikroframeworku Flask, běžícím v Pythonu, čímž je možné dosáhnout vyšší modulárnosti s možností v budoucnu implementovat další užitečné funkce. Cílem bylo vytvořit modulární moderovaný imageboard systém s filtrovatelným obsahem jednoho zaměření, které se dá dle instance přizpůsobit, s použitelným API, které umožní stavět aplikační klienty pro propojení s ostatními sociálními službami. Backend projektu je postavený na mikroframeworku Flask, běžícím v Pythonu, čímž je možné dosáhnout vyšší modulárnosti s možností v budoucnu implementovat další užitečné funkce.
Motivací byla převážně absence moderně vypadajícího, self-hostovatelného systému, zaměřeného na sdílení a třídění obrázků a pozadí plochy. Motivací byla převážně absence moderně vypadajícího, self-hostovatelného systému, zaměřeného na sdílení a\,\,třídění obrázků a\,\,pozadí plochy.
Frontend je moderní, přesto minimalistický, umožňující rychlé prohlížení a stahování obrázků. Je postavený s myšlenkou jednoduchosti a nezávislosti na přebytečných knihovnách jako je Bootstrap nebo jQuery. Frontend je moderní, přesto minimalistický, umožňující rychlé prohlížení a\,\,stahování obrázků. Je postavený s myšlenkou jednoduchosti a\,\,nezávislosti na přebytečných knihovnách jako je Bootstrap nebo jQuery.
% FIX BOOTSTRAP % FIX BOOTSTRAP
\pagebreak \pagebreak
@ -100,7 +117,7 @@ Frontend je moderní, přesto minimalistický, umožňující rychlé prohlíže
\begin{itemize} \begin{itemize}
\item[Adresa] \url{https://konachan.net} \item[Adresa] \url{https://konachan.net}
\end{itemize} \end{itemize}
Konachan.net běží na projektu Moebooru\footnote{\url{https://github.com/moebooru/moebooru}}, hluboce modifikovaném forku Danbooru\footnote{\url{https://github.com/r888888888/danbooru}}. Je napsán v ne-úplně standardním frameworku Ruby on Rails, který ve výsledku jenom zhoršuje rozšiřitelnost projektu. Nabízí moderovaný systém obrazových příspěvků, filtrovatelný pomocí tagů, s komentáři u každého příspěvku, rozsáhlým API a spoustou dalších funkcí. Frontend je jednoduchý, nabízející docela pohodlné prohlížení na desktopu, avšak neresponzivní, takže na mobilních zařízeních takřka nepoužitelný. Konachan.net běží na projektu Moebooru\footnote{\url{https://github.com/moebooru/moebooru}}, hluboce modifikovaném forku Danbooru\footnote{\url{https://github.com/r888888888/danbooru}}. Je napsán v ne-úplně standardním frameworku Ruby on Rails, který ve výsledku jenom zhoršuje rozšiřitelnost projektu. Nabízí moderovaný systém obrazových příspěvků, filtrovatelný pomocí tagů, s komentáři u každého příspěvku, rozsáhlým API a\,\,spoustou dalších funkcí. Frontend je jednoduchý, nabízející docela pohodlné prohlížení na desktopu, avšak neresponzivní, takže na mobilních zařízeních takřka nepoužitelný.
\paragraph{Kladné stránky} \paragraph{Kladné stránky}
\begin{itemize} \begin{itemize}
\item klasický vzhled imageboard, bez zbytečností, které by jinak zpomalovaly stránku \item klasický vzhled imageboard, bez zbytečností, které by jinak zpomalovaly stránku
@ -119,7 +136,7 @@ Konachan.net běží na projektu Moebooru\footnote{\url{https://github.com/moebo
\begin{itemize} \begin{itemize}
\item[Adresa] \url{https://www.pixiv.net} \item[Adresa] \url{https://www.pixiv.net}
\end{itemize} \end{itemize}
Pixiv je kompletní, (převážně v Japonsku) populární platforma/sociální síť zaměřená na tvůrce ilustrací, mangy a knižních novel. Obsahuje žebříčky nejlepších, přizpůsobuje zobrazovaný obsah podle zájmů uživatele. Pixiv je kompletní, (převážně v Japonsku) populární platforma/sociální síť zaměřená na tvůrce ilustrací, mangy a\,\,knižních novel. Obsahuje žebříčky nejlepších, přizpůsobuje zobrazovaný obsah podle zájmů uživatele.
\paragraph{Kladné stránky} \paragraph{Kladné stránky}
\begin{itemize} \begin{itemize}
\item moderní, responzivní vzhled \item moderní, responzivní vzhled
@ -154,24 +171,29 @@ Deviantart je centralizovaná platforma pro tvůrce pro publikování své uměl
\section{Návrh projektu} \section{Návrh projektu}
\subsection{Cílové skupiny} \subsection{Cílové skupiny}
Projekt je primárně cílen na anime fanoušky a ostatní znalce moderní Japonské tvorby, kteří ocení open-source moderovanou platformu pro obrazovou tvorbu v nejvyšší/původní kvalitě. Primární využití by mělo být uchovávání/archivování tvorby do budoucna s transparentním přístupem pro kohokoli. Projekt je primárně cílen na anime fanoušky a\,\,ostatní znalce moderní Japonské tvorby, kteří ocení open-source moderovanou platformu pro obrazovou tvorbu v nejvyšší/původní kvalitě. Primární využití by mělo být uchovávání/archivování tvorby do budoucna s transparentním přístupem pro kohokoli.
% Za zmínku stojí i možnost přístupu přes Danbooru API. % Za zmínku stojí i možnost přístupu přes Danbooru API.
%Stránky jsou napsány %Stránky jsou napsány
\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.
\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.
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.
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, kategorii přístupnosti, tagy a zdroj/odkaz na stránku autora. 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.
Tabulka \verb|tags| je jednoduchá. Je definována unikátním názvem tagu a jeho kategorií. Tabulka \verb|tags| je jednoduchá. Je definována unikátním názvem tagu a\,\,jeho kategorií. Tagových kategorií je přesně 6. Vyjadřují typ tagu ve vztahu s obsahem příspěvku tak, aby to v budoucnu umožnilo jednodušší parsování databáze, ale i vizuálního rozlišení.
% Typy/kategorie tagů % Typy/kategorie tagů
Kromě tagů je k tabulce \verb|post| i \verb|user| připojená tabulka \verb|comment|, implementující uživatelské komentáře u příspěvku. Obsahuje vlastní obsah zprávy a vlastnost deleted, pokud byl komentář zablokován moderátorem. Kromě tagů je k tabulce \verb|post| i \verb|user| připojená tabulka \verb|comment|, implementující uživatelské komentáře u příspěvku. Obsahuje vlastní obsah zprávy a\,\,vlastnost deleted, pokud byl komentář zablokován moderátorem.
\subsection{Design a responzivita} \subsection{Design a\,\,responzivita}
Jedna z původních myšlenek bylo zachovat klasický imageboard formát, ale přinést trochu vylepšení v podobě responzivity a moderních designových prvků. Veškeré styly jsou zde řešené pomocí CSS, resp. SCSS stylovacího jazyka a miniaturní knihovny \verb|include-media|\footnote{\url{https://eduardoboucas.github.io/include-media/}}, starající se o elegantnější řešení rezponzivity za pomoci CSS Media Queries. Jedna z původních myšlenek bylo zachovat klasický imageboard formát, ale přinést trochu vylepšení v podobě responzivity a\,\,moderních designových prvků. Veškeré styly jsou zde řešené pomocí CSS, resp. SCSS stylovacího jazyka a\,\,miniaturní knihovny \verb|include-media|\footnote{\url{https://eduardoboucas.github.io/include-media/}}, starající se o elegantnější řešení rezponzivity za pomoci CSS Media Queries.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{scss} \begin{minted}[breaklines=true,fontsize=\footnotesize]{scss}
@ -186,7 +208,7 @@ $breakpoints: (tablet: 560px, desktop: 900px);
\caption{Příklad využití knihovny include-media} \caption{Příklad využití knihovny include-media}
\end{listing} \end{listing}
Rezponzivita je rozdělena do tří rozměrů, kde minimální šířka pro desktop je 900px a pro tablet 560px. Při přechodu z desktopového rozvržení na tabletové se obsah pravého postranního panelu přesune nad hlavní obsah a při dalším zmenšování na mobilní rozvržení se kompletně skryjí odkazy v horním navigačním panelu a jsou dostupné přes menu tlačítko vpravo nahoře. Naopak při nadměrném zvětšování je tu limit pro šířku hlavního wrapperu 1300px, takže bude obsah vždy vycentrován na očích uživatele. Rezponzivita je rozdělena do tří rozměrů, kde minimální šířka pro desktop je 900px a\,\,pro tablet 560px. Při přechodu z desktopového rozvržení na tabletové se obsah pravého postranního panelu přesune nad hlavní obsah a\,\,při dalším zmenšování na mobilní rozvržení se kompletně skryjí odkazy v horním navigačním panelu a\,\,jsou dostupné přes menu tlačítko vpravo nahoře. Naopak při nadměrném zvětšování je tu limit pro šířku hlavního wrapperu 1300px, takže bude obsah vždy vycentrován na očích uživatele.
Stránky jsou designované v tmavém šedivém barevném schématu, ne jen kvůli tomu, že se s tmavými prvky lépe pracuje, ale i proto, že méně svítící obrazovka také méně unavuje oči uživatele. Původní design byl postaven okolo tmavě červené, ale od toho se upustilo kvůli nevhodnosti kombinace s dalšími barevnými prvky. Barvy, včetně pár dalších parametrů, lze však kdykoli jednoduše přizpůsobit přenastavením globálních proměnných v scss souboru \verb|assets/css/main.scss|. Stránky jsou designované v tmavém šedivém barevném schématu, ne jen kvůli tomu, že se s tmavými prvky lépe pracuje, ale i proto, že méně svítící obrazovka také méně unavuje oči uživatele. Původní design byl postaven okolo tmavě červené, ale od toho se upustilo kvůli nevhodnosti kombinace s dalšími barevnými prvky. Barvy, včetně pár dalších parametrů, lze však kdykoli jednoduše přizpůsobit přenastavením globálních proměnných v scss souboru \verb|assets/css/main.scss|.
\begin{listing}[h] \begin{listing}[h]
@ -205,7 +227,7 @@ $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;| 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 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ě.
% 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.
@ -235,14 +257,14 @@ section.post-list {
\end{minted} \end{minted}
\caption{Zjednodušený pohled do designu výpisu náhledů} \caption{Zjednodušený pohled do designu výpisu náhledů}
\end{listing} \end{listing}
V tabletovém a dále mobilním rozvržení se pomocí záporného marginu odeberou okraje u náhledů pro lepší uživatelský experience. V tabletovém a\,\,dále mobilním rozvržení se pomocí záporného marginu odeberou okraje u náhledů pro lepší uživatelský experience.
Výpis dále využívá \verb|srcset| HTML atribut pro poskytnutí náhledu v rozlišení adekvátním pro dané zařízení. Výpis dále využívá \verb|srcset| HTML atribut pro poskytnutí náhledu v rozlišení adekvátním pro dané zařízení.
V levém panelu se nachází speciální prvek pro přehled a výběr/filtrování pomocí tagů. Výpis, který po najetí myší umožní následný výběr pro filtraci, indikuje tagy, které se v tento moment vyskytují v příspěvcích na přehledové části vpravo a jejich současný unikátní počet. V horní části je vyhledávací pole, kterým lze vyhledávat a vybírat tagy, které nejsou na stránce. V levém panelu se nachází speciální prvek pro přehled a\,\,výběr/filtrování pomocí tagů. Výpis, který po najetí myší umožní následný výběr pro filtraci, indikuje tagy, které se v tento moment vyskytují v příspěvcích na přehledové části vpravo a\,\,jejich současný unikátní počet. V horní části je vyhledávací pole, kterým lze vyhledávat a\,\,vybírat tagy, které nejsou na stránce.
Tento prvek s tagy je přizpůsoben, aby byl znovuužitelný i na jiných místech webu (např. na stránce uploadu nebo úpravy příspěvku) jako náhrada za multiselect. Prvek je použitelný i v prostředích s vypnutým JavaScriptem, kde se zobrazí jen jako textový input obsahující mezerou oddělené hodnoty. Tagy nabízené na hlavní stránce se v tomto prostředí chovají jako jednoduché odkazy, takže se výpis při kliknutí automaticky aktualizuje. Očividně však není možné provádět hledání s nápovídáním. Tento prvek s tagy je přizpůsoben, aby byl znovuužitelný i na jiných místech webu (např. na stránce uploadu nebo úpravy příspěvku) jako náhrada za multiselect. Prvek je použitelný i v prostředích s vypnutým JavaScriptem, kde se zobrazí jen jako textový input obsahující mezerou oddělené hodnoty. Tagy nabízené na hlavní stránce se v tomto prostředí chovají jako jednoduché odkazy, takže se výpis při kliknutí automaticky aktualizuje. Očividně však není možné provádět hledání s nápovídáním.
Stránka zobrazení příspěvku je neméně zajímavá - kromě postranního panelu obsahuje flexový wrapper pro JPEG sample obrázku ve vyšším rozlišení a komentářovou sekci. Při přechodu na tabletové rozvržení je díky funkci \mintinline{css}|display: contents;|, který předá své položky bloku o třídu výše, možné vložit boční panel mezi náhled obrázku a komentářovou sekci. Stránka zobrazení příspěvku je neméně zajímavá - kromě postranního panelu obsahuje flexový wrapper pro JPEG sample obrázku ve vyšším rozlišení a\,\,komentářovou sekci. Při přechodu na tabletové rozvržení je díky funkci \mintinline{css}|display: contents;|, který předá své položky bloku o třídu výše, možné vložit boční panel mezi náhled obrázku a\,\,komentářovou sekci.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{scss} \begin{minted}[breaklines=true,fontsize=\footnotesize]{scss}
.important-subwrap { .important-subwrap {
@ -258,32 +280,32 @@ Stránka zobrazení příspěvku je neméně zajímavá - kromě postranního pa
\caption{Řešení responzivity na stránce příspěvku} \caption{Řešení responzivity na stránce příspěvku}
\end{listing} \end{listing}
Původní design tohoto přeskládání byl postaven poněkud složitějším způsobem. Vlastní náhled a sidebar byl ve svém flexboxu a postranní panel měl \mintinline{css}|height: 0;|, kde jeho obsah přetíkal ven. Když se nastavil patřičný margin na levé straně, tak to na desktopu umožňovalo umístit komentáře rovnou pod náhled a v mobilním rozvržení naopak dát náhledu \mintinline{css}|order: -1;| a připíchnout ho tak na vrch stránky. Nevýhoda tohoto řešení spočívala v překrývání levého panelu s patičkou stránky, takže se od tohoto designu upustilo. Původní design tohoto přeskládání byl postaven poněkud složitějším způsobem. Vlastní náhled a\,\,sidebar byl ve svém flexboxu a\,\,postranní panel měl \mintinline{css}|height: 0;|, kde jeho obsah přetíkal ven. Když se nastavil patřičný margin na levé straně, tak to na desktopu umožňovalo umístit komentáře rovnou pod náhled a\,\,v mobilním rozvržení naopak dát náhledu \mintinline{css}|order: -1;| a\,\,připíchnout ho tak na vrch stránky. Nevýhoda tohoto řešení spočívala v překrývání levého panelu s patičkou stránky, takže se od tohoto designu upustilo.
Levý panel zde obsahuje kromě výpisu tagů, které definují daný příspěvek, s jejich globálním počtem výskytů i samotný popis příspěvku a malý panel pro editaci příspěvku. Levý panel zde obsahuje kromě výpisu tagů, které definují daný příspěvek, s jejich globálním počtem výskytů i samotný popis příspěvku a\,\,malý panel pro editaci příspěvku.
Popis obsahuje výpis prakticky veškerých parametrů příspěvku, které se vyskytují v tabulce \verb|post| (str. \pageref{database}), včetně lidsky formátovaného relativního času nahrání a jmen uploadera a moderátora, který přispěvek schválil (popř. statusu schválenosti). Může se zde vyskytovat odkaz na ,,parent`` příspěvek, pokud současný nějaký má, nebo naopak jeho děti. Pod položkami jsou odkazy na originální zdrojový soubor beze změny, popřípadě i JPEG verzi, pokud byl originál ve formátu PNG. Popis obsahuje výpis prakticky veškerých parametrů příspěvku, které se vyskytují v tabulce \verb|post| (str. \pageref{database}), včetně lidsky formátovaného relativního času nahrání a\,\,jmen uploadera a\,\,moderátora, který přispěvek schválil (popř. statusu schválenosti). Může se zde vyskytovat odkaz na ,,parent`` příspěvek, pokud současný nějaký má, nebo naopak jeho děti. Pod položkami jsou odkazy na originální zdrojový soubor beze změny, popřípadě i JPEG verzi, pokud byl originál ve formátu PNG.
Komentářová sekce má jednoduchý vzhled. Hlavička komentáře obsahuje uživatelské jméno autora a na pravou stranu odsazený control tooltip, kterým lze spravovat daný komentář. Pokud jste autor daného komentáře, po kliknutí na \verb|edit| odkaz se obsah komentáře nahradí za textové pole pro úpravu a v tooltipu přibydou možnosti pro aktualizaci, nebo zrušení změn. Jako moderátor se zde objeví odkazy pro zablokování/odblokování komentáře. Komentářová sekce má jednoduchý vzhled. Hlavička komentáře obsahuje uživatelské jméno autora a\,\,na pravou stranu odsazený control tooltip, kterým lze spravovat daný komentář. Pokud jste autor daného komentáře, po kliknutí na \verb|edit| odkaz se obsah komentáře nahradí za textové pole pro úpravu a\,\,v tooltipu přibydou možnosti pro aktualizaci, nebo zrušení změn. Jako moderátor se zde objeví odkazy pro zablokování/odblokování komentáře.
Pokud bude mít uživatel vypnutý JavaScript, panel úprav se zobrazí automaticky při najetí kurzorem nad blok komentáře. Pokud bude mít uživatel vypnutý JavaScript, panel úprav se zobrazí automaticky při najetí kurzorem nad blok komentáře.
Pod hlavičkou je samotný obsah komentáře. V případě zablokování komentáře moderátorem, se jeho obsah nahradí červenou poznámkou o jeho stavu zablokování. To však neznemožní jeho správu, jelikož pro autora i moderátora bude nadále obsah zprávy viditelný. Pod hlavičkou je samotný obsah komentáře. V případě zablokování komentáře moderátorem, se jeho obsah nahradí červenou poznámkou o jeho stavu zablokování. To však neznemožní jeho správu, jelikož pro autora i moderátora bude nadále obsah zprávy viditelný.
% SCREENSHOT - KOMENTÁŘ WITHOUT/WITH EDIT % SCREENSHOT - KOMENTÁŘ WITHOUT/WITH EDIT
Každý uživatel má svou stránku profilu. Jsou zde veřejně dostupné statistiky o jeho užívání služby, blacklist tagů a seznam posledních komentářů. Jako přihlášený uživatel lze najít svůj profil kliknutím na položku \verb|Profile| v padacím menu, dostupném po najetí kurzorem na jméno uživatele v horním panelu. Jako registrovaný uživatel máte také přístup do stránek administrace. Na to je tu položka \verb|Settings|. Každý uživatel má svou stránku profilu. Jsou zde veřejně dostupné statistiky o jeho užívání služby, blacklist tagů a\,\,seznam posledních komentářů. Jako přihlášený uživatel lze najít svůj profil kliknutím na položku \verb|Profile| v padacím menu, dostupném po najetí kurzorem na jméno uživatele v horním panelu. Jako registrovaný uživatel máte také přístup do stránek administrace. Na to je tu položka \verb|Settings|.
Jako normální uživatel můžete manipulovat s nastavením svého profilu. Jsou zde formuláře pro úpravu vlastní biografie, změnu hesla nebo emailové adresy, nastavení preferované maximální přístupové kategorie a blacklistu tagů příspěvků zobrazovaných na hlavní stránce a samozřejmě možnost smazat veškerá svá uživatelská data. Jako normální uživatel můžete manipulovat s nastavením svého profilu. Jsou zde formuláře pro úpravu vlastní biografie, změnu hesla nebo emailové adresy, nastavení preferované maximální přístupové kategorie a\,\,blacklistu tagů příspěvků zobrazovaných na hlavní stránce a\,\,samozřejmě možnost smazat veškerá svá uživatelská data.
Moderátorům v levém navigačním panelu přibydou položky s odkazy na stránky pro hromadnou správu detailů příspěvků a tagů. Pokud uživatel už přispěl nějakým obrázkem do databáze, může se přes levý panel dostat do správy příspěvků také. Zobrazí se však pouze příspěvky které sám přidal. Rozhraní pro správu je ve formě základní tabulky parametrů. Na konci každého řádku ve sloupci \verb|Manage| kliknutím na ikonku pro editování nebo jednoduše poklikáním na položku, kterou chcete upravit, lze zobrazit formulář pro daný řádek s ikonkami pro zahození a odeslání změn. Vždy je na konci také ikonka koše pro vymazání daného záznamu. Stránka správy tagů navíc umožňuje vytváření nových tagů. Responzivita u tabulky není bez použití přebytečných knihoven elegantní na implementaci, proto jsem se zdržel přílišných složitostí a aplikoval horizontální scrollování, aby alespoň tak bylo možné na mobilních platformách provádět modifikace. Moderátorům v levém navigačním panelu přibydou položky s odkazy na stránky pro hromadnou správu detailů příspěvků a\,\,tagů. Pokud uživatel už přispěl nějakým obrázkem do databáze, může se přes levý panel dostat do správy příspěvků také. Zobrazí se však pouze příspěvky které sám přidal. Rozhraní pro správu je ve formě základní tabulky parametrů. Na konci každého řádku ve sloupci \verb|Manage| kliknutím na ikonku pro editování nebo jednoduše poklikáním na položku, kterou chcete upravit, lze zobrazit formulář pro daný řádek s ikonkami pro zahození a\,\,odeslání změn. Vždy je na konci také ikonka koše pro vymazání daného záznamu. Stránka správy tagů navíc umožňuje vytváření nových tagů. Responzivita u tabulky není bez použití přebytečných knihoven elegantní na implementaci, proto jsem se zdržel přílišných složitostí a\,\,aplikoval horizontální scrollování, aby alespoň tak bylo možné na mobilních platformách provádět modifikace.
Administrátorům dále přibyde možnost pro správu uživatelů. Administrátorům dále přibyde možnost pro správu uživatelů.
\pagebreak \pagebreak
\section{Popis projektu} \section{Popis projektu}
Ke stavbě svého projektu jsem využil mikroframework Flask, který běží na jazyku Python. S mými dřívějšími zkušenostmi s jazykem Python a frameworkem Flask, jsem se rozhodl, že využiji příležitosti a prohloubím své znalosti na větším projektu. Flask není plnohodnotný framework typu Django nebo Laravel v případě PHP, ale umožňuje jednoduché rozšíření svých funkcí pomocí spousty pomocných balíčků vytvořených komunitou. Ke stavbě svého projektu jsem využil mikroframework Flask, který běží na jazyku Python. S mými dřívějšími zkušenostmi s jazykem Python a\,\,frameworkem Flask, jsem se rozhodl, že využiji příležitosti a\,\,prohloubím své znalosti na větším projektu. Flask není plnohodnotný framework typu Django nebo Laravel v případě PHP, ale umožňuje jednoduché rozšíření svých funkcí pomocí spousty pomocných balíčků vytvořených komunitou.
Jako databázový engine používám PostgreSQL. Moje volba byla postavena na vyšší jednoduchosti obsluhy a nižší velikosti/výkonové náročnosti, a tím samozřejmě odvozené vyšší bezpečnosti celého engine ve srovnání např. s MySQL/MariaDB SQL DBMS implementací. Jako databázový engine používám PostgreSQL. Moje volba byla postavena na vyšší jednoduchosti obsluhy a\,\,nižší velikosti/výkonové náročnosti, a\,\,tím samozřejmě odvozené vyšší bezpečnosti celého engine ve srovnání např. s MySQL/MariaDB SQL DBMS implementací.
\subsection{Frontend} \subsection{Frontend}
Flask má vestavěný šablonový engine Jinja2, pomocí něhož jsem schopen efektivně třídit a skládat pohledy s přidanou vrstvou bezpečnosti, jako ochrana před XSS escapováním znaků. Tímto jsem schopen vytvořit základní kostru stránky, ze které lze dále dědit formou bloků. Flask má vestavěný šablonový engine Jinja2, pomocí něhož jsem schopen efektivně třídit a\,\,skládat pohledy s přidanou vrstvou bezpečnosti, jako ochrana před XSS escapováním znaků. Tímto jsem schopen vytvořit základní kostru stránky, ze které lze dále dědit formou bloků.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{html} \begin{minted}[breaklines=true,fontsize=\footnotesize]{html}
{% extends 'layout/base.html' %} {% extends 'layout/base.html' %}
@ -299,15 +321,15 @@ Flask má vestavěný šablonový engine Jinja2, pomocí něhož jsem schopen ef
\caption{Příklad jednoduché šablony, použité pro postranní panel} \caption{Příklad jednoduché šablony, použité pro postranní panel}
\end{listing} \end{listing}
Základní šablona se nachází v souboru \path{templates/layout/base.html}. Obsahuje základní HTML strukturu včetně hlavičky, v níž se importují zabundlované (viz. Backend) CSS soubory a \verb|Font-Awesome| icon pack, který využívám na mnoha místech projektu. Tělo stránky obsahuje základní strukturu hlavního navigačního panelu, cyklus pro výpis pop-up notifikací a patičku stránky s importy opět zabundlovaných JS skriptů. Jelikož z této šablony dědí všechny stránky projektu, budou tyto prvky dostupné všude. Základní šablona se nachází v souboru \path{templates/layout/base.html}. Obsahuje základní HTML strukturu včetně hlavičky, v níž se importují zabundlované (viz. Backend) CSS soubory a\,\,\verb|Font-Awesome| icon pack, který využívám na mnoha místech projektu. Tělo stránky obsahuje základní strukturu hlavního navigačního panelu, cyklus pro výpis pop-up notifikací a\,\,patičku stránky s importy opět zabundlovaných JS skriptů. Jelikož z této šablony dědí všechny stránky projektu, budou tyto prvky dostupné všude.
V mobilním rozvržení se v hlavičce aktivuje skript \path{assets/js/base.js}, který se postará o zobrazení přetékajícího menu a o zmrazení scrollování stránky. V mobilním rozvržení se v hlavičce aktivuje skript \path{assets/js/base.js}, který se postará o zobrazení přetékajícího menu a\,\,o zmrazení scrollování stránky.
Lze si také všimnout, že zde, stejně jako na mnoha stránkách frontendu, využívám pomocné funkce z modulu \path{utils.py} (str. \pageref{utilspy}), které jsou do tzv. (frontendového) kontextu naimportované v \path{__init__.py}. Lze si také všimnout, že zde, stejně jako na mnoha stránkách frontendu, využívám pomocné funkce z modulu \path{utils.py} (str. \pageref{utilspy}), které jsou do tzv. (frontendového) kontextu naimportované v \path{__init__.py}.
Většina stránek dědí i ze \path{layout/base_sidebar.html}, který přidává postranní panel, ale zdaleka zajímavější je \path{layout/base_sidebar_tags.html}. Je zde vidět základní struktura panelu s tagy. Většina interaktivních prvků je však definována až ve skriptu v \path{assets/js/taginput.js}. Tento skript se aplikuje na každý prvek se vstupem pro tagy. Po zadání příslušného slova do textového inputu lze kliknutím na nabízený tag v popupu nebo stisknutím klávesy \verb|<Enter>| zvýrazněný tag přidat do vybraných. Na hlavní stránce se opakovaným stisknutím \verb|<Enter>| potvrdí vyhledávání a po pravé straně se aktualizuje výpis náhledů příspěvků. V popupu nabízených tagů během vyhledávání se lze také pohybovat pomocí klávesových šipek nebo kombinací \verb|<Tab>| a \verb|<Shift-Tab>|. Vyhledávání probíhá pomocí AJAX dotazů v pozadí využívající \verb|Fetch| API. Dotaz se provede vždy v určitém časovém intervalu poté, co uživatel přestane psát. Většina stránek dědí i ze \path{layout/base_sidebar.html}, který přidává postranní panel, ale zdaleka zajímavější je \path{layout/base_sidebar_tags.html}. Je zde vidět základní struktura panelu s tagy. Většina interaktivních prvků je však definována až ve skriptu v \path{assets/js/taginput.js}. Tento skript se aplikuje na každý prvek se vstupem pro tagy. Po zadání příslušného slova do textového inputu lze kliknutím na nabízený tag v popupu nebo stisknutím klávesy \verb|<Enter>| zvýrazněný tag přidat do vybraných. Na hlavní stránce se opakovaným stisknutím \verb|<Enter>| potvrdí vyhledávání a\,\,po pravé straně se aktualizuje výpis náhledů příspěvků. V popupu nabízených tagů během vyhledávání se lze také pohybovat pomocí klávesových šipek nebo kombinací \verb|<Tab>| a\,\,\verb|<Shift-Tab>|. Vyhledávání probíhá pomocí AJAX dotazů v pozadí využívající \verb|Fetch| API. Dotaz se provede vždy v určitém časovém intervalu poté, co uživatel přestane psát.
Template \path{layout/management.html} obsahuje univerzální znovuužitelnou strukturu pro tvorbu tabulek pro management, který masivně využívá schopností Jinja2 engine. Je tu předdefinovaná kostra tabulky s formuláři pro každý řádek, které se pomocí \verb|for| cyklu generují. Dědící šablony z adresáře \path{manage/} pak mají díky block definicím možnost vložit vlastní obsah hlavičky a polí do těla tabulky. Pole jsou generována pomocí makra, \verb|genfield()|, kterému lze pomocí \verb|call| statementu vložit vlastní payload pro lepší přizpůsobení zobrazovaného pole, když není editováno (např. jako odkaz na příslušnou stránku příspěvku). Template \path{layout/management.html} obsahuje univerzální znovuužitelnou strukturu pro tvorbu tabulek pro management, který masivně využívá schopností Jinja2 engine. Je tu předdefinovaná kostra tabulky s formuláři pro každý řádek, které se pomocí \verb|for| cyklu generují. Dědící šablony z adresáře \path{manage/} pak mají díky block definicím možnost vložit vlastní obsah hlavičky a\,\,polí do těla tabulky. Pole jsou generována pomocí makra, \verb|genfield()|, kterému lze pomocí \verb|call| statementu vložit vlastní payload pro lepší přizpůsobení zobrazovaného pole, když není editováno (např. jako odkaz na příslušnou stránku příspěvku).
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{html} \begin{minted}[breaklines=true,fontsize=\footnotesize]{html}
{% macro genfield(formfield=None) %} {% macro genfield(formfield=None) %}
@ -329,27 +351,27 @@ Template \path{layout/management.html} obsahuje univerzální znovuužitelnou st
% 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 \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 \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.
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 \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}.
\subsection{Backend} \subsection{Backend}
Základem celého projektu je tzv. app-factory v souboru \path|__init__.py| v kořenové složce projektu, kde se definuje chod celé Flask aplikace. Základem celého projektu je tzv. app-factory v souboru \path|__init__.py| v kořenové složce projektu, kde se definuje chod celé Flask aplikace.
Nejprve se zde načtou globální konfigurační proměnné ze souboru, jehož šablona \path|config.def.py| se po nasazení aplikace do provozu musí umístit do kořene instančního adresáře pod názvem \path|config.py|. Uvnitř jsou definované hodnoty jako je název instance aplikace, tajný klíč pro generování unikátních tokenů nebo URI pro přístup do zvoleného DBMS. Konfigurace je pak dostupná pod objektem \verb|config| v instanci Flasku. Nejprve se zde načtou globální konfigurační proměnné ze souboru \path|config.py| v instančním adresáři repozitáře. Konfigurace je pak dostupná pod objektem \verb|config| v instanci Flasku.
Dále se zde inicializují balíčky jako např. SQLAlchemy\footnote{\url{https://www.sqlalchemy.org/}} ORM (nebo spíše jeho adaptace pro Flask -- \verb|Flask-SQLAlchemy|\footnote{\url{https://flask-sqlalchemy.palletsprojects.com/en/2.x/}}), který využívám pro operace s databází nebo \verb|Flask-Assets|\footnote{\url{https://flask-assets.readthedocs.io/en/latest/}}, který se postará o kompilaci a minimalizaci SCSS a zabalení do jednotných souborů, a to i v případě JS. Dále se zde inicializují balíčky jako např. SQLAlchemy\footnote{\url{https://www.sqlalchemy.org/}} ORM (nebo spíše jeho adaptace pro Flask -- \verb|Flask-SQLAlchemy|\footnote{\url{https://flask-sqlalchemy.palletsprojects.com/en/2.x/}}), který využívám pro operace s databází nebo \verb|Flask-Assets|\footnote{\url{https://flask-assets.readthedocs.io/en/latest/}}, který se postará o kompilaci a\,\,minimalizaci SCSS a\,\,zabalení do jednotných souborů, a\,\,to i v případě JS.
\subsubsection{Struktura aplikace} \subsubsection{Struktura aplikace}
\paragraph{Směrování} \paragraph{Směrování}
Flask obsahuje vlastní směrovací systém s podporou tzv. blueprintů, jimiž jsem schopen přehledně oddělit specifické části projektu do zvláštních souborů a přidělit jim vlastní prefix v URL cestě. Uvnitř blueprintů je pak možné pomocí tzv. funkčních dekorátorů označit koncové funkce cestami nebo jinými podmínkami. Flask obsahuje vlastní směrovací systém s podporou tzv. blueprintů, jimiž jsem schopen přehledně oddělit specifické části projektu do zvláštních souborů a\,\,přidělit jim vlastní prefix v URL cestě. Uvnitř blueprintů je pak možné pomocí tzv. funkčních dekorátorů označit koncové funkce cestami nebo jinými podmínkami.
Program je rozdělen do pěti blueprintů. Program je rozdělen do pěti blueprintů.
Z uživatelské perspektivy je nejpodstatnější částí blueprint \path|bp/post.py|, kde jsou definované endpointy pro zobrazení indexu a jednotlivých příspěvků, ale i formulář pro nahrávání příspěvků, koncový bod pro uživatelské komentáře, jednoduché API pro automatické napovídání během výběru tagů k filtraci a velice jednoduché API pro aplikaci třetí strany, aby mohla přistupovat k obrázkové databázi. Z uživatelské perspektivy je nejpodstatnější částí blueprint \path|bp/post.py|, kde jsou definované endpointy pro zobrazení indexu a\,\,jednotlivých příspěvků, ale i formulář pro nahrávání příspěvků, koncový bod pro uživatelské komentáře, jednoduché API pro automatické napovídání během výběru tagů k filtraci a\,\,velice jednoduché API pro aplikaci třetí strany, aby mohla přistupovat k obrázkové databázi.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{python} \begin{minted}[breaklines=true,fontsize=\footnotesize]{python}
from yadc.bp import main, post, auth, manage, user from yadc.bp import main, post, auth, manage, user
@ -364,13 +386,13 @@ app.register_blueprint(user.bp, url_prefix='/user')
Neméně důležitý je pak \path|bp/main.py|, který má na starost zpracovávat dotazy na obrazová data uložená ve složce instance. Jsou zde koncové body pro pět různých formátů/velikostí každého nahraného obrázku s dynamicky parsovanou URL cestou. Neméně důležitý je pak \path|bp/main.py|, který má na starost zpracovávat dotazy na obrazová data uložená ve složce instance. Jsou zde koncové body pro pět různých formátů/velikostí každého nahraného obrázku s dynamicky parsovanou URL cestou.
V souboru \path|bp/manage.py| jsou endpointy pro stránky managementu a jejich formuláře a \path|bp/user.py| obsahuje koncové body pro uživatelský profil s jeho stránkou nastavení. V souboru \path|bp/manage.py| jsou endpointy pro stránky managementu a\,\,jejich formuláře a\,\,\path|bp/user.py| obsahuje koncové body pro uživatelský profil s jeho stránkou nastavení.
Blueprint \verb|bp/auth.py| se nakonec stará o přihlášení a registrace. 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í 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.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{python} \begin{minted}[breaklines=true,fontsize=\footnotesize]{python}
class LoginForm(CSRFForm): class LoginForm(CSRFForm):
@ -385,7 +407,7 @@ class LoginForm(CSRFForm):
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 \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]
@ -401,17 +423,18 @@ Definice pomocí modelů mi umožňuje definovat vlastní metody na daném objek
V souboru \path|models.py| se kromě modelů vyskytují i enumerace obecných hodnot jako je datový formát nahraných obrázků, úrovně oprávnění uživatelů nebo kategorie tagů. Se všemi dokáže SQLAlchemy operovat. V souboru \path|models.py| se kromě modelů vyskytují i enumerace obecných hodnot jako je datový formát nahraných obrázků, úrovně oprávnění uživatelů nebo kategorie tagů. Se všemi dokáže SQLAlchemy operovat.
\paragraph{Utility} \label{utilspy} \paragraph{Utility} \label{utilspy}
Pro uchování užitečných funkcí, které však nepatří na žádné specifické místo a je potřeba k nim přistupovat v globálním měřítku, slouží soubor \path{utils.py}. Jsou zde funkce napomáhající s manipulací s URL adresami jako např. nahrazování parametrů, tvorba adres pro tagy nebo jednoduché \textit{,,flashování``} errorů z formulářových endpointů, aby se poté mohly vypsat uživateli. Je zde také definovaná vypůjčená funkce \mintinline{python}|sizeof_fmt()| \footnote{\url{https://web.archive.org/web/20111010015624/http://blogmag.net/blog/read/38/Print_human_readable_file_size}}, která převádí jednotky velikosti souboru. Pro uchování užitečných funkcí, které však nepatří na žádné specifické místo a\,\,je potřeba k nim přistupovat v globálním měřítku, slouží soubor \path{utils.py}. Jsou zde funkce napomáhající s manipulací s URL adresami jako např. nahrazování parametrů, tvorba adres pro tagy nebo jednoduché \textit{,,flashování``} errorů z formulářových endpointů, aby se poté mohly vypsat uživateli. Je zde také definovaná vypůjčená funkce \mintinline{python}|sizeof_fmt()| \footnote{\url{https://web.archive.org/web/20111010015624/http://blogmag.net/blog/read/38/Print_human_readable_file_size}}, která převádí jednotky velikosti souboru.
\paragraph{Konfigurace} \paragraph{Konfigurace}
Příklad základní konfigurace je uložen ve skriptu \path{config.def.py}. Před nasazením projektu je však nutné tento soubor přesunout do instančního adresáře v kořenu repozitáře pod jménem \path{config.py}, jinak nebude aplikace operovat správně. V konfiguračním souboru lze najít základní parametry, jako je URI pro přístup do databáze obsahující přihlašovací údaje, adresu a\,\,název databáze nebo náhodný tajný klíč, určený pro generování bezpečných tokenů a\,\,hesel napříč aplikací. Lze zde také najít vlastní konfigurační proměnné měnící např. počet zobrazovaných náhledů na hlavní stránce, položek na stránkách managementu nebo možnost pro změnu názvu instance, který se projeví na mnoha místech aplikace.
\subsubsection{Hlavní stránka} \subsubsection{Hlavní stránka}
Ačkoli se to nemusí zdát, struktura endpointu pro vypisování příspěvků není jednoduchá. Ačkoli se to nemusí zdát, struktura endpointu pro vypisování příspěvků není jednoduchá.
Zpracovávají se zde vstupní parametry URL v podobě tagů a vynucené hodnoty věkové přístupnosti. Zpracovávají se zde vstupní parametry URL v podobě tagů a\,\,vynucené hodnoty věkové přístupnosti.
Pokud byl věkový rating vynucen v URL, instantně se převede na enumerátor \mintinline{python}|RATING| a vloží se pro příští návštěvy do \verb|session|, aby byl při příštích návštěvách indexu dostupný. Pokud není vynucen, tak se jako default nastaví preference přihlášeného uživatele. Pokud nejsou splněny podmínky výše, zobrazí se jen obsah s bezpečnou tématikou. Věková přístupnost se pomocí funkce \mintinline{python}|matched| na instanci enumerátoru počítá sestupně, takže není možné vypínat jednotlivé kategorie. Pokud byl věkový rating vynucen v URL, instantně se převede na enumerátor \mintinline{python}|RATING| a\,\,vloží se pro příští návštěvy do \verb|session|, aby byl při příštích návštěvách indexu dostupný. Pokud není vynucen, tak se jako default nastaví preference přihlášeného uživatele. Pokud nejsou splněny podmínky výše, zobrazí se jen obsah s bezpečnou tématikou. Věková přístupnost se pomocí funkce \mintinline{python}|matched| na instanci enumerátoru počítá sestupně, takže není možné vypínat jednotlivé kategorie.
Poté co se provede implicitní SELECT tagů, které má uživatel v blacklistu, se dynamicky vytvoří dotaz a pomocí speciální \mintinline{python}|paginate()| funkce se dotaz provede a převede na objekt \verb|Pagination|, v němž se dá později stránkovat a současně je efektivnější než \verb|OFFSET| a \verb|LIMIT| atributy. Poté co se provede implicitní SELECT tagů, které má uživatel v blacklistu, se dynamicky vytvoří dotaz a\,\,pomocí speciální \mintinline{python}|paginate()| funkce se dotaz provede a\,\,převede na objekt \verb|Pagination|, v němž se dá později stránkovat a\,\,současně je efektivnější než \verb|OFFSET| a\,\,\verb|LIMIT| atributy.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{python} \begin{minted}[breaklines=true,fontsize=\footnotesize]{python}
@ -432,8 +455,8 @@ posts = posts_query.paginate(page, current_app.config.get('POSTS_PER_PAGE'))
\caption{Dynamická tvorba databázového dotazu v závislosti na vstupu} \caption{Dynamická tvorba databázového dotazu v závislosti na vstupu}
\end{listing} \end{listing}
\subsubsection{Přihlášení a registrace} \subsubsection{Přihlášení a\,\,registrace}
Mezi jeden z nejvíce užitečných rozšíření pro Flask je \verb|Flask-Login|\footnote{\url{https://flask-login.readthedocs.io/en/latest/}}. Zajistí integraci s modelem uživatele a postará se i o session proměnné. Na mě byla jen integrace s modelem v podobě tvorby a srovnávání hesel funkcemi \mintinline{python}|Post.create_password()| a \mintinline{python}|Post.check_password()| v podobě \verb|PBKDF2| hashů. Mezi jeden z nejvíce užitečných rozšíření pro Flask je \verb|Flask-Login|\footnote{\url{https://flask-login.readthedocs.io/en/latest/}}. Zajistí integraci s modelem uživatele a\,\,postará se i o session proměnné. Na mě byla jen integrace s modelem v podobě tvorby a\,\,srovnávání hesel funkcemi \mintinline{python}|Post.create_password()| a\,\,\mintinline{python}|Post.check_password()| v podobě \verb|PBKDF2| hashů.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{python} \begin{minted}[breaklines=true,fontsize=\footnotesize]{python}
def create_password(self, password): def create_password(self, password):
@ -448,10 +471,10 @@ def login(self, remember):
login_user(self, remember=remember) login_user(self, remember=remember)
self.last_login = utcnow() self.last_login = utcnow()
\end{minted} \end{minted}
\cprotect\caption{Metody na třídě \verb|User| pro práci s hesly a operaci s \verb|Flask-Login|} \cprotect\caption{Metody na třídě \verb|User| pro práci s hesly a\,\,operaci s \verb|Flask-Login|}
\end{listing} \end{listing}
Jak již bylo zmíněno, endpointy pro přihlašování a registrace jsou v blueprintu \path{bp/auth.py}. Ve většině případů jde o velice podobné zpracování dotazů, kde se při \verb|POST| requestu zvaliduje odeslaný formulář a provede odpovídající akce, nebo jen vrátí zpracovaný template, v němž se nová instance formuláře vyrenderuje. Jak již bylo zmíněno, endpointy pro přihlašování a\,\,registrace jsou v blueprintu \path{bp/auth.py}. Ve většině případů jde o velice podobné zpracování dotazů, kde se při \verb|POST| requestu zvaliduje odeslaný formulář a\,\,provede odpovídající akce, nebo jen vrátí zpracovaný template, v němž se nová instance formuláře vyrenderuje.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{python} \begin{minted}[breaklines=true,fontsize=\footnotesize]{python}
@ -478,13 +501,13 @@ def login():
\cprotect\caption{Endpoint pro login uživatele} \cprotect\caption{Endpoint pro login uživatele}
\end{listing} \end{listing}
Je zde implementována registrace, přihlášení, odhlášení a reset hesla. Je zde implementována registrace, přihlášení, odhlášení a\,\,reset hesla.
\subsubsection{Nahrávání příspěvků} \subsubsection{Nahrávání příspěvků}
Upload příspěvku je, jak již je zřejmé, dělen do několika částí. Nejprve se za pomoci balíčku \verb|Flask-Login| a jeho dekorátoru \mintinline{python}|@loginrequired| zajistí, že je uživatel přihlášen, jinak bude přesměrován na stránku s přihlášením. V případě, že uživatel pomocí POST dotazu odesílá obsah formuláře, proběhne validace na straně formuláře, a při jakémkoli erroru ho přesměruje na původní stránku a notifikací ho upozorní na chybnost odeslaných dat. Upload příspěvku je, jak již je zřejmé, dělen do několika částí. Nejprve se za pomoci balíčku \verb|Flask-Login| a\,\,jeho dekorátoru \mintinline{python}|@loginrequired| zajistí, že je uživatel přihlášen, jinak bude přesměrován na stránku s přihlášením. V případě, že uživatel pomocí POST dotazu odesílá obsah formuláře, proběhne validace na straně formuláře, a\,\,při jakémkoli erroru ho přesměruje na původní stránku a\,\,notifikací ho upozorní na chybnost odeslaných dat.
Kromě základní validace textových vstupů se zde kontroluje i stav nahraného obrázku. Nejprve se za pomoci balíčku \verb|Magic| srovná reálný mimetype souboru obrázku s podporovanými formáty, posléze se pomocí knihovny \verb|Pillow| zkontroluje integrita souboru. Kromě základní validace textových vstupů se zde kontroluje i stav nahraného obrázku. Nejprve se za pomoci balíčku \verb|Magic| srovná reálný mimetype souboru obrázku s podporovanými formáty, posléze se pomocí knihovny \verb|Pillow| zkontroluje integrita souboru.
Poskytnutím souboru statické metodě \mintinline{python}|Post.fileinfo()| se dále obstarají metadata o daném obrázku, na kterých se dále kontroluje unikátnost a minimální rozlišení nahrávaného příspěvku. Poskytnutím souboru statické metodě \mintinline{python}|Post.fileinfo()| se dále obstarají metadata o daném obrázku, na kterých se dále kontroluje unikátnost a\,\,minimální rozlišení nahrávaného příspěvku.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{python} \begin{minted}[breaklines=true,fontsize=\footnotesize]{python}
fileinfo = Post.fileinfo(file) fileinfo = Post.fileinfo(file)
@ -498,11 +521,11 @@ if width*height<min_width*min_height or width<min_size or height<min_size:
\end{minted} \end{minted}
\caption{Část validace nahrávaného souboru} \caption{Část validace nahrávaného souboru}
\end{listing} \end{listing}
Po úspěšné validaci se objekt \verb|Post| inicializuje, originál obrázku se uloží do složky v adresáři instance a zavoláním \mintinline{python}|Post.generate_image_files()| se opět pomocí balíčku \verb|Pillow| vygenerují všechny jeho varianty pro pozdější užití. Po úspěšné validaci se objekt \verb|Post| inicializuje, originál obrázku se uloží do složky v adresáři instance a\,\,zavoláním \mintinline{python}|Post.generate_image_files()| se opět pomocí balíčku \verb|Pillow| vygenerují všechny jeho varianty pro pozdější užití.
\subsubsection{Management} \subsubsection{Management}
Blueprint pro management v \path{bp/manage.py} má poněkud jinou strukturu než autorizační koncové body nebo endpoint pro upload. Pro zpřehlednění a zjednodušení manipulace jsou zde oddělené cesty pro zobrazení spravovacích tabulek dotazy GET a ty pro formuláře dotazem POST. I ve \path{forms.py} si lze povšimnout abstraktní třídy \verb|EditForm|, která definuje základní způsob manipulace s daty a z níž jednotlivé typy dědí. Blueprint pro management v \path{bp/manage.py} má poněkud jinou strukturu než autorizační koncové body nebo endpoint pro upload. Pro zpřehlednění a\,\,zjednodušení manipulace jsou zde oddělené cesty pro zobrazení spravovacích tabulek dotazy GET a\,\,ty pro formuláře dotazem POST. I ve \path{forms.py} si lze povšimnout abstraktní třídy \verb|EditForm|, která definuje základní způsob manipulace s daty a\,\,z níž jednotlivé typy dědí.
\begin{listing}[h] \begin{listing}[h]
\begin{minted}[breaklines=true,fontsize=\footnotesize]{python} \begin{minted}[breaklines=true,fontsize=\footnotesize]{python}
class EditForm(CSRFForm): class EditForm(CSRFForm):
@ -520,10 +543,11 @@ 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ů \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.
\subsection{Deployment} % \subsection{Deployment}
\section{Závěr} \section{Závěr}
% Tento projekt byl
\end{document} \end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Loading…
Cancel
Save