Dezvoltarea unei aplicații web rezistente la defecte cu ajutorul [626255]

Universitatea “Politehnica” din București
Facultatea de Electronică, Telecomunicații și Tehnologia Informației

Dezvoltarea unei aplicații web rezistente la defecte cu ajutorul
sistemului de gestiune a bazelor de date PostgreSQL

Proiect de diplomă
prezentat ca cerință parțială pentru obținerea titlului de
Inginer în domeniul domeniul Calculatoare și Tehnologia Informației
programul de studii de licență program Ingineria Informației

Conducător științific Absolvent
Ș.l.dr.ing. Valentin PUPEZES CU Alin-Ionuț PREDA

Anul 2019

Cuprins

Lista acronimelor ………………………….. ………………………….. ………………………….. ………………………….. . 9
Lista figurilor ………………………….. ………………………….. ………………………….. ………………………….. ….. 11
Introducere ………………………….. ………………………….. ………………………….. ………………………….. ……… 13
Capitolul 1 Noțiuni introductive de baze de date ………………………….. ………………………….. …………… 15
1.1 Ce este o bază de date? ………………………….. ………………………….. ………………………….. ……………………. 15
1.2 Avantaje ale sistemelor de baze de date ………………………….. ………………………….. …………………………. 16
1.3 Clasificarea de bazelor de date dupa numărul de statii pe care este stocata baza d e date …………….. 17
1.3.1 Baze de date centralizate ………………………….. ………………………….. ………………………….. …………… 17
1.3.2 Baze de date distribuite ………………………….. ………………………….. ………………………….. ……………… 18
1.4 Replicare ………………………….. ………………………….. ………………………….. ………………………….. ……………. 18
1.4.1 Ce este replicarea? ………………………….. ………………………….. ………………………….. ……………………. 18
1.4.2 Utilizări ………………………….. ………………………….. ………………………….. ………………………….. ………… 19
1.4.3 O singura instanță master versus mai multe instanțe master ………………………….. ………………….. 19
1.4.4 Replicarea „Hot Standby” ………………………….. ………………………….. ………………………….. …………… 19
Capitolul 2 Tehnologii fol osite la realizarea aplicației ………………………….. ………………………….. …… 21
2.1 Java ………………………….. ………………………….. ………………………….. ………………………….. ………………….. 21
2.2 Spring Boot ………………………….. ………………………….. ………………………….. ………………………….. ………… 22
2.3 HTML5 ………………………….. ………………………….. ………………………….. ………………………….. ……………….. 22
2.4 CSS ………………………….. ………………………….. ………………………….. ………………………….. ……………………. 23
2.5 Bootstrap ………………………….. ………………………….. ………………………….. ………………………….. …………… 23
2.6 Angular 7 ………………………….. ………………………….. ………………………….. ………………………….. ……………. 23
2.7 Node.JS ………………………….. ………………………….. ………………………….. ………………………….. ……………… 24
2.8 Npm ………………………….. ………………………….. ………………………….. ………………………….. ………………….. 24
2.9 JHipster ………………………….. ………………………….. ………………………….. ………………………….. ……………… 24
2.10 Maven ………………………….. ………………………….. ………………………….. ………………………….. ……………… 24
2.11 Git ………………………….. ………………………….. ………………………….. ………………………….. …………………… 25
2.12 REST ………………………….. ………………………….. ………………………….. ………………………….. ………………… 25
2.13 Swagger ………………………….. ………………………….. ………………………….. ………………………….. …………… 26
Capitolul 3 Proiectare și implementare ………………………….. ………………………….. ………………………… 27
3.1 Baza de date ………………………….. ………………………….. ………………………….. ………………………….. ………. 27
3.2 Prezentarea aplicației ………………………….. ………………………….. ………………………….. ………………………. 28
3.2.1 Arhitectura ………………………….. ………………………….. ………………………….. ………………………….. ………. 28
3.2.2 Interfața cu utlizatorul ………………………….. ………………………….. ………………………….. …………………… 28
Capitolul 4 Instalare și configurare ………………………….. ………………………….. ………………………….. …. 35

4.1 Pregătire mediu de dezvoltare aplicație ………………………….. ………………………….. ………………………….. 35
4.1.1 Instalare JDK versiunea 8 ………………………….. ………………………….. ………………………….. ……………. 35
4.1.2 Instalare IDE ………………………….. ………………………….. ………………………….. ………………………….. …. 36
4.1.3 Instalare Maven ………………………….. ………………………….. ………………………….. ………………………… 36
4.2 Pregătire sistem de replicare PostgreSQL ………………………….. ………………………….. ……………………….. 37
4.2.1 Instalare Virtual Box ………………………….. ………………………….. ………………………….. ………………….. 37
4.2.2 Pregatirea masinii virtuale cu Ubuntu 16.04 ………………………….. ………………………….. ……………… 37
4.2.3 Instalare PostgreSQ L ………………………….. ………………………….. ………………………….. ………………….. 37
4.2.4 Clonarea mașinii virtuale ………………………….. ………………………….. ………………………….. ……………. 38
4.2.4 Configurare Master ………………………….. ………………………….. ………………………….. …………………… 38
4.2.5 Configurare Slave ………………………….. ………………………….. ………………………….. ………………………. 39
4.2.6 Testare proces de replicare ………………………….. ………………………….. ………………………….. ………… 40
Concluzii ………………………….. ………………………….. ………………………….. ………………………….. ………… 43
Bibliografie ………………………….. ………………………….. ………………………….. ………………………….. …….. 45
Anexe ………………………….. ………………………….. ………………………….. ………………………….. …………….. 47

Lista acronimelor

API = Application Programming Interface (Interfață de programare a aplicaț iilor)
CSS = Cascading Style Sheets (Foi de stil in cascadă )
HTML = Hypertext Markup Language (Limbaj de marcare)
IDE = Integrated development environment (Mediu de dezvoltare integrat )
JPA = Java Persistence API
JS = Java Script
JVM = Java Virtual Machine (Mașină virtuală java )
REST = Representational State Transfer
SGBD = Sistem de gestiune al bazelor de date
SPA = Single Page A pplication (Aplicatie intr -o singura pagina )
SQL = Structured Query Language (Limbaj de interog are structurat)
VM = Virtual Machine (Masina virtuala)
WAL = Write -ahead logging (Logare înainte de scriere )
IP = Internet Protocol (Protocol de transmisie a datelor)

Lista figurilor

Figură 1.1 Componentele unui sistem de baze de date[ 2] ………………………….. ………………………….. …………. 15
Figura 1.2 Sisteme de baze de date centralizate: a -monoutilizator; b -multiutilizator; [2] ……………………….. 17
Figura 1.3 Sistem de baze de date distribuit. ………………………….. ………………………….. ………………………….. .. 18
Figura 3.1 Diagrama bazei de date ………………………….. ………………………….. ………………………….. ……………… 27
Figura 3.2 Structura Aplicatiei [22] ………………………….. ………………………….. ………………………….. ……………… 28
Figura 3.3 Pagina principala aplicației (neautentificat) ………………………….. ………………………….. ………………. 29
Figura 3.5 Pagina de activare a contului si modalul de autentificare ………………………….. ……………………….. 30
Figura 3.7 Pagina cu albume ………………………….. ………………………….. ………………………….. ………………………. 31
Figura 3.8 Pagina de creare a unui album ………………………….. ………………………….. ………………………….. ……. 31
Figura 3.9 Pagina de vizualizare a unui album ………………………….. ………………………….. ………………………….. . 32
Figura 3.10 Pagina de prezentare a agendelor ………………………….. ………………………….. ………………………….. 32
Figura 3.11 pagina de creare a unei agende ………………………….. ………………………….. ………………………….. … 33
Figura 3.12 Pagina de prezentare a unei agende. ………………………….. ………………………….. ……………………… 33
Figura 3.13 Pagina de schimbare a parolei ………………………….. ………………………….. ………………………….. …… 34
Figura 3.14 Pagina cu setări ale utilizatorului ………………………….. ………………………….. ………………………….. .. 34
Figura 4.1 Adăugare variabila de sistem JAVA_HOME ………………………….. ………………………….. ……………….. 35
Figura 4.2 Adăugare cale către directorul „bin” pentru JDK ………………………….. ………………………….. ……….. 35
Figura 4.3 Adăugare variabilă de sistem MAVEN_HOME ………………………….. ………………………….. ……………. 36
Figura 4.4 Adăugare cale către directorul „bin” pentru Maven ………………………….. ………………………….. …… 36
Figura 4.5 Testarea utilizatorului de re plicare ………………………….. ………………………….. ………………………….. . 39
Figura 4.6 Testare replicare (master) ………………………….. ………………………….. ………………………….. ………….. 41
Figura 4.7 Testare r eplicare (slave) ………………………….. ………………………….. ………………………….. …………….. 41
Figura 4.8 Testare replicare prin inserare de date (slave) ………………………….. ………………………….. ………….. 42

13
Introducere

În ultimul an Român ia a fost clasată pe locul 6 în clasamentul tărilor î n care este
rentabil/recomandabil să construieș ti un centru de date. In 2017 piața locală de centre de date a crescut
cu 55 -60%, iar în 2018 a c rescut cu 25 -30%, conform estimărilor. Astfel a apărut curi ozitatea de a
cunoaște care sunt metodele prin care acestea oferă clienților protecț ie a datelor in caz de dezastre
naturale.
Un centru de date este o locație folosită pentru a gă zdui sisteme de calculatoare ș i componente
asociate, cum ar fi sistemele de t elecomunicaț ii și de stocare .
Prezentul proiect descrie modul de impleme ntare a -l unei aplicaț ii web rezistente la defecte în
sistemul de gestiune a bazelor de date PostgreSQL. Rezistența la defecte a aplicației a fost realizată
cu ajutorul procesului de replicare disponibil în SGBD -ul PostgreSQL.
Am folosit topologia de replicare clasica de tip master -slave, iar pentru aceasta am pregătit doua
mașini virtuale cu distribuț ia de Linux Ubuntu 16.04 pe care am configurat sistemul de gestiune a
bazelor de date PostgreSQL astfel încat să se asigure distribuț ia datelor intre sisteme.
Accesul la aplicaț ie a fost securizat cu ajutorul framework -ului de J ava, Spring Security. Pentru
o securitat e sporita parolele au fost mai î ntai cripta te folosind altgoritmul BCrypt și apoi stocate in
baza de date sub forma de hash.
Aplicația w eb este dest inată proaspeților părinți și le va permite acestora sa își personalizeze
programul zilnic, să respecte rutina zilnică a copiilor si sa îndeplinească taskur ile zilnice. De
asemenea aplicaț ia permite utiliz atorilor să creeze o colecție de albume cu momente importante din
viața copiilor lor.

14

15
Capitolul 1 Noțiuni introductive de baze de date

1.1 Ce este o bază de date?

„O baza de date este o colecție de date, destinată stocări e ficiente a datelor. O baza de date permite
menținerea si ac cesarea rapida a datelor.” [1]

„O bază de date permite operaț ii de:
 Inserare
 Actualizare
 Ștergere
 Interogare ”[2]

„Un sistem de baze de date este un sistem computerizat de menținere a evidenței u nei anumite
activităț i, folosind baze de date .

Figur ă 1.1 Componentele unui sistem de baze de date[2]

“Componentele unui sistem de baze de date sunt urmatoarele :

 Hardware :
o Sistemele de baze de date sunt instalate pe calculatoare de uz general
o Bazele d e date sunt memorate fizic ca fiș iere pe discuri magnetice
o Dimensiunea și performanțele bazei de date depind de sistemul de calcul pe care
este instalată
 Software
o Sisteme de operare, biblioteci, instrumente de dezvoltare, interfete
o Sistemul de gestiune a bazelor de d ate (SGBD) ”[2] “ – set de unel te software care
controlează accesul, organizează, stochează, gestionează accesea ză și menține
datele într -o bază de date ”[1]
o “Aplicaț ii de baze de date: – sunt programe care cree ază și utilizează baze de date

16
 Utilizatori
o Administratorul bazei de date
o Analiști și proiectanț i ai bazelor de date
o Programatori de aplicații
o Utilizatori finali
 Date persistente
o Fișiere memorate pe hard -disk”[2]

“Sistemul de programe cu care se pot construi bazele de date, se pot introduce date in bazele de
date și se pot dezvolta aplicaț ii privind bazele de date se numeș te sistem de gestiune al ba zelor de
date (SGBD). Un SGBD dă posibilitatea utilizatorului sa aibă acces la date folosind un limbaj de
nivel înalt apropiat de modul obi șnuit de exprimare pentru a obține informații, utilizatorul facând
abstracție de algoritmii aplicați pentru selecționarea datelor implicate ș i a modului de memorare a lor.
SGBD -ul este o interfața între utilizatori ș i sistemul de operare.

Orice SGBD conț ine pri ntre alte componente un limbaj de descriere a datelor (LDD) care permite
descrierea struc turii unei baze de date, a fiecărei componente a ei, a relaț iilor dintre ele, a drepturilor
de acces ale utilizator ilor la baza de date, a restricțiilor î n reprezentar ea informațiilor și alte elemente
asemănătoare. O altă componentă foarte importantă a unui SGBD este limbajul de cereri (LC) sau
limbajul de prelucrare a datelor (LPD) ce permite operaț ii asupra datelo r aflate în baza de date cum
sunt: î ncarcarea bazei de date, inserarea unui nou element, ș terger ea unui element, modificarea un ui
element, cautarea unor elemente, dife rite statistici asupra datelor și alte operații asemănă toare.”[18]

1.2 Avantaje ale sistemel or de baze de date

"Față de vechile metode de înre gistrare a datelor privind diferite activități pe fișe (documente
scrise) sau chiar în f ișiere pe disc, sistemele de baze de dat e oferă avantaje considerabile, ceea ce
explică utilizarea extinsă a acestora.

Câteva dintre avantajele oferit e sunt prezentat e în continuare:
 Compactitate ridicată: volumul ocupat de sistemele de baze de date este mult ma i redus
decât volumul ocupat de documente scrise sau de fișierele necorelate.
 Viteză mare de regăsire și actualizare a informațiilor.
 Redundanță scăzută a d atelor memorate, care se obține prin partajarea datelor între mai
mulți utilizatori și aplicații. În stocarea pe fișe sau în fișie re a datelor, fiecare aplicație
conținea propriile seturi de date . În sistemele de baze de date, mai multe aplicații pot folosi
date comune, memorate o singură dată. De exemplu, o aplicație de pers onal și o aplicație
de rezultate la examene dintr -o universitate care exploatează o singură bază de date, pot
folosi aceleași informații referitoare la
 structurarea facultăților și a secți ilor.
 Posibilitatea de introduce re a standardelor privind modul de stocare a datelor , ceea ce
permite interschimbul informațiilor între diferite organizații.

17
 Menținerea integrității date lor prin politica de securitate (drepturi de acces diferențiate în
funcție de rolul utilizatorilor), prin gestionarea tranzacțiilor și p rin refacerea datelor în caz
de funcționare defectuoasă a dife ritelor componente hardware sau software.
 Independența datelor față de suportul hardware utilizat. Sistemele de gestiune a bazelo r de
date oferă o vedere (view) externă a datelor, care nu se modifică atunci când se schimbă
suportul de memorare fi zic, ceea ce asigură imunitatea structurii bazei de date și a
aplicațiilor la modificări ale sistemului hardware utilizat. ”[23]

1.3 Clasif icarea de baze lor de date dupa numărul de statii pe care este stocata
baza de date

1.3.1 Baze de date centralizate

„Un sist em de baze de date centralizat, este un sistem de baze de date în care datele și sistemul de
gestiune sunt stocate pe o singură sta ție (calculator).
Un sistem centralizat poate suporta unul sau mai mulți utilizatori, dar, în orice situație, datele și
sistemul de gestiune rezidă în întregime pe o singură stație.
Într-un sistem centralizat există un singur server, care este chiar sistem ul SGBD, care răspunde
cererilor unui singur client sau mai multor clienți, care accesează baza de date respectivă. Clienții
sunt programe de aplicații oferite de furnizorul sistemului de gestiune sau dezvoltate de programatori.
Aplicațiile client pot fi e xecutate pe stații diferite, conectate printr -o rețea de comunicație cu stația pe
care rulează serverul. Această arhitectură permite o prelucrare distribuită a datelor, mai mult chiar, o
configurare a sistemului adaptată cerințelor de calcul particulare. A stfel, serverul bazei de date poate
fi un sistem puternic, echipat corespunzător (cu volum mare de memorie secundară), în timp ce fiecare
client este o stație personală, cu putere de calcul adecvată aplicației executate.”[3]

Figura 1 .2 Sisteme de baze de date centralizate: a -monoutilizator; b -multiutilizator; [2]

18
1.3.2 Baze de date distribuite

“O bază de date distribuită este o colecție de date care aparțin din punct de vedere logic aceluiași
sistem, dar care pot să fie din punct de vedere fizic, memor ate în mai multe stații de calcul conectate
printr -o rețea de comunicație.
Sistemul software care gestionează o astfel de bază de date se numește Sistem de Gestiune a Bazei
de Date Distribuite – SGBDD . Aplicațiile client rulează pe alte stații din rețea și solicită servicii de
la sistemul de gestiune distribuit.
Există numeroase avantaje ale sistemelor de baze de date distribuite (creșterea capacității de
stocare și prelucrare a datelor, creșterea disponibilității și a partajării datelor etc.), dar și o creștere
considerabilă a complexității acestora. ”[3]

Figura 1.3 Sistem de baze de date distribuit.

1.4 Replicare

1.4.1 Ce este replicarea?

“Replicarea este un proces care constă în realizarea și distribuirea de copii ale datelor și, în plus,
permit e ca modificările efectuate să fie propagate în mod consistent la copiile corespunzătoare.
Distribuirea acestor replici are ca scop procesarea datelor la nivel local.”[4]
„Problema principală pe care o rezolvă procesul de replicare este păstrarea datelor u nui server
sincronizate cu datele altuia. Multe stații slave se pot conecta la o singură stație master, iar un slave
poate, la rândul său, să acționeze ca un master. Se pot aranja stațiile master și slave în multe topologii

19
diferite. Putem replica întregul server, numai anumite baze de date sau chiar putem alege tabelele pe
care dorim să le replicăm.”[3]

1.4.2 Utilizări
Replicarea este un proces util î n urmă toarele situaț ii:
 “Scalare pe orizo ntal, î mpărțirea ș i distribuirea interogărilor către mai multe i nstanț e slave
 Analiză de date: extragerea de rapoarte si analiza de data se poate face pe instanț e de tip
slave pentru a nu supraîncărca serverul master
 Distribuția geografică a datelor: utilizatorii vor accesa o aplicaț ie locala iar datele de
analiza vor fi replicate pe instanțele master folosite pentru analiză ”
 Restaurarea unei copii de rezerva î ntr-un anumit stadiu cu mare precizie [5]

1.4.3 O singura instanță master versus mai mult e instanț e master

„Având un singur server master înseamnă că ap licația va scrie date doar pe un ser ver care va
distribuii datele către instanț ele sla ve din sistem. Instanța slave accepta doar operaț ii de citire.
Pe de al ta parte având mai multe instanț e master replicarea permite scrier ea pe toate serverele din
cluster . Abilitatea de a putea scrie pe fiecare nod al clusterului suna ca un avantaj dar nu este neapă rat
unul, deoarece replicarea cu mai multe instanț e master face ca sistemul sa devina foarte complex .
Având o singura instanță master se va ș tii clar care date sunt corecte și sunt șanse foarte mici sa apară
conflicte in timpul replică rii.”[5]

1.4.4 Replicarea „Hot Standby”

„Acest tip de replicare implică doua sau mai multe servere:
 Un server principal pe care rulează baza de date activă care acceptă conexiun i de la clienți
și permite operații de citire si scriere.
 Doua sau mai multe servere standby pe care rulează o copie a bazei de date active. Aceste
baze de date sunt configurate să accepte conexiuni de la client și să permită doar operații
de citi re. Dac a baza de date principala nu mai poate fi accesata , sistemul poate fii
comuta t către unul din serverele standby, acest a din urma devenind noul server principal
activ.
Postgres SQL foloseș te tehnica WAL pentru a arhiva î n continu u tranzacț iile efectuat e, ceea ce
înseamnă ca înainte de a fii stocate î n baza de date , modifică rile aduse vor fii mai întâ i stocate in
loguri și apoi scrise î n baza de date. Procesul care actualizează serverul cu intrări WAL se numeș te
flux de replicare . Acest proces opere ază asincron, ceea ce înseamnă ca poate exista o întâ rziere intre
sincronizarea serverelor.
Postgres nu oferă nicio soluție automată de comutare între master și slave în cazul în care instanța
master este inaccesibilă .”[6]

20

21
Capitolul 2 Tehnologii folosite la realizarea aplicaț iei

2.1 Java

„Java este un limbaj de programare de nivel înalt, dezvoltat de JavaSoft, companie în cadrul
firmei Sun Microsystems.
Dintre caracteristicile principale ale limbajului amintim:
 simplitate – Java este un limbaj ușor d e învățat, caracteristicile complicate
(supraîncărcarea operatorilor, moștenirea multiplă, șabloane) întâlnite în alte limbaje
de programare sunt eliminate.
 robustețe , elimină sursele frecvente de erori ce apar în programare prin eliminarea
pointerilor, a dministrarea automată a memoriei și eliminarea fisurilor de memorie
printr -o procedură de colectare a 'gunoiului' care rulează în fundal.
 complet orientat pe obiecte – elimină complet stilul de programare procedural; se
bazează pe încapsulare, moștenire, p olimorfism
 ușurință în ceea ce privește programarea în rețea
 portabilitate , cu alte cuvinte Java este un limbaj independent de platforma pe care
lucreaza , aceeași aplicație rulând, fără nici o modificare, pe sisteme diferite cum ar fi
Windows, UNIX sau Ma cintosh, lucru care aduce economii substanțiale firmelor care
dezvoltă aplicații pentru Internet. Sloganul de bază este: „ Write once, run anywhere ”
 compilat și interpretat
 permite programarea cu fire de execuție (multithreaded)
 este modelat după C și C++ , trecerea de la C / C++ la Java făcându -se foarte ușor.
 permite dezvoltarea aplicațiilor pentru Internet – crearea unor documente Web
îmbunătățite cu animație și multimedia.

În funcție de modul de execuție al programelor, limbajele de programar e se împa rt în două
categorii:
 interpretate: instrucțiunile sunt citite linie cu linie de un program numit interpretor și
traduse în instrucțiuni mașină; avantaj: simplitate; dezavantaj: viteza de execuție
redusă;
 compilate: codul sursă al programelor este transfor mat de compilator într -un cod ce
poate fi executat direct de procesor; avantaj: execuție rapidă; dezavantaj: lipsa
portabilității, codul compilat într -un format de nivel scăzut nu poate fi rulat decât pe
platforma pe care a fost compilat.
Programele Java sunt atât interpretate cât și compilate .
Codul de octeți este diferit de codul mașină. Codul mașină este reprezentat de o succesiune de 0
și 1; codurile de octeți sunt seturi de instrucțiuni care seamănă cu codul scris în limbaj de asamblare.
Codul mașină este executat direct de către procesor și poate fi folosit numai pe platforma pe care a
fost creat; codul de octeți este interpretat de mediul Java și de aceea poate fi rulat pe orice platformă
care folosește mediul de execuție Java.

22
Fazele prin care trec e un program Java sunt:
Cod sursa Java -> (compilare) -> Cod de octeti -> (interpretare) >”[7]

2.2 Spring Boot

“Spring Boot este un proiect construit peste scheletul framework -ului Spring. Acesta permite
crearea, configurarea și rularea mai rapida atâ t a unor aplicații simple cât și web.

Dacă î n framework -ul Spring era nevoie sa configurezi toate lucrurile de unul singur in fiși ere
XML, ei bine Spring Boot rezolvă această problemă .

Acesta alege dependențele într -un mod inte ligent și configurează automat aplicația bazându -se pe
dependentele adă ugate de programator astfel încât procesul de rulare al aplicaț iei se reduce la un
singur click.

Avantaje :
 Auto -configurabil – sistemul inteligent de auto -configurare va încerca să configureze
automat aplicația b azându-se pe dependențele adăugate. De exemplu, daca vom adăuga o
dependența legată de o bază de date, Spring Boot va ș tii ca dorim sa folosim o conexiune
la baza de date și va configura aplicația în așa fel încâ t aceasta să permită realizarea
conexiunii.
 Independent – procesul de pornire al unei aplicații web presupune împachetarea aplicaț iei,
alegerea unui server web, configurarea s erverului web, si lansarea aplicației. C u Spring
Boot nu mai este nevoie de atâția pași, aplicația va fi împachetata î ntr-un jar si apoi aceasta
poate fii pornita folosind o comanda simpla precum
˃ java –jar aplicatie.jar
 Doctrinar – dezvoltând aplicații java, există o mulțime de alegeri ce trebuie fă cute precum
partea de web, sistemul de loguri, colecț ia de framework -uri si alte le. In ciuda acestui fapt
programatorii aleg sa folosească aproape î ntotdeauna cele mai populare librarii, astfel
Spring B oot intervine si le configurează î ntr-un mod standard pentru a reduce timpul
pierdut de programatori. ” [8]

2.3 HTML5

“HTML este abr evierea de la Hyper Text Markup Language. Acesta este limbajul în care sunt
realizate site -urile.
HTML5 este cea mai recentă versiune de HTML, în scopul de a s implifica dezvoltarea de aplicaț ii
web. Sintaxa HTML5 este mult mai ușoară în comparație cu HTML4 , și oferă multe caracteristici
noi. HTML este folosit pentru a crea structura paginii web. Spun em structură deoarece partea estetică
a unui site se poate realiza folosind CSS .
Ca orice limba j, HTML are propria sa sintaxă:
 Limbajul HTML este compus din etic hete care descriu părți diferite ale unei pagini .

23
 Etichetele HTML sunt plasate între simbolurile „ <” și „ >”: <eticheta>….</eticheta>
Majoritatea etichetelor sunt perechi .Fiecare pereche are o etichetă de deschidere și una de
închidere:
 <tag> – acesta est e tag -ul de deschidere;
 </tag> – acesta este tag -ul de închidere.
Orice documen t HTML conține 2 mari secțiuni:
 secțiune <head>conținut</head> – care oferă informații despre conținutul paginii
respective. Informația furnizată aici nu va fi vizibilă pe pagi na afișată în browser.
 secțiune <body>conținut</body> – informația furnizată aici va fi vizibilă pe pagină. “[9]

2.4 CSS

„Descrie modul în care elementele HTML vor fi afișate pe ecran, pe hârtie sau pe alte suporturi
media. Acesta poate controla aspectul mai multor pagini web simultan. Definițiile de stil sunt salvate
în mod normal în fișiere externe .css. Cu un fișier .css extern se poate modifica aspectul unui întreg
site web prin schimbarea unui singur fișier.” [ 10]

2.5 Bootstrap

“Este un framework dezvoltat iniț ial de Twitter dar care a devenit gratuit pentru publicul larg.
Acesta permite realizarea de site -uri web responsive, care se adaptează la orice rezoluț ie de dispozitiv :
desktop, tablete si telefoane mobile.
Boostrap este un instrume nt utiliza t pentru a gestiona cât mai bine faza inițială a unui proiect
deoarece putem conta pe o serie de comp onente care pot fi reutilizate ș i personalizate oferindu -ne o
baza solida de pornire a proiectel or noastre pentru a nu fi nevoiți sa î ncepem de la zero.
Bootstrap a dezvoltat un sistem de coloane – poate găzdui 12 coloane într -un rând. In funcț ie de
layout -ul variilor zone din pagina web coloanele se pot folosi î n varii combinații. Toate elementele
preconfecționate î n Bootstrap pot fi utilizate prin clase le CSS corespondente, denumite î n mod foarte
intuitiv.” [11]

2.6 Angular 7

“Angular, este o platfor ma gratuită pentru publicului larg, folosi t pentru construirea de interfețe
grafice ș i care are suport de la Google. Principalul ava ntaj oferit de angular a f ost că a transfor mat
documentele bazate pe HTML în conținut dinamic. Inițial limbajul folosit a fost JavaScript, iar in
2016 câ nd a fost lansat Angular 2, acesta s -a schimbat complet, fiind scris in TypeScript si devenind
la acel moment un limbaj bazat pe componente.
Câteva dintre beneficiile acestui framework sunt:
 Creste gradul de reutilizare al codului
 Face ca aplicația să poată fi testata mai uș or

24
 Aplicația va avea o structură mai curata
 Dezvoltare modulara
 Perfect pentru SPA
 Ușor de menț inut”[12]

2.7 Node.JS

“Node.js este un in terpretor sau un mediu de execuț ie pentru JavaScript care necesită ș i include o
mulțime de librarii. Acesta este d eschis publicului larg si folos ește programare asi ncrona.
Ce poate face Node.JS?
 Node.js poate genera conț inut di namic pe pagina.
 Poate crea, deschide, citi, scrie, șterge și închide fiș iere pe server.
 Node.js poate colecta date din formular.
 Poate adăuga, șterge, modifica date î ntr-o baza de date.

2.8 Npm

“Npm este cel mai mar e registru software. Acesta conț ine p este 800 000 de pachete de cod.
Programatorii care dezvoltă pentru publicul larg folosesc npm pentru a d istribui software. Acesta
vine î mpachetat in Node.js”[14]

2.9 JHipster

“Este o platforma de dezvoltare deschisă publicului larg care ajută la de zvoltarea ș i lansarea de
aplicații web sau microser vicii realizate cu Spring Boot si Angular/Reac t/Vue.”[15]

2.10 Maven

“Apache Maven este o unealta de management al proiectului. Maven poate coordona const ruirea
proiectului, raportarea ș i documentarea acestu ia.
Maven este responsabil de :
 Descărcarea dependenț elor
 Împachetarea codului binar
 Compilarea codului s ursă și generarea codului binar
 Rularea testelor
 Generarea documentaț iei
 Instalarea aplicației în mediul de producț ie sau de testare ” [16]

25

2.11 Git

“Git este un sistem de control de versiune distribuit. Conținutul stocat în git se schimbă pe masură
ce adăugam mai mult. Acesta ajută la menț inerea unui istoric al tuturor modifică rilor aduse de
contributorii unui proiect.
Un asemenea sistem este util de oarece, în majoritatea cazurilor există mai mulți programatori care
lucrează în paralel la acelaș i proiect. Folosind git nu vor apărea conflicte î ntre codul scris de
programatori. De asemenea Git este un si stem de backup al codului foarte bun , deoarece se poate
reveni oricând la o versiune anterioară .
Git este un sistem de control al versiunii distribuit, ceea ce înseamnă că fiecare persoana care
lucrează pe un proiect va avea local o copie a acestuia. ”[17]

2.12 REST

“Reprezintă un model ar hitectural de d ezvoltare a aplicațiilor w eb bazat pe reprezentarea datelor.
În acest de tip de arhitectură totul este privit ca o resursa. Orice poate fi referi t ca un obiect este o
resursa. Î n general tot ce poate fi stocat în calculator ș i reprezentat ca un flux de oct eti este o resursă .
Clienții pot interacționa cu reprezentă ri ale resurselor prin metode precum:
 GET: este cea mai folosită metodă, fiind utilizată atunci când serverului i se cere o resursă.
 POST – a fost proiectată pentru a trimi te date de intrare către server, pentru a crea noi
resurse
 DELETE – folosit pentru a ș terge resurse
 PUT – este utilizat î n cele mai multe cazuri pentru actualizări, dar este capabil și sa cre eze
resurse daca identificator ul resursei este dat de client ș i nu generat de server
 PAT CH – folosit pentru actualizarea parțial a unei reprezentă ri a unei resurse
 OPTIONS – este folosită pentru identificarea capacităților serverului Web, înainte de a
face o cerere.
 HEAD – se comportă exact ca metoda GET, dar serverul returnează doar antetul resursei,
ceea ce permite clientului să inspecteze antetul resursei, fără a fi nevoit să obțină și corpul
resursei.
Adresarea că tre un serviciu REST se face prin URI, iar fiecare cerere este independentă și
trebuie să conțină toate informațiile necesare pr ocesă rii.”[19]
Comunicația se realizează prin protocolul HTTP ș i reprezentare a resurselor poate fi transmis ă
în format :
 “JSON – format de reprezentare ș i inte rschimbare de date intre aplicaț ii” [20]
 “XML – meta -limbaj de marcare folosit pentru stocarea si transportul datelor” [21]

26
2.13 Swagger

Aplicaț ia fiind bazata pe un API , am considerat ca este necesară documentarea acestuia. Pentru
asta am folosit Swagger, care este cea mai folosită unealta de documentare și care este gratuită pentru
publicul larg.

27
Capitolul 3 Proiectare ș i implementare

3.1 Baza de date

Sistemul de baze de date folosit este PostgreSQL. Am ales sa folosesc SGBD -ul PostgreSQL,
deoarece este disponibil gratuit și își bazează dezvoltarea pe o comunitate răspandită la nivel global.

Figura 3.1 Diagrama bazei de date
După cum se poate deduce din diagram a de mai sus, aplicația nu va putea fii folosită fără
înregistrarea unui cont, d eoarece compo nentele acesteia sunt strâ ns legate de utilizator.
Tipuri de relaț ii intre tabele:
 Unu la unu:
o jhi_user – attachment
o user_data – jhi_user
o user_data – attachment

 Unu la mai multi:
o agenda – jhi_user
o attachment – album
o album – jhi_user
o device – jhi_user
o scheduled_item – agenda

28
3.2 Prezentarea aplicaț iei

3.2.1 Arhitectura

Aplicaț ia este una de tip monolit si folosește ca ș i componente principale:
 Spring Boot
 Java
 Angular

Figura 3.2 Structura Aplicatiei [ 22]
Aplicația se bazează pe interacț iunea dintre Angular ș i serviciile R EST realizate in Java,
interacțiune care se face prin cereri HTTP. Securizarea aplicaț iei a fost realizata cu ajutorul
framework -ului Spring Secu rity, framewor k foarte customizabil ce permite gestionarea aut entificării
și autorizării in aplicațiile J ava.

3.2.2 Interfaț a cu utlizatorul

Interfata cu utilizatorul a aplicat iei este impartita in trei zone :
 Zona de navigare în aplicaț ie (NAVBAR)
 Zona în care este plasat conț inutul propriu -zis (BODY)
 Zona de copyright (FOOTER)

29

Figura 3.3 Pagina principala aplicaț iei (neautentificat)
După cum se poate observa , zona de navigați e este alcă tuită din mai multe elemente după cum
urmează :
 In partea stâ ngă este sigla aplicației care ne va direcț iona către pagina principală
 In partea dreaptă avem butoanele c e ne permit sa navigam:
o Butonul “Ho me” care ne permite navigarea că tre pagina principal a
o Un buton expand abil care ne permite navigarea în zona de înregistrare ș i
autentificare
Zona în care este plasat conț inutul , conț ine un mesaj de bu n venit pentru utilizatori dar ș i un mesaj
care ne spune ca nu suntem autentificați încă si va treb ui sa ne î nregistram sau sa ne autentificam.
Subsolul ne oferă inf ormații referitoare la drepturile de copiere .

Figura 3.4 Pagina de î nregistrare a a plicaț iei

30
Această pagina conț ine un formular prin care ne putem înregistra completând câteva câ mpuri
precum:
 Nume de ultilizator
 Email
 Parola
 Confirmarea parolei
Pe măsură ce completăm în câ mpurile formularului aces tea sunt validate, iar atunci când ne
alegem parola aplicaț ia ne va spune cat de puternica este.
După apăsarea butonului de î nregistrare aplic ația va trimite un mail de confirmare la adres a de
email. Fără această confirma re nu ne vom putea autentifica în aplicaț ie.

Figura 3.5 Pagina de activare a contului si modalul de autentificare
După accesarea link -ului de activare primit prin e -mail ne p utem autentifica în aplicaț ie.
La apă sarea butonului “Sign in” se va deschide mod alul din figura de mai sus în care avem un
formular care trebuie completat cu numele de utilizator ales în prealabil ș i parola.

Figura 3.6 Pagina principală după autentifi care

31
După autentificare putem observa mesajul personalizat din prima pagina dar ș i noile butoane
apărute în zona de navigaț ie:
 Album
 Agenda
 Settings
 Sign Out

Figura 3.7 Pagina cu albume
În aceasta secț iune putem vizualiza albumele create de utilizat or. De asemenea , daca se dorește
adăugarea unui album nou se poate folosi butonul de adăugare situat î n dreapta sus. Pentru a vizualiza
conținutul unui album, se va da click pe albumul dorit.

Figura 3.8 Pagina de creare a unui album
Acesta pagina conț ine formularul de creare a unui album in care trebuie sa completam numele
albumului pe care îl creăm si descrier ea acestuia . Pentru finalizare se apasă butonul care indică salvarea.

32

Figura 3.9 Pagina de vizualizare a unui album
Această pagină conține po zele încărcate î n albumul curent . Buto anele aflate in dreapta sus ne
permit sa ad ăugam poze noi la album sau să edităm informaț iile albumului curent. Pentru editarea
unei poze sau ștergerea acesteia din album se va da click pe poza dorita.

Figura 3.10 Pagina de prezentare a agendelor
In aceasta pagină sunt prezentate toate agendele pe care utilizatorul le -a creat. Folosind butonul
din dreapta sus avem posibilitate sa cre ăm agende noi. În funcție de tipul agendei, acesteia îi este
atribuit automat un simb ol reprezentativ.

33

Figura 3.11 pagina de creare a unei agende
Această pagină conține un formular ce ne permite sa creăm diferite tipuri de agende după cum
urmează :
 Agendă pentru a programa vizitele la medic ale copilului (DOCTOR)
 Agendă pentru administ rarea tratamentului prescris de medic (TREATMENT )
 Agendă pentru respectarea programului de somn al copilului (SLEEP)
 Agendă pentru respectarea programului de hrănire al copilului (FEED)
 Agendă personalizată de utilizator (DUMMY)

Figura 3.12 Pagina de pr ezentare a unei agende.
Pagina de prezentare a agendei. Ace asta ne prezintă î n ordine cronologica lista evenimentel or ce
urmează sa se întâmple . În dreapta sus avem doua butoane cu care putem edita agenda curenta dar si
prin care putem adăuga evenimente no i.
De exemplu , am creat mai sus „Treatment Agenda ” in care am introdus detalii privind tratamentul
administrat copilului, ora la care trebuie administrat precum si ca ntitatea ce trebuie administrată .

34

Figura 3.13 Pagina de schimbare a parolei
In ace asta pagină aveam po sibilitatea de a ne schimba parola confirmând parola curenta ș i
introducând noua parolă .

Figur a 3.14 Pagina cu setări ale utilizatorului
Aceasta pagină permite utilizatorului își modifice informațiile personale.

35
Capitolul 4 Instal are ș i configurare

4.1 Pregătire mediu de dezvoltare aplicație

În cele ce urmează vom detalia pașii ce trebuie urmați pentru instalarea tehnologiei Java, a
mediului integ rat de dezvoltare Intelij IDEA ș i a modulelor nec esare pentru realizarea proiectulu i.

4.1.1 Instalare JDK versiunea 8

Se descarcă executabilul de pe pagina oficială și se in stalează . În urma acestui pas va trebui să
setăm calea în variabilele de sistem conform următorilor pași:
Click pe Start – Control Panel – System
Advance – Environm ent Variables – System Variables
Click pe butonul „New” si vom crea o nouă variabilă de sistem cu numele „JAVA_HOME”, iar
la valoare vom adăuga calea către directorul JDK .

Figura 4.1 Adăugare variabila de sistem JAVA_HOME

Se alege variabil a „Path” – Edit și se adaugă o noua cale către directorul „bin” aflat in directorul î n care este instalat JDK

Figura 4.2 Adăugare cale către directorul „bin” pentru JDK

36
4.1.2 Instalare IDE

În acest proiect am ales să folosesc Intellij IDEA , deoarece deține multe module utile și ajutăto are
pentru o astfel de aplicație ș i totodată este mediul de dezvoltare cu care sunt familiarizat.
Pentru a instala și configura mediul integrat de dezvoltare, se descarcă pachetul de instalare de pe
pagina oficiala https://www.jetbrains.com/idea/download/ și se instalează versiunea Ultimate .

4.1.3 Instalare Maven

Se descarcă Maven de pe pagina oficiala https://maven.apache.o rg/download.cgi , alegându -se
varianta “Source zip archive” și se dezarhivea ză pe disc.
Se adaugă o noua variabilă de sistem “MAVEN_HOME” care va indica că tre directorul maven.

Figura 4.3 Adăugare v ariabilă de sistem MAVEN _HOME

Am adăugat la variabi la “Path” locația că tre directorul „bin” din directorul maven.

Figura 4.4 Adăugare cale că tre directorul „bin” pentru Maven

37
4.2 Preg ătire sistem de replicare PostgreSQL

4.2.1 Instalare Virtual Box

 Se accesează site -ul oficial http://virtualbox.org , sectiunea “Downloads”
 Se descarcă în funcț ie de sistemul de operare pachetul de instalare
 Se instalează VirtualBox

4.2.2 Pregatirea masinii virtuale cu Ubuntu 16.04

 Se descarcă distribuț ia de linux Ubuntu 16. 04.6 LTS (Xenial Xerus) de la adresa
http://releases.ubuntu.com/16.04/
 Se deschide Virtua l Box ș i se apasa butonul “New”
 Se da un nume mașinii, se alege tipul “Linux” si versiunea “U buntu” si se trece la pa sul
urmă tor
 Se alocă minimum 2GB de memorie RAM ce va fi folosită de maș ina virtuala
 Se trece la pasul următor și se selectează crearea unui h ard disk virtual nou si se apasă butonu l
“Create”
 Se merge in panoul din stâ nga la VirtualBox se selectează mașin a virtuală creată și se apasă
butonul “Settings”
 Se navighează î n tabul „System ” la categoria „Proce ssor„ și se aloca 2 nuclee
 Se navighează î n tabul „Network ” și se alege opț iunea Attached to: “Bridged Adapter ”
 In tabul „Storage ” se selectează Controlle r: IDE Empty , se da click pe ico nița î n forma de CD
se alege “Choos e a virtual optical disk file” și se alege fișierul cu distribuția de linux
descărcată la primul pas.
 Se selectează mașina creată și se apasă butonu l „Start” pentru a pornii instalarea
 Se alege limba și se apasă butonul “ Install U buntu” apoi “Continue”
 Se selectează opț iunea “ Erase disk and install Ubuntu” și se apasă butonul “Install Now” apo i
“Continue”
 Se ale ge Regiunea si Limba si se apasă “Continue ” așteptâ ndu-se ca instalarea sa se fin alizeze

4.2.3 Instalare PostgreSQL

PostgreSQL 11 nu este disponibil pentru distr ibuția de linux Ubuntu 16.04 LTS. Pentru a -l putea
instala va trebui sa importă m o cheie pentru a avea acces la pachetele PostgreSQL rulând urmă torul
set de comenzi:
˃ sudo ap t-get install wget ca -certificates
˃ wget –quiet -O – https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt -key
add –
Se adaugă repository -ul oficial Postgres ruland urmatoarea comanda:
˃ sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main"
>> /etc/apt/sources.list.d/pgdg.list'
Acum ca avem repository -ul oficial adaugat în sistem vom rula urmă toarele comenzi pentru a
actualiza lista de repository -uri și pentru a instala PostgreSQL:
˃ sudo apt -get update
˃ sudo apt -get install postgresql postgresql -contrib

38
Pentru a putea realiza comunicaț ia dintre serverul master si cel slave avem nevoie sa
deschidem portul folosit de postgres „ 5432”. Pentru asta vom instala o unealta care ne va permit e sa
facem acest lucru foarte uș or.
Instalam UFW rulâ nd in terminal comanda:
˃ apt-get install -y ufw
Adăugam postgres în lista de excepț ii folosind comanda:
˃ ufw allow postgresql
Pornim UFW și verif icăm statusul rulând urmă toarele comenzi:
˃ ufw enable
˃ ufw status

4.2.4 Clonarea maș inii virt uale

După instalarea PostgresSQL vom clona maș ina virtuala pentru a putea realiza procesul de
replicare.
Pentru a realiza clonarea se oprește maș ina virtua lă creată mai devreme, se selectează mașina și
se merge în meniu la Machine – Clone. Am ales ca prim a mașină create sa fie cea master si clona sa
fie slave.
In fereastra care s-a deschis vom seta numele maș inii “slave” iar la “MAC Address Policy” vom
selecta “ Generate new MAC addre sses for all network adapters” și apă sam butonul “Next”
Se alege “Full c lone” la tipul clonei și se apasă butonul “Clone”
Se pornesc ambele maș ini virtuale si vom schimba hostname -ul pentru a le putea identifica
mai ușor folosind coman da de mai jos pentru fiecare maș ina.
˃ sudo hostnamectl set -hostname master
˃ sudo hostnamectl set-hostname slave
Pentru a continua avem nevoie sa aflam ip -ul fiecărei maș ini virtual e. Pentru a afla ip -ul vom rula
comanda si vom salva ip -ul.
˃ ip a
In cazul meu cele doua ip -uri sunt:
 192.168.0.100 – master
 192.168.0.105 –slave

4.2.4 Co nfigurare Mast er

„Vom deschide pentru editare fișerul “postgresql.conf” din directorul de configurare postgres.
˃ cd /etc/postgresql/11/main/
˃ vim postgresql.conf
Vom activa ș i seta următorii parametrii după cum urmează :
listen_addresses = '192.168.0.100 '
wal_level = hot _standby
synchronous_commit = local
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/11/main/archive/%f'
max_wal_senders = 2
wal_keep_segments = 10
synchronous_standby_names = 'pgslave001'

Pentru ca am activat arhivarea este nevoie să creăm un director pentru arhiva și să î i atribuim
dreptur i utilizatorului “postgres” rulâ nd urmă toarele comenzi:
˃ mkdir -p /var/lib/postgresql/11/main/archive/

39
˃ chmod 700 /var/lib/postgresql/11/main/archive/
˃ chown -R postgres:postgres /var/lib/postgresql/11/main/a rchive/

Următorul pas constă în editarea fiș ierului „pg_hba.conf ” aflat tot î n directorul de configurare
postgres . Vom adăuga la sfârșitul fișierului urmă toarele linii pentru autentificare.
# PostgreSQL Master IP address
host replication replica 192.168.0.100/24 md5

# PostgreSQL Sl ave IP address
host replication replica 192.168.0.105/24 md5

Am restartat insta nța de postgres rulâ nd comanda
˃ systemctl restart postgresql
Am creat un utilizator care va fi folosit la replicare pentru asta se rulează urmă toarele comenzi :
˃ su – postgres
˃ psql
˃ CREATE USER replica REPLICATION LOGIN ENCRYPTED PASSWORD
‘replicauser@ ’;
Pentru verificare se rulează comanda și se verifică ca ieș irea sa fie ca cea din figura de mai j os.
˃ \du

Figura 4.5 Testarea utilizatorului de replicare
4.2.5 Configurare Slave

Am oprit instanța de postgres rulâ nd comanda
˃ Systemctl stop postgresql
Am mers î n directorul de configu rare și am deschis fiș ierul „postgresql .conf ”
˃ cd /etc/postgresql/9.6 /main/
˃ vim postgresql.conf
Am setat următorii parametrii și am slavat fiș ierul:
listen_addresses = '192.168.0.105'
wal_level = hot_standby
synchronous_commit = local
max_wal_senders = 2
wal_keep_segments = 10
synchronous_standby_names = 'pgslave001'
hot_s tandby = on
Urmă toarea etapa a fost copierea directorului “main” de pe serverul master pe serverul slave.
M-am conectat cu utilizatorul postgres
˃ su – postgres

40
Am reden umit directorul main î n main -backup
˃ cd 11/
˃ mv main main -backup
Am creat un nou director m ain și i-am setat permisiunile
˃ mkdir main/
˃ chmod 700 main/
Folosind comanda „pg_basebackup ” și utilizatorul creat pe master “replica” am copiat directorul
main din master pe serverul slave
˃ pg_basebackup -h 192.168.0.100 -U replica -D /var/lib/postgresql/1 1/main -P –xlog
Am mers î n directorul main și am creat un fiș ier numit “r ecovery.conf” pe care serverul î l va
folosi la pornirea pentru a putea folosi backup -ul creat anterior.
In fiș ierul „recovery.conf ” am setat următoarea configuraț ie:
standby_mode = 'o n'
primary_conninfo = 'host=192.168.0.100 port=5432 user=replica password=replicauser@
application_name=pgslave001'
restore_command = 'cp /var/lib/postgresql/11/main/archive/%f %p'
trigger_file = '/tmp/postgresql.trigger.5432
Am setat permisiunile acestui fișier :
˃ chmod 600 recovery.conf
Am pornit serviciul PostgreSQL
˃ systemctl start postgresql

4.2.6 Testare proces de replicare

Pentru testare, m -am conectat pe serverul m aster ș i am creat o tabela în care am adăugat c âteva
intrări:
˃ su – postgres
˃ psql
˃ CREATE TABLE sesiuni_licenta (sesiune varchar(100));
˃ INSERT INTO sesiuni_licenta VALUES ( 'iulie 2019 ');
˃ INSERT INTO sesiuni_licenta VALUES ('septembrie 2019 ');
M-am conectat pe s erverul slave ș i am interogat baza pentru a verifica daca replicarea a
funcț ionat:
˃ su – postgres
˃ psql
˃ select * from sesiuni_licenta; ”[24]

41
Rezultatul a fost urmă torul:

Figura 4.6 Testare replicare (master)

Figura 4.7 Testare replicare ( slave )
Un alt test care se poate face este î ncercarea de inserare a datelor în tabel a de pe serverul slave
care ar trebui să se finalizeze cu o eroare deoarece serverul slave permite doar citirea de date.
˃ INSERT INTO sesiuni_licenta VALUES ('februarie 2020 ');

42

Figura 4.8 Testare replicare prin inserare de date (slave)

43
Concluzii

Prezentul proiect a avut ca scop realiz area unei aplicaț ii rezistente la defecte cu ajutorul
sistemului de gestiune a bazelor de date PostgreSQL . Am ales sa folosesc SGBD -ul PostgreSQL,
deoarece este disponibil gratuit și îș i bazeaza devol tarea pe o comunitat e răspandită la nivel global .

Principalele obiect ive ale proiectului au fost:
 Studiu l bazelor de date distribuite implementate î n sistemul de gestiune a bazelor de date
PostgreSQL
 Crearea unui sistem de recuperare a datelor î n caz de dezastre naturale folosind procesul
de replicare disponibil în SGBD -ul PostgreSQL
 Realizarea unei aplicații web pentru părinți ce va permite utilizatorilor să își personalize
programul zilnic, să respecte rutina zilnică a copiilor și să îndeplinească task -urile zilnice

In procesul de realizare a acestui proiect am constat că :
 replicarea bazei de date este o bună metodă de backup pentru un centru de date î n cazul
unui dezastru natural
 replicarea bazei de date este o metoda utiliza de a face ca aplicațiile web să aibă un timp
de încărcare mai bun atunci câ nd sunt suprasolicitate, distribuind cererile de interogare ,
care î n mod normal vin catre o singura bază de date , către replici ale acestia.
 timpul de raspuns poate fi micș orat având câ te o replică a bazei de date î n fiecare zon a
geografi ca importantă astfel încat aplicația să se conecteze la cea mai apropiată replică
 în cazul unei analize pe o bază de date ce conț ine miliarde de int rări, pentru a nu
suprasolicita serverul ș i sistemul de gestiune al bazei de date, se poate face a naliza ruland
interogările pe o instanță de tip slave a bazei principale

Contribuții personale aduse acestui proiect:
 Realizarea aplicaț iei web
 Configurarea si instalarea maș inilor virtuale
 Realizarea documentației proiectului de diplomă;

Luând în con siderare cele menț ionate mai sus, a plicația realizată poate reprezenta un punct de
plecare în realizarea unei comunității virtuale cu oameni deveniți părinț i în vederea împărtășirii de
informații în ceea ce privește creșterea ș i devoltarea copilului.
Pe vi itor doresc să continui dezvoltarea acestui proiect adăugând următoarele funcționalităț i:
 un sistem automat de balansare între bazele de date în cazul indisponibilităț ii serverului
master
 adăugarea unui nou tip de utilizator, persoana jurdica, care să își poată promova pe această
platformă servicii destinate proaspeților pă rinti
 posibilitatea de a distribui propriile agende cu alți utilizatori, î n cazul î n care copilul
rămâ ne cu bona/alte perso ane, astfel încat programul acestuia să fie respectat
 implementa rea unei secțiuni care să atragă specialiști care să publice conț inut adecvat
pentru utilizatori

44

45
Bibliografie

[1] Database Fundamentals, Neeraj Sharma, Liviu Perniu, Raul F. Chong, Abhishek Iyer, Chaitali
Nandan, Adi -Cristina Mitea, Mallarswami No nvinkere, Mirela Danubianu , IBM Corporation 2010,
http://public.dhe.ibm.com/software/dw/db2/express -c/wiki/Database_fundamentals.pdf , accesat la
data: 09.03. 2019
[2] Curs Proiectarea Bazelor de Date, profesori Felicia Ionescu si Valentin Pupezescu
[3] Introducere – Concepte de bază privind sistemele de baze de date,
http://webbut.unitbv.ro/carti%20on -line/Ratiu/BD/Cap.1.pdf , accesat la data : 09.03.2019
[4] Replicarea bazelor de date
http://stst.elia.pub.ro/news/soa/Teme_SOA_14_15/SOA_Stoica_Se_Replicarea%20bazelor%20de
%20date_2.docx , accesat la data 09 .03.2019
[5] PostgreSQL Replication, Zoltan Böszörmenyi, Hans -Jürgen Schönig,
https://books.google.ro/books?id= lXu74U9_ZpwC&lpg=PA1&dq=postgres%20replication&hl=ro
&pg=PT5#v=onepage&q=postgres%20replication&f=false , accesat la 27.03.2019
[6] How to set up PostgreSQL for high availability and replication with Hot Standby
,https://cloud.google.com/community/tutorials/setting -up-postgres -hot-standby , accesat la
15.04 .2019
[7] Curs practic de Java, https://profs.info.uaic.ro/~acf/java/Cristian_Frasinaru –
Curs_practic_de_Java.pdf , accesat la 15.04 .2019
[8] What Is Spring Boot? , https://dzone.com/articles/what -is-spring -boot, accestat la 04.05 .2019
[9] Introducere. Ce este HTML? Ce este HTML5? Reguli de baza, https://azimutvision.ro/unit/a -ce-
este-html/ , accesat 04.05 .2019
[10]CSS Introduction, https://www.w3schools.com/css/css_intro.asp , accesat la 04.05 .2019
[11] Introducerere la Bootsrap, https://www.multimedia -creations.a cademy/introducere -la-
bootstrap -3/, accesat la 04.05 .2019
[12] The Good and the Bad of Angular Development,
https://www.altexsoft.com/blog/engineering /the-good -and-the-bad-of-angular -development/ ,
accesat la 23.05 .2019
[13] Despre Node.JS https://marplo.net/javascript/tutoriale -nodejs -js, accesat la 23.05 .2019
[14]What is npm?, https://www.w3schools.com/whatis/whatis_npm.asp , accesat la 23.05 .2019
[15] What is JHipster, https://www.jhipster.tech/ , accesat la 29.05 .2019
[16] Introduc ere în maven,
http://control.aut.utcluj.ro/hmihai/lib/exe/fetch.php?media=isp:cursuri2018:introducere_in_maven_r
o_.pdf , accesat la 29.05.2019
[17] What is Git and how to use it? , https://www.freecodecamp.org/news/what -is-git-and-how-to-
use-it-c341b049ae61/ , accesat la 02.06 .2019
[18] Introducer e in baze de date, http://www.scritub.com/stiinta/informatica/INTRODUCERE -IN-
BAZE -DE-DATE13191425.php , accesat la 02.06 .2019

46
[19] Servicii Web – REST ,
https://profs.info.uaic.ro/~busaco/teach/courses/web/presentations/web11ServiciiWeb -REST.pdf ,
accesat la 06.0 7.2019
[20] JSON, https://ro.wikipedia.org/wiki/JSON , accesat la 05.0 8.2019
[21] XML, https://ro.wikipedia.org/wiki/XML , accesat la 05.0 8.2019
[22] Figura , https://www.slideshare.net/Pivotal/jhipster -170620184413 accesat la 05.08 .2019
[23]Sisteme de baze de date, Introducere, http://www.scritub.com/stiinta/informatica/baze -de-
date/SISTEME -DE-BAZE -DE-DATE -INTROD32525.php , accesat la 0 7.08.2019
[24] How to set up master slave replication for posgresql 9.6 on Ubuntu 16.04,
https://www.howtoforge.com/tutorial/how -to-set-up-master -slave -replication -for-postgresql -96-on-
ubuntu -1604/ , accesat la 16.08 .2019

47
Anexe

Anexa 1 Cod Sursa Java

AgendaResource .java

package com.upb.etti.web.rest;

import com.upb.etti.domain.Agenda;
import com.upb.etti.repository.AgendaRepository;
import com.upb.etti.security.SecurityUtils;
import com.upb.etti.service.UserService;
import com.upb.etti.web.rest.errors.BadRequestAl ertException;

import io.github.jhipster.web.util.HeaderUtil;
import io.github.jhipster.web.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframewor k.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.net.URISyntaxExc eption;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;

/**
* REST controller for managing {@link com.upb.etti.domain.Agenda}.
*/
@RestController
@RequestMapping("/api")
public class AgendaResource {

@Autowired
UserService userService;

private final Logger log = LoggerFactory.getLogger(AgendaResource.class);

private static final String ENTITY_NAME = "agenda";

@Value("${jhipster.clientApp.name}")
private String applicationName;

private fi nal AgendaRepository agendaRepository;

public AgendaResource(AgendaRepository agendaRepository) {

48
this.agendaRepository = agendaRepository;
}

/**
* {@code POST /agenda} : Create a new agenda.
*
* @param agenda the agen da to create.
* @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the
new agenda, or with status {@code 400 (Bad Request)} if the agenda has already an ID.
* @throws URISyntaxException if the Location URI syn tax is incorrect.
*/
@PostMapping("/agenda")
public ResponseEntity<Agenda> createAgenda(@RequestBody Agenda agenda) throws
URISyntaxException {
log.debug("REST request to save Agenda : {}", agenda);
if (agenda.getId() != null) {
throw new BadRequestAlertException("A new agenda cannot already have an ID",
ENTITY_NAME, "idexists");
}
agenda.setUser(userService.getUserWithAuthorities().get());
agenda.setCreateDate(ZonedDateTime.now());
Agenda result = agendaRepository.save(agenda);
return ResponseEntity.created(new URI("/api/agenda/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME,
result.getId().toString()))
.body(result);
}

/**
* {@code PUT /agenda} : Updates an existing agenda.
*
* @param agenda the agenda to update.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
updated agenda,
* or with status {@code 400 (Bad Request)} if the agenda is not valid,
* or with status {@code 500 (Internal Server Error)} if the agenda couldn't be updated.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PutMapping("/ agenda")
public ResponseEntity<Agenda> updateAgenda(@RequestBody Agenda agenda) throws
URISyntaxException {
log.debug("REST request to update Agenda : {}", agenda);
if (agenda.getId() == null) {
throw new BadRequestAlertExce ption("Invalid id", ENTITY_NAME, "idnull");
}

if(!agenda.getUser().getLogin().equals(userService.getUserWithAuthorities().get().getLogin())){
throw new BadRequestAlertException("Not authorized", ENTITY_NAME,"notauth");
}
agenda.setUpdateDate(ZonedDateTime.now());
Agenda result = agendaRepository.save(agenda);
return ResponseEntity.ok()

49
.headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME,
agenda.getId().toStrin g()))
.body(result);
}

/**
* {@code GET /agenda} : get all the agenda.
*
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of agenda
in body.
*/
@GetMapping("/agenda")
public Li st<Agenda> getAllAgenda() {
log.debug("REST request to get all Agenda");
return agendaRepository.findByUserIsCurrentUser();
}

/**
* {@code GET /agenda/:id} : get the "id" agenda.
*
* @param id the id of the agenda t o retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
agenda, or with status {@code 404 (Not Found)}.
*/
@GetMapping("/agenda/{id}")
public ResponseEntity<Agenda> getAgenda(@PathVariable Long id) {
log.debug("REST request to get Agenda : {}", id);
Optional<Agenda> agenda = agendaRepository.findByUserIsCurrentUserAndId(id);
return ResponseUtil.wrapOrNotFound(agenda);
}

/**
* {@code DELETE /agenda/:id} : delete the "id" agenda.
*
* @param id the id of the agenda to delete.
* @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/agenda/{id}")
public ResponseEntity<Void> deleteAgenda(@PathVariable L ong id) {
log.debug("REST request to delete Agenda : {}", id);
agendaRepository.deleteById(id);
return
ResponseEntity.noContent().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true,
ENTITY_NAME, id.toString())).build ();
}
}

50
ScheduledItem.java

package com.upb.etti.web.rest;

import com.upb.etti.domain.ScheduledItem;
import com.upb.etti.repository.ScheduledItemRepository;
import com.upb.etti.web.rest.errors.BadRequestAlertException;

import io.github.jhipste r.web.util.HeaderUtil;
import io.github.jhipster.web.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springfra mework.web.bind.annotation.*;

import java.net.URI;
import java.net.URISyntaxException;

import java.util.List;
import java.util.Optional;

/**
* REST controller for managing {@link com.upb.etti.domain.ScheduledItem}.
*/
@RestController
@RequestMapping(" /api")
public class ScheduledItemResource {

private final Logger log = LoggerFactory.getLogger(ScheduledItemResource.class);

private static final String ENTITY_NAME = "scheduledItem";

@Value("${jhipster.clientApp.name}")
private String a pplicationName;

private final ScheduledItemRepository scheduledItemRepository;

public ScheduledItemResource(ScheduledItemRepository scheduledItemRepository) {
this.scheduledItemRepository = scheduledItemRepository;
}

/**
* {@code POST /scheduled -items} : Create a new scheduledItem.
*
* @param scheduledItem the scheduledItem to create.
* @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the
new scheduledItem, or with status {@co de 400 (Bad Request)} if the scheduledItem has already an
ID.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PostMapping("/scheduled -items")

51
public ResponseEntity<ScheduledItem> createScheduledItem(@RequestBody ScheduledItem
scheduledItem) throws URISyntaxException {
log.debug("REST request to save ScheduledItem : {}", scheduledItem);
if (scheduledItem.getId() != null) {
throw new BadRequestAlertException("A new scheduledItem cannot al ready have an
ID", ENTITY_NAME, "idexists");
}
ScheduledItem result = scheduledItemRepository.save(scheduledItem);
return ResponseEntity.created(new URI("/api/scheduled -items/" + result.getId()))
.headers(HeaderUtil.crea teEntityCreationAlert(applicationName, true, ENTITY_NAME,
result.getId().toString()))
.body(result);
}

/**
* {@code PUT /scheduled -items} : Updates an existing scheduledItem.
*
* @param scheduledItem the scheduledItem t o update.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
updated scheduledItem,
* or with status {@code 400 (Bad Request)} if the scheduledItem is not valid,
* or with status {@code 500 (Internal Server E rror)} if the scheduledItem couldn't be updated.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PutMapping("/scheduled -items")
public ResponseEntity<ScheduledItem> updateScheduledItem(@RequestBody
ScheduledItem scheduledItem) throws URISyntaxException {
log.debug("REST request to update ScheduledItem : {}", scheduledItem);
if (scheduledItem.getId() == null) {
throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
}
ScheduledItem result = scheduledItemRepository.save(scheduledItem);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME,
scheduledItem.getId().toString()))
.body(result);
}

/**
* {@code GET /scheduled -items} : get all the scheduledItems.
*
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of
scheduledItems in body.
*/
@GetMapping("/scheduled -items ")
public List<ScheduledItem> getAllScheduledItems() {
log.debug("REST request to get all ScheduledItems");
return scheduledItemRepository.findAll();
}

/**
* {@code GET /scheduled -items/sorted} : get all the scheduledItem s sorted.

52
*
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of
scheduledItems in body.
*/
@GetMapping("/scheduled -items/sorted")
public List<ScheduledItem> getAllScheduledItemsSortedByScheduleAt() {
log.debug("REST request to get all ScheduledItems sorted by schedule date");
return scheduledItemRepository.findAllByOrderByScheduledAtAsc();
}

/**
* {@code GET /scheduled -items/:id} : get the "id" scheduledItem.
*
* @param id the id of the scheduledItem to retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
scheduledItem, or with status {@code 404 (Not Found)}.
*/
@GetMapping("/scheduled -items/{id}")
public ResponseEntity<ScheduledItem> getScheduledItem(@PathVariable Long id) {
log.debug("REST request to get ScheduledItem : {}", id);
Optional<ScheduledItem> scheduledItem = scheduledItemRepository.findById(id);
return ResponseUtil .wrapOrNotFound(scheduledItem);
}

/**
* {@code GET /scheduled -items/agenda/{agendaId}} : get all scheduledItems by agenda "id"
.
*
* @param agendaId the id of the Agenda to retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
scheduledItem, or with status {@code 404 (Not Found)}.
*/
@GetMapping("/scheduled -items/agenda/{agendaId}")
public List<ScheduledItem> getScheduledItemFromAgenda(@PathVariable Long agendaId)
{
log.debug("REST request to get all ScheduledItems from agenda : {}", agendaId);
return scheduledItemRepository.findByAgenda_IdOrderByScheduledAtAsc(agendaId);
}

/**
* {@code DELETE /scheduled -items/:id} : delete the "id" scheduledIte m.
*
* @param id the id of the scheduledItem to delete.
* @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/scheduled -items/{id}")
public ResponseEntity<Void> deleteScheduledItem(@PathV ariable Long id) {
log.debug("REST request to delete ScheduledItem : {}", id);
scheduledItemRepository.deleteById(id);

53
return
ResponseEntity.noContent().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true,
ENTITY_NAME , id.toString())).build();
}
}

AlbumResource.java

package com.upb.etti.web.rest;

import com.upb.etti.domain.Album;
import com.upb.etti.repository.AlbumRepository;
import com.upb.etti.service.UserService;
import com.upb.etti.web.rest.errors.BadRequ estAlertException;

import io.github.jhipster.web.util.HeaderUtil;
import io.github.jhipster.web.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.net.URISyntaxException;

import java.time.ZonedDateTime;
import j ava.util.List;
import java.util.Optional;

/**
* REST controller for managing {@link com.upb.etti.domain.Album}.
*/
@RestController
@RequestMapping("/api")
public class AlbumResource {

@Autowired
private UserService userService;

private fin al Logger log = LoggerFactory.getLogger(AlbumResource.class);

private static final String ENTITY_NAME = "album";

@Value("${jhipster.clientApp.name}")
private String applicationName;

private final AlbumRepository albumRepository;

54
public AlbumResource(AlbumRepository albumRepository) {
this.albumRepository = albumRepository;
}

/**
* {@code POST /albums} : Create a new album.
*
* @param album the album to create.
* @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the
new album, or with status {@code 400 (Bad Request)} if the album has already an ID.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PostMapping("/albums")
public ResponseEntity<Album> createAlbum(@RequestBody Album album) throws
URISyntaxException {
log.debug("REST request to save Album : {}", album);
if (album.getId() != null) {
throw new BadRequestAlertException("A new album cannot already have an ID",
ENTITY_NAME, "idexists");
}
album.setUser(userService.getUserWithAuthorities().get());
album.setCreateDate(ZonedDateTime.now());
Album result = albumRepository.save(album);
return ResponseEntity. created(new URI("/api/albums/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME,
result.getId().toString()))
.body(result);
}

/**
* {@code PUT /albums} : Updates an e xisting album.
*
* @param album the album to update.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
updated album,
* or with status {@code 400 (Bad Request)} if the album is not valid,
* or with status {@code 500 (Internal Server Error)} if the album couldn't be updated.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PutMapping("/albums")
public ResponseEntity<Album> updateAlbum(@RequestBody Album albu m) throws
URISyntaxException {
log.debug("REST request to update Album : {}", album);
if (album.getId() == null) {
throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
}

if(!album.getUser().ge tLogin().equals(userService.getUserWithAuthorities().get().getLogin())){
throw new BadRequestAlertException("Not authorized", ENTITY_NAME,"notauth");
}
album.setUpdateDate(ZonedDateTime.now());
Album result = albumReposi tory.save(album);

55
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME,
album.getId().toString()))
.body(result);
}

/**
* {@code GET /albums} : get all the albums.
*
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of albums
in body.
*/
@GetMapping("/albums")
public List<Album> getAllAlbums() {
log.debug("REST request to get all Albums");
return albumRepository.findByUserIsCurrentUser();
}

/**
* {@code GET /albums/:id} : get the "id" album.
*
* @param id the id of the album to retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with bo dy the
album, or with status {@code 404 (Not Found)}.
*/
@GetMapping("/albums/{id}")
public ResponseEntity<Album> getAlbum(@PathVariable Long id) {
log.debug("REST request to get Album : {}", id);
Optional<Album> album = albumR epository.findByUserIsCurrentUserAndId(id);
return ResponseUtil.wrapOrNotFound(album);
}

/**
* {@code DELETE /albums/:id} : delete the "id" album.
*
* @param id the id of the album to delete.
* @return the {@link Respo nseEntity} with status {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/albums/{id}")
public ResponseEntity<Void> deleteAlbum(@PathVariable Long id) {
log.debug("REST request to delete Album : {}", id);
albumRepository.deleteById( id);
return
ResponseEntity.noContent().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true,
ENTITY_NAME, id.toString())).build();
}
}

56
AttachmentResource.java

package com.upb.etti.web.rest;

import com.upb.etti.domain.Attach ment;
import com.upb.etti.repository.AttachmentRepository;
import com.upb.etti.security.SecurityUtils;
import com.upb.etti.web.rest.errors.BadRequestAlertException;

import io.github.jhipster.web.util.HeaderUtil;
import io.github.jhipster.web.util.Response Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.ne t.URISyntaxException;

import java.util.List;
import java.util.Optional;

/**
* REST controller for managing {@link com.upb.etti.domain.Attachment}.
*/
@RestController
@RequestMapping("/api")
public class AttachmentResource {

private final Logger lo g = LoggerFactory.getLogger(AttachmentResource.class);

private static final String ENTITY_NAME = "attachment";

@Value("${jhipster.clientApp.name}")
private String applicationName;

private final AttachmentRepository attachmentRepository;

public AttachmentResource(AttachmentRepository attachmentRepository) {
this.attachmentRepository = attachmentRepository;
}

/**
* {@code POST /attachments} : Create a new attachment.
*
* @param attachment the attachment to create.
* @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the
new attachment, or with status {@code 400 (Bad Request)} if the attachment has already an ID.
* @throws URISyntaxException if the Location URI sy ntax is incorrect.
*/
@PostMapping("/attachments")

57
public ResponseEntity<Attachment> createAttachment(@RequestBody Attachment
attachment) throws URISyntaxException {
log.debug("REST request to save Attachment : {}", attachment);
if (attachment.getId() != null) {
throw new BadRequestAlertException("A new attachment cannot already have an ID",
ENTITY_NAME, "idexists");
}
Attachment result = attachmentRepository.save(attachment);
return ResponseE ntity.created(new URI("/api/attachments/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME,
result.getId().toString()))
.body(result);
}

/**
* {@code PUT /attachments } : Updates an existing attachment.
*
* @param attachment the attachment to update.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
updated attachment,
* or with status {@code 400 (Bad Request)} if th e attachment is not valid,
* or with status {@code 500 (Internal Server Error)} if the attachment couldn't be updated.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PutMapping("/attachments")
public Respon seEntity<Attachment> updateAttachment(@RequestBody Attachment
attachment) throws URISyntaxException {
log.debug("REST request to update Attachment : {}", attachment);
if (attachment.getId() == null) {
throw new BadRequestAlertEx ception("Invalid id", ENTITY_NAME, "idnull");
}
Attachment result = attachmentRepository.save(attachment);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME,
attach ment.getId().toString()))
.body(result);
}

/**
* {@code GET /attachments} : get all the attachments.
*
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of
attachments in body.
*/
@GetMapping("/attachments")
public List<Attachment> getAllAttachments() {
log.debug("REST request to get all Attachments");
return
attachmentRepository.findByUser_Login(SecurityUtils.getCurrentUserLogin().get());
}

/**

58
* {@ code GET /attachments/:id} : get the "id" attachment.
*
* @param id the id of the attachment to retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
attachment, or with status {@code 404 (Not Found)} .
*/
@GetMapping("/attachments/{id}")
public ResponseEntity<Attachment> getAttachment(@PathVariable Long id) {
log.debug("REST request to get Attachment : {}", id);
Optional<Attachment> attachment = attachmentRepository.findByI d(id);
return ResponseUtil.wrapOrNotFound(attachment);
}

/**
* {@code DELETE /attachments/:id} : delete the "id" attachment.
*
* @param id the id of the attachment to delete.
* @return the {@link ResponseEntity} with s tatus {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/attachments/{id}")
public ResponseEntity<Void> deleteAttachment(@PathVariable Long id) {
log.debug("REST request to delete Attachment : {}", id);
attachmentRepository.deleteBy Id(id);
return
ResponseEntity.noContent().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true,
ENTITY_NAME, id.toString())).build();
}

/**
* {@code GET /attachments/album/{albumId}} : get all photos by album "albumId" .
*
* @param albumId the id of the Album to retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the
attachment, or with status {@code 404 (Not Found)}.
*/
@GetMapping("/attachments/album/{album Id}")
public List<Attachment> getPhotosForAlbum(@PathVariable Long albumId) {
log.debug("REST request to get all Attachments from album : {}", albumId);
return attachmentRepository.findByAlbum_Id(albumId);
}

}

AccountResource.jav a

package com.upb.etti.web.rest;

import com.upb.etti.domain.PersistentToken;
import com.upb.etti.repository.PersistentTokenRepository;

59
import com.upb.etti.domain.User;
import com.upb.etti.repository.UserRepository;
import com.upb.etti.security.SecurityU tils;
import com.upb.etti.service.MailService;
import com.upb.etti.service.UserService;
import com.upb.etti.service.dto.PasswordChangeDTO;
import com.upb.etti.service.dto.UserDTO;
import com.upb.etti.web.rest.errors.*;
import com.upb.etti.web.rest.vm.KeyAn dPasswordVM;
import com.upb.etti.web.rest.vm.ManagedUserVM;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;

/**
* REST controller for managing the current user's account.
*/
@RestController
@RequestMapping("/api")
public class AccountResource {

private static class AccountResourceException extends RuntimeException {
private AccountResourceException(String message) {
super(message);
}
}

private final Logger log = LoggerFactory.getLogger(AccountResource.class);

private final UserRepository userRepository;

private final UserService userService;

private final MailService mailService;

private final PersistentTokenRepository persistentTo kenRepository;

public AccountResource(UserRepository userRepository, UserService userService,
MailService mailService, PersistentTokenRepository persistentTokenRepository) {

this.userRepository = userRepository;
this.userService = use rService;
this.mailService = mailService;

60
this.persistentTokenRepository = persistentTokenRepository;
}

/**
* {@code POST /register} : register the user.
*
* @param managedUserVM the managed user View Model.
* @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is
incorrect.
* @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already
used.
* @throws LoginAlreadyUsedException {@code 400 (Bad Request)} if the login is already
used.
*/
@PostMapping("/register")
@ResponseStatus(HttpStatus.CREATED)
public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) {
if (!checkPasswordLength(managedUserVM.getPassword())) {
throw new InvalidPasswordException();
}
User user = userService.registerUser(managedUserVM, managedUserVM.getPassword());
mailService.sendActivationEmail(user);
}

/**
* {@code GET /activate} : activate the re gistered user.
*
* @param key the activation key.
* @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be
activated.
*/
@GetMapping("/activate")
public void activateAccount(@RequestParam(value = "k ey") String key) {
Optional<User> user = userService.activateRegistration(key);
if (!user.isPresent()) {
throw new AccountResourceException("No user was found for this activation key");
}
}

/**
* {@code GET /authenticate} : check if the user is authenticated, and return its login.
*
* @param request the HTTP request.
* @return the login if the user is authenticated.
*/
@GetMapping("/authenticate")
public String isAuthenticated(Ht tpServletRequest request) {
log.debug("REST request to check if the current user is authenticated");
return request.getRemoteUser();
}

/**

61
* {@code GET /account} : get the current user.
*
* @return the current user.
* @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be
returned.
*/
@GetMapping("/account")
public UserDTO getAccount() {
return userService.getUserWithAuthorities()
.map(UserDTO::new)
.orElseThrow(() -> new AccountResourceException("User could not be found"));
}

/**
* {@code POST /account} : update the current user information.
*
* @param userDTO the current user information.
* @throws EmailAlre adyUsedException {@code 400 (Bad Request)} if the email is already
used.
* @throws RuntimeException {@code 500 (Internal Server Error)} if the user login wasn't
found.
*/
@PostMapping("/account")
public void saveAccount(@Valid @RequestBod y UserDTO userDTO) {
String userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() -> new
AccountResourceException("Current user login not found"));
Optional<User> existingUser =
userRepository.findOneByEmailIgnoreCase(userDTO.getEm ail());
if (existingUser.isPresent() &&
(!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) {
throw new EmailAlreadyUsedException();
}
Optional<User> user = userRepository.findOneByLogin(userLogin);
if (!user.isPresent()) {
throw new AccountResourceException("User could not be found");
}
userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(),
userDTO.getEmail(),
userDTO.getLangKey(), userDTO.getImageU rl());
}

/**
* {@code POST /account/change -password} : changes the current user's password.
*
* @param passwordChangeDto current and new password.
* @throws InvalidPasswordException {@code 400 (Bad Request)} if the new passwor d is
incorrect.
*/
@PostMapping(path = "/account/change -password")
public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) {
if (!checkPasswordLength(passwordChangeDto.getNewPassword())) {
throw new Inv alidPasswordException();

62
}
userService.changePassword(passwordChangeDto.getCurrentPassword(),
passwordChangeDto.getNewPassword());
}

/**
* {@code GET /account/sessions} : get the current open sessions.
*
* @return t he current open sessions.
* @throws RuntimeException {@code 500 (Internal Server Error)} if the current open
sessions couldn't be retrieved.
*/
@GetMapping("/account/sessions")
public List<PersistentToken> getCurrentSessions() {
return persistentTokenRepository.findByUser(
userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin()
.orElseThrow(() -> new AccountResourceException("Current user login not found")))
.orElseThrow(() -> new AccountResourceException("User could not be found"))
);
}

/**
* {@code DELETE /account/sessions?series={series}} : invalidate an existing session.
*
* – You can only delete your own sessions, not any other user's ses sion
* – If you delete one of your existing sessions, and that you are currently logged in on that
session, you will
* still be able to use that session, until you quit your browser: it does not work in real time
(there is
* no API for t hat), it only removes the "remember me" cookie
* – This is also true if you invalidate your current session: you will still be able to use it until
you close
* your browser or that the session times out. But automatic login (the "remember me" c ookie)
will not work
* anymore.
* There is an API to invalidate the current session, but there is no API to check which session
uses which
* cookie.
*
* @param series the series of an existing session.
* @throws Unsuppor tedEncodingException if the series couldn't be URL decoded.
*/
@DeleteMapping("/account/sessions/{series}")
public void invalidateSession(@PathVariable String series) throws
UnsupportedEncodingException {
String decodedSeries = URLDeco der.decode(series, "UTF -8");
SecurityUtils.getCurrentUserLogin()
.flatMap(userRepository::findOneByLogin)
.ifPresent(u ->
persistentTokenRepository.findByUser(u).stream()
.filter(persisten tToken -> StringUtils.equals(persistentToken.getSeries(),
decodedSeries))

63
.findAny().ifPresent(t -> persistentTokenRepository.deleteById(decodedSeries)));
}

/**
* {@code POST /account/reset -password/init} : Send an email to reset the password of the
user.
*
* @param mail the mail of the user.
* @throws EmailNotFoundException {@code 400 (Bad Request)} if the email address is not
registered.
*/
@PostMapping(path = "/account/reset -password/init")
public void requestPasswordReset(@RequestBody String mail) {
mailService.sendPasswordResetMail(
userService.requestPasswordReset(mail)
.orElseThrow(EmailNotFoundException::new)
);
}

/**
* {@code POST /account/reset -password/finish} : Finish to reset the password of the user.
*
* @param keyAndPassword the generated key and the new password.
* @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is
incorrect.
* @throws RuntimeException {@code 500 (Internal Server Error)} if the password could not
be reset.
*/
@PostMapping(path = "/account/reset -password/finish")
public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
if (!checkPasswordLength(keyAndPassword.getNewPassword())) {
throw new InvalidPasswordException();
}
Optional<User> user =
userService.completePasswordReset(keyAndPassword.getNewPassword(),
keyAndPassword.getKey());

if (!user.isPresent()) {
throw new AccountResourceException("No user was found for this reset key");
}
}

private static boolean checkPasswordLength(String password) {
return !StringUtils.isEmpty(password) &&
password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH &&
password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH;
}
}

64

Anexa 2 Cod Angular

agenda.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { JhiEventManager, JhiAlertService } from 'ng -jhipster';

import { IAgenda } from 'app/shared/mod el/agenda.model';
import { AccountService } from 'app/core';
import { AgendaService } from './agenda.service';

@Component({
selector: 'jhi -agenda',
templateUrl: './agenda.component.html'
})
export class AgendaComponent implements OnInit, OnDestroy {
agenda: IAgenda[];
currentAccount: any;
eventSubscriber: Subscription;

constructor(
protected agendaService: AgendaService,
protected jhiAlertService: JhiAlertService,
protected eventManager: JhiEventManager,
protected accountServic e: AccountService
) {}

loadAll() {
this.agendaService
.query()
.pipe(
filter((res: HttpResponse<IAgenda[]>) => res.ok),
map((res: HttpResponse<IAgenda[]>) => res.body)
)
.subscribe(
(res: IAgenda[]) => {
this.agenda = res;
},
(res: HttpErrorResponse) => this.onError(res.message)
);
}

ngOnInit() {
this.loadAll();
this.accountService.identity().then(account => {
this.currentAccount = account;

65
});
this.registerChangeInAgenda();
}

ngOnDestroy() {
this.eventManager.destroy(this.eventSubscriber);
}

trackId(index: number, item: IAgenda) {
return item.id;
}

registerChangeInAgenda() {
this.eventSubscriber = this.eventManager.s ubscribe('agendaListModification', response =>
this.loadAll());
}

protected onError(errorMessage: string) {
this.jhiAlertService.error(errorMessage, null, null);
}
}

agenda.service.ts

import { Injectable } from '@angular/core';
import { HttpCl ient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import * as moment from 'moment';
import { DATE_FORMAT } from 'app/shared/constants/input.constants';
import { map } from 'rxjs/operators';

import { SERVER_API_URL } from 'app/app.constants';
import { createRequestOption } from 'app/shared';
import { IAgenda } from 'app/shared/model/agenda.model';

type EntityResponseType = HttpResponse<IAgenda>;
type EntityArrayResponseType = HttpResponse<IAgenda[]>;

@Injectable({ provid edIn: 'root' })
export class AgendaService {
public resourceUrl = SERVER_API_URL + 'api/agenda';

constructor(protected http: HttpClient) {}

create(agenda: IAgenda): Observable<EntityResponseType> {
const copy = this.convertDateFromClient(agenda );
return this.http
.post<IAgenda>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

update(agenda: IAgenda): Observable<EntityResponseType> {

66
const copy = this.convertDateFromClient(agenda);
return this.http
.put<IAgenda>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

find(id: number): Observable<EntityResponse Type> {
this.http.get(`${this.resourceUrl}/${id}`).subscribe(res => {
console.log(res);
});
return this.http
.get<IAgenda>(`${this.resourceUrl}/${id}`, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.conve rtDateFromServer(res)));
}

query(req?: any): Observable<EntityArrayResponseType> {
const options = createRequestOption(req);
return this.http
.get<IAgenda[]>(this.resourceUrl, { params: options, observe: 'response' })
.pipe(map((re s: EntityArrayResponseType) => this.convertDateArrayFromServer(res)));
}

delete(id: number): Observable<HttpResponse<any>> {
return this.http.delete<any>(`${this.resourceUrl}/${id}`, { observe: 'response' });
}

protected convertDateFromClient (agenda: IAgenda): IAgenda {
const copy: IAgenda = Object.assign({}, agenda, {
createDate: agenda.createDate != null && agenda.createDate.isValid() ?
agenda.createDate.toJSON() : null,
updateDate: agenda.updateDate != null && agenda.updateD ate.isValid() ?
agenda.updateDate.toJSON() : null
});
return copy;
}

protected convertDateFromServer(res: EntityResponseType): EntityResponseType {
if (res.body) {
res.body.createDate = res.body.createDate != null ? moment(res.body.c reateDate) : null;
res.body.updateDate = res.body.updateDate != null ? moment(res.body.updateDate) : null;
}
return res;
}

protected convertDateArrayFromServer(res: EntityArrayResponseType):
EntityArrayResponseType {
if (res.body) {
res.body.forEach((agenda: IAgenda) => {
agenda.createDate = agenda.createDate != null ? moment(agenda.createDate) : null;
agenda.updateDate = agenda.updateDate != null ? moment(agenda.updateDate) : null;
});
}

67
return res ;
}
}

album.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { J hiEventManager, JhiAlertService } from 'ng -jhipster';

import { IAlbum } from 'app/shared/model/album.model';
import { AccountService } from 'app/core';
import { AlbumService } from './album.service';

@Component({
selector: 'jhi -album',
templateUrl: ' ./album.component.html'
})
export class AlbumComponent implements OnInit, OnDestroy {
albums: IAlbum[];
currentAccount: any;
eventSubscriber: Subscription;

constructor(
protected albumService: AlbumService,
protected jhiAlertService: JhiAl ertService,
protected eventManager: JhiEventManager,
protected accountService: AccountService
) {}

loadAll() {
this.albumService
.query()
.pipe(
filter((res: HttpResponse<IAlbum[]>) => res.ok),
map((res: HttpRes ponse<IAlbum[]>) => res.body)
)
.subscribe(
(res: IAlbum[]) => {
this.albums = res;
},
(res: HttpErrorResponse) => this.onError(res.message)
);
}

ngOnInit() {
this.loadAll();
this.accountServ ice.identity().then(account => {
this.currentAccount = account;
});

68
this.registerChangeInAlbums();
}

ngOnDestroy() {
this.eventManager.destroy(this.eventSubscriber);
}

trackId(index: number, item: IAlbum) {
return item.id;
}

registerChangeInAlbums() {
this.eventSubscriber = this.eventManager.subscribe('albumListModification', response =>
this.loadAll());
}

protected onError(errorMessage: string) {
this.jhiAlertService.error(errorMessage, null, null);
}
}

album.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import * as moment from 'moment';
import { DATE_FORMAT } from 'app/shared/constants/input.cons tants';
import { map } from 'rxjs/operators';

import { SERVER_API_URL } from 'app/app.constants';
import { createRequestOption } from 'app/shared';
import { IAlbum } from 'app/shared/model/album.model';

type EntityResponseType = HttpResponse<IAlbum>;
type EntityArrayResponseType = HttpResponse<IAlbum[]>;

@Injectable({ providedIn: 'root' })
export class AlbumService {
public resourceUrl = SERVER_API_URL + 'api/albums';

constructor(protected http: HttpClient) {}

create(album: IAlbum): Observable<En tityResponseType> {
const copy = this.convertDateFromClient(album);
return this.http
.post<IAlbum>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

update( album: IAlbum): Observable<EntityResponseType> {
const copy = this.convertDateFromClient(album);

69
return this.http
.put<IAlbum>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromS erver(res)));
}

find(id: number): Observable<EntityResponseType> {
return this.http
.get<IAlbum>(`${this.resourceUrl}/${id}`, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

query(req?: any): Observable<EntityArrayResponseType> {
const options = createRequestOption(req);
return this.http
.get<IAlbum[]>(this.resourceUrl, { params: options, observe: 'response' })
.pipe(map((res: EntityArrayResponseType) => this. convertDateArrayFromServer(res)));
}

delete(id: number): Observable<HttpResponse<any>> {
return this.http.delete<any>(`${this.resourceUrl}/${id}`, { observe: 'response' });
}

protected convertDateFromClient(album: IAlbum): IAlbum {
const copy: IAlbum = Object.assign({}, album, {
createDate: album.createDate != null && album.createDate.isValid() ?
album.createDate.toJSON() : null,
updateDate: album.updateDate != null && album.updateDate.isValid() ?
album.updateDate.toJSON() : nu ll
});
return copy;
}

protected convertDateFromServer(res: EntityResponseType): EntityResponseType {
if (res.body) {
res.body.createDate = res.body.createDate != null ? moment(res.body.createDate) : null;
res.body.updateDate = res.body.updateDate != null ? moment(res.body.updateDate) : null;
}
return res;
}

protected convertDateArrayFromServer(res: EntityArrayResponseType):
EntityArrayResponseType {
if (res.body) {
res.body.forEach((album: IAlbum) => {
album.createDate = album.createDate != null ? moment(album.createDate) : null;
album.updateDate = album.updateDate != null ? moment(album.updateDate) : null;
});
}
return res;
}
}

70
scheduled -item.component.ts

import { Componen t, OnInit, OnDestroy } from '@angular/core';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { JhiEventManager, JhiAlertService } from 'ng -jhipster';

import { IScheduledItem } from 'app/shared/model/scheduled -item.model';
import { AccountService } from 'app/core';
import { ScheduledItemService } from './scheduled -item.service';

@Component({
selector: 'jhi -scheduled -item',
templateUrl: './s cheduled -item.component.html'
})
export class ScheduledItemComponent implements OnInit, OnDestroy {
scheduledItems: IScheduledItem[];
currentAccount: any;
eventSubscriber: Subscription;

constructor(
protected scheduledItemService: ScheduledIte mService,
protected jhiAlertService: JhiAlertService,
protected eventManager: JhiEventManager,
protected accountService: AccountService
) {}

loadAll() {
this.scheduledItemService
.query()
.pipe(
filter((res: HttpRes ponse<IScheduledItem[]>) => res.ok),
map((res: HttpResponse<IScheduledItem[]>) => res.body)
)
.subscribe(
(res: IScheduledItem[]) => {
this.scheduledItems = res;
},
(res: HttpErrorResponse) => this.onEr ror(res.message)
);
}

ngOnInit() {
this.loadAll();
this.accountService.identity().then(account => {
this.currentAccount = account;
});
this.registerChangeInScheduledItems();
}

ngOnDestroy() {

71
this.eventManager.dest roy(this.eventSubscriber);
}

trackId(index: number, item: IScheduledItem) {
return item.id;
}

registerChangeInScheduledItems() {
this.eventSubscriber = this.eventManager.subscribe('scheduledItemListModification',
response => this.loadAll( ));
}

protected onError(errorMessage: string) {
this.jhiAlertService.error(errorMessage, null, null);
}
}

scheduled -item.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import * as moment from 'moment';
import { DATE_FORMAT } from 'app/shared/constants/input.constants';
import { map } from 'rxjs/operators';

import { SERVER_API_URL } from 'app/app.constants';
import { createRequestOption } from 'app/shared';
import { IScheduledItem } from 'app/shared/model/scheduled -item.model';

type EntityResponseType = HttpResponse<IScheduledItem>;
type EntityArrayResponseType = HttpResponse<IScheduledItem[]>;

@Injectable({ providedIn: 'root' })
export c lass ScheduledItemService {
public resourceUrl = SERVER_API_URL + 'api/scheduled -items';
public resourceUrlSorted = SERVER_API_URL + 'api/scheduled -items/sorted';

constructor(protected http: HttpClient) {}

create(scheduledItem: IScheduledItem): O bservable<EntityResponseType> {
const copy = this.convertDateFromClient(scheduledItem);
return this.http
.post<IScheduledItem>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromS erver(res)));
}

update(scheduledItem: IScheduledItem): Observable<EntityResponseType> {
const copy = this.convertDateFromClient(scheduledItem);
return this.http
.put<IScheduledItem>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

72

find(id: number): Observable<EntityResponseType> {
return this.http
.get<IScheduledItem>(`${this.resourceUrl}/${id}`, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

query(req?: any): Observable<EntityArrayResponseType> {
const options = createRequestOption(req);
return this.http
.get<IScheduledItem[]>(this.resourceUrlSorted, { params: optio ns, observe: 'response' })
.pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res)));
}

queryByAgenda(id: number): Observable<EntityArrayResponseType> {
return this.http
.get<IScheduledItem[]>(`api/scheduled -items/agenda/${id}`, { observe: 'response' })
.pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res)));
}

delete(id: number): Observable<HttpResponse<any>> {
return this.http.delete<any>(`${this.resourceUrl}/${id}`, { observe: 'response' });
}

protected convertDateFromClient(scheduledItem: IScheduledItem): IScheduledItem {
const copy: IScheduledItem = Object.assign({}, scheduledItem, {
scheduledAt: scheduledItem.scheduledAt != null && scheduledItem.sched uledAt.isValid() ?
scheduledItem.scheduledAt.toJSON() : null,
createDate: scheduledItem.createDate != null && scheduledItem.createDate.isValid() ?
scheduledItem.createDate.toJSON() : null,
updateDate: scheduledItem.updateDate != null && schedul edItem.updateDate.isValid() ?
scheduledItem.updateDate.toJSON() : null
});
return copy;
}

protected convertDateFromServer(res: EntityResponseType): EntityResponseType {
if (res.body) {
res.body.scheduledAt = res.body.scheduledAt != n ull ? moment(res.body.scheduledAt) : null;
res.body.createDate = res.body.createDate != null ? moment(res.body.createDate) : null;
res.body.updateDate = res.body.updateDate != null ? moment(res.body.updateDate) : null;
}
return res;
}

protected convertDateArrayFromServer(res: EntityArrayResponseType):
EntityArrayResponseType {
if (res.body) {
res.body.forEach((scheduledItem: IScheduledItem) => {
scheduledItem.scheduledAt = scheduledItem.scheduledAt != null ?
moment (scheduledItem.scheduledAt) : null;

73
scheduledItem.createDate = scheduledItem.createDate != null ?
moment(scheduledItem.createDate) : null;
scheduledItem.updateDate = scheduledItem.updateDate != null ?
moment(scheduledItem.updateDate) : null ;
});
}
return res;
}
}

attachment.component.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import * as moment from 'moment';
import { DA TE_FORMAT } from 'app/shared/constants/input.constants';
import { map } from 'rxjs/operators';

import { SERVER_API_URL } from 'app/app.constants';
import { createRequestOption } from 'app/shared';
import { IScheduledItem } from 'app/shared/model/scheduled -item.model';

type EntityResponseType = HttpResponse<IScheduledItem>;
type EntityArrayResponseType = HttpResponse<IScheduledItem[]>;

@Injectable({ providedIn: 'root' })
export class ScheduledItemService {
public resourceUrl = SERVER_API_URL + 'api/sche duled -items';
public resourceUrlSorted = SERVER_API_URL + 'api/scheduled -items/sorted';

constructor(protected http: HttpClient) {}

create(scheduledItem: IScheduledItem): Observable<EntityResponseType> {
const copy = this.convertDateFromClient(s cheduledItem);
return this.http
.post<IScheduledItem>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

update(scheduledItem: IScheduledItem): Observable<Entity ResponseType> {
const copy = this.convertDateFromClient(scheduledItem);
return this.http
.put<IScheduledItem>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

find(id: number): Observable<EntityResponseType> {
return this.http
.get<IScheduledItem>(`${this.resourceUrl}/${id}`, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));

74
}

query(req?: any): Observable<EntityArrayResponseType> {
const options = createRequestOption(req);
return this.http
.get<IScheduledItem[]>(this.resourceUrlSorted, { params: options, observe: 'response' })
.pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res)));
}

queryByAgenda(id: number): Observable<EntityArrayResponseType> {
return this.http
.get<IScheduledItem[]>(`api/scheduled -items/agenda/${id}`, { observe: 'response' })
.pipe(map((res: EntityArray ResponseType) => this.convertDateArrayFromServer(res)));
}

delete(id: number): Observable<HttpResponse<any>> {
return this.http.delete<any>(`${this.resourceUrl}/${id}`, { observe: 'response' });
}

protected convertDateFromClient(scheduledItem : IScheduledItem): IScheduledItem {
const copy: IScheduledItem = Object.assign({}, scheduledItem, {
scheduledAt: scheduledItem.scheduledAt != null && scheduledItem.scheduledAt.isValid() ?
scheduledItem.scheduledAt.toJSON() : null,
createDat e: scheduledItem.createDate != null && scheduledItem.createDate.isValid() ?
scheduledItem.createDate.toJSON() : null,
updateDate: scheduledItem.updateDate != null && scheduledItem.updateDate.isValid() ?
scheduledItem.updateDate.toJSON() : null
});
return copy;
}

protected convertDateFromServer(res: EntityResponseType): EntityResponseType {
if (res.body) {
res.body.scheduledAt = res.body.scheduledAt != null ? moment(res.body.scheduledAt) : null;
res.body.createDate = res.bo dy.createDate != null ? moment(res.body.createDate) : null;
res.body.updateDate = res.body.updateDate != null ? moment(res.body.updateDate) : null;
}
return res;
}

protected convertDateArrayFromServer(res: EntityArrayResponseType):
Entit yArrayResponseType {
if (res.body) {
res.body.forEach((scheduledItem: IScheduledItem) => {
scheduledItem.scheduledAt = scheduledItem.scheduledAt != null ?
moment(scheduledItem.scheduledAt) : null;
scheduledItem.createDate = schedu ledItem.createDate != null ?
moment(scheduledItem.createDate) : null;
scheduledItem.updateDate = scheduledItem.updateDate != null ?
moment(scheduledItem.updateDate) : null;
});
}

75
return res;
}
}

attachment.service.ts

import { Inje ctable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import * as moment from 'moment';
import { DATE_FORMAT } from 'app/shared/constants/input.constants';
import { map } from 'rx js/operators';

import { SERVER_API_URL } from 'app/app.constants';
import { createRequestOption } from 'app/shared';
import { IAttachment } from 'app/shared/model/attachment.model';
import { IScheduledItem } from 'app/shared/model/scheduled -item.model';

type EntityResponseType = HttpResponse<IAttachment>;
type EntityArrayResponseType = HttpResponse<IAttachment[]>;

@Injectable({ providedIn: 'root' })
export class AttachmentService {
public resourceUrl = SERVER_API_URL + 'api/attachments';

constructor (protected http: HttpClient) {}

create(attachment: IAttachment): Observable<EntityResponseType> {
const copy = this.convertDateFromClient(attachment);
return this.http
.post<IAttachment>(this.resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

update(attachment: IAttachment): Observable<EntityResponseType> {
const copy = this.convertDateFromClient(attachment);
return this.http
.put<IAttachment>(this .resourceUrl, copy, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

find(id: number): Observable<EntityResponseType> {
return this.http
.get<IAttachment>(`${this.resourceUrl}/${id}`, { observe: 'response' })
.pipe(map((res: EntityResponseType) => this.convertDateFromServer(res)));
}

query(req?: any): Observable<EntityArrayResponseType> {
const options = createRequestOption(req);
return this.http
.get<IAttachme nt[]>(this.resourceUrl, { params: options, observe: 'response' })
.pipe(map((res: EntityArrayResponseType) => this.convertDateArrayFromServer(res)));

76
}

delete(id: number): Observable<HttpResponse<any>> {
return this.http.delete<any>(`${this. resourceUrl}/${id}`, { observe: 'response' });
}

queryByAlbum(albumId: number): Observable<EntityArrayResponseType> {
return this.http
.get<IAttachment[]>(`api/attachments/album/${albumId}`, { observe: 'response' })
.pipe(map((res: Ent ityArrayResponseType) => this.convertDateArrayFromServer(res)));
}

protected convertDateFromClient(attachment: IAttachment): IAttachment {
const copy: IAttachment = Object.assign({}, attachment, {
createDate: attachment.createDate != null && attachment.createDate.isValid() ?
attachment.createDate.toJSON() : null,
updateDate: attachment.updateDate != null && attachment.updateDate.isValid() ?
attachment.updateDate.toJSON() : null
});
return copy;
}

protected convertDateFromSe rver(res: EntityResponseType): EntityResponseType {
if (res.body) {
res.body.createDate = res.body.createDate != null ? moment(res.body.createDate) : null;
res.body.updateDate = res.body.updateDate != null ? moment(res.body.updateDate) : nu ll;
}
return res;
}

protected convertDateArrayFromServer(res: EntityArrayResponseType):
EntityArrayResponseType {
if (res.body) {
res.body.forEach((attachment: IAttachment) => {
attachment.createDate = attachment.createDate ! = null ? moment(attachment.createDate) :
null;
attachment.updateDate = attachment.updateDate != null ? moment(attachment.updateDate)
: null;
});
}
return res;
}
}

Anexa 3 Cod HTML

agenda.component.html

<push -notification></push -notification>
<div class="container">
<div class="row">
<div class="col">

77
<h2 id="page -heading">
<span jhiTranslate="parentGuideApp.agenda.home.title">Agenda</span>
<button id="jh -create -entity" class= "btn btn -primary float -right jh -create -entity create –
agenda"
[routerLink]="['/agenda/new']">
<fa-icon [icon]="'plus'" [size]="'2x'"></fa -icon>
</button>
</h2>
</div>
</div>
<br/>
<br/>
<div class="row">
<div class="col">
<div class="main" *ngIf="agenda">
<ul class="cbp -ig-grid">
<li *ngFor="let ag of agenda ;trackBy: trackId">
<a [rou terLink]="['/agenda', ag.id, 'view' ]">
<div class="cbp -ig-icon">
<span [ngSwitch]="ag.agendaType">
<fa-icon *ngSwitchCase="'DOCTOR'" [icon]="'user -md'" [size]="'10x'"></fa –
icon>
<fa-icon *ngSwitchCase="'SLEEP'" [icon]="'bed'" [size]="'10x'"></fa -icon>
<fa-icon *ngSwitchCase="'DUMMY'" [icon]="'calendar -alt'"
[size]="'10x'"></fa -icon>
<fa-icon *ng SwitchCase="'TREATMENT'" [icon]="'pills'"
[size]="'10x'"></fa -icon>
<fa-icon *ngSwitchCase="'FEED'" [icon]="'utensils'" [size]="'10x'"></fa –
icon>
</span>
</div>
<h3 class="cbp -ig-title">{{ag.title}}</h3>
<span class="cbp -ig-category">{{ag.description}}</span>
</a>
</li>
</ul>
</div>
</div>
</div>

<div class="row" *ngIf="agenda.length === 0">
<div class="col text -center">
<h3 class="font -weight -bold">You have no agenda created!</h3>
</div>

</div>
</div>

album.component.html

<div class="container">
<div class="row">

78
<div class="col">
<h2 id="page -heading">
<span jhiTranslate="parentGuideApp.album.home.title">Agenda</span>
<button id="jh -create -entity" class="btn btn -primary float -right jh -create -entity create –
agenda"
[routerLink]="['/album/new']">
<fa-icon [icon]="'plus'" [size]="'2x'"></fa -icon>
</button>
</h2>
</div>
</div>
<br/>
<br/>
<div class="row">
<div class="col">
<div class="main" *ngIf="albums">
<ul class="cbp -ig-grid">
<li *ngFor="let album of albums ;trackBy: trackId">
<a [routerLink]="['/album', album.id, 'view' ]">
<div class="cbp -ig-icon">
<span>
<fa-icon [icon]="'camera -retro'" [size]="'10x'"></fa -icon>
</span>
</div>
<h3 class="cbp -ig-title">{{album.title}}</h3>
<span class="cbp -ig-category">{{album.description}}</span>
</a>
</li>
</ul>
</div>
</div>
</div>

<div class="row" *ngIf="albums.length === 0">
<div class="col text -center">
<h3 class="font -weight -bold">You have no album created!</h3>
</div>

</div>
</div>

Similar Posts