Za početak, važna napomena. Jedna stvar mora biti jasna. Ova metoda neće raditi u 100% slučajeva i treba se koristiti kao zadnja opcija.
Olakotna okolnost može biti ako ste sami kreirali keystore za koji više nemate lozinku jer lakše ćete dobiti inspiraciju za potencijalne mogućnosti kada znate koje najčešće kombinacije koristite No, ako želite doći do lozinke keystore datoteke koju je netko drugi kreirao onda najveću ulogu igra sreća i dovoljno vremena provedenog u čekanju da ovaj alat dođe do lozinke.
P.S. Prije korištenja ovog alata dobra je opcija kontaktirati Google kroz njihovu General Play Console issues formu (I have a key or keystore related issue -> I have an upload key-related issue -> I forgot the password to my keystore).
Metoda koja će vrtiti popis zadanih riječi u točnom obliku kako su navedene. Znači neće ih kombinirati kao što to radi u 3. metodi. Potreban je puno veći popis riječi i sve moguće kombinacije.
Najbolja metoda jer će od svih riječi iz riječnika napraviti sve moguće kombinacije. Brojevi se dodaju automatski i nije ih potrebno posebno navoditi. Ipak, ako znate da se lozinka sastoji od npr. broja godine “2020” dobro je to navesti jer će ubrzati pronalazak ispravne kombinacije.
Popis riječi koje sam koristio u wordlist.txt:
Shell
1
2
3
4
5
6
7
tomislav
primjer
demo
blog
8
7
0
Ispravnu kombinaciju lozinke dobio sam za 22 sekunde:
U ovom ću blog postu pokazati kako napraviti upit na API Sudskog registra i dohvatiti informacije o poslovnom subjektu prema OIB-u/MBS-a. U dokumentaciji se može vidjeti koje je sve informacije i preko kojih ruta moguće napraviti, ali ja ću se zadržati na onoj po meni najzanimljivijoj subjekt_detalji_Get.
Za kreiranje forme koristiti ću FormBuilder, a mogao sam isto tako koristiti i ngModel ili FormControl. Više o tome objavio sam u jednom od prijašnjih blog postova. Forma će se sastojati od nekoliko polja od kojih će većina biti obavezna. Prilikom unosa OIB-a ili MBS-a odmah ide provjera na API Sudskog registra i tek nakon te provjere moguće je kliknuti na gumb “Spremi” nakon kojega se podaci mogu spremiti u bazu podataka.
Provjera rada API-ja
Prije nego krenem s izradom Angular forme idem se uvjeriti da API radi na način kako je prikazano u dokumentaciji i da mi vraća podatke koje želim koristiti. API je moguće testirati i na ovoj adresi. Da nema te forme koristio bi Postman.
Kreiram formu sa poljima:
–
oib – dužina 11 znakova. Obavezno polje.
–
mbs – dužina 9 znakova. Obavezno polje.
–
nazivtvrtke – Obavezno polje.
–
ulica – Obavezno polje.
–
grad – Obavezno polje.
–
e-mail
Prilikom unosa OIB-a ili MBS-a odmah se vrši provjera na API putem funkcije
provjera(angularForma). Tek nakon što se forma ispuni podacima tj. kada se zadovolji unos obaveznih polja moguće je kliknuti na gumb “Spremi”.
Unutar ngOnInit()funkcije radim inicijalizaciju forme. Ovdje odmah dodajem i
Validators kako bi mogao validirati potrebna polja i spriječiti klik na gumb “Spremi” pomoću
[disabled]="!angularForma.valid" u slučaju kada forma nije ispravno ispunjena.
Kada se unutar polja forme unesu OIB ili MBS poziva se funkcija
provjera(angularForma). Prvo vršim provjeru koja vrsta identifikatora (OIB ili MBS) je unesena jer ću kasnije na osnovu toga pozivati pripadajući API Sudskog registra iz
ApiService i paralelno provjeravam da su ispravne dužine. Nakon toga provjeravam da unutar unesenih znakova nema slova tj. da su samo brojevi
match(/^[0-9]+$/). Kada su svi navedeni uvjeti zadovoljeni pozivam
this._apiService.sudskiRegistarOIB ili
this._apiService.sudskiRegistarMBS te prikazujem dobivene podatke
console.log(res) i odmah popunjavam formu.
Kada je forma ispravno validirana podaci će se uspješno dohvatiti.
Ne međutim, ostaje problem kod popunjavanja forme sa nasumičnim brojevima koji će ispravno biti validirani prema dužini iako ne postoje u Registru. Npr. netko za OIB može unijeti 11 nula ili za MBS 9 nula i forma će biti validna te će se taj poslovni subjekt moći spremiti u bazu podatka.
To mogu spriječiti koristeći setValue ili patchValue. Znači, ako mi API Sudskog registra ne vrati podatke neću dopustiti da forma prođe kao validna i da se uopće može kliknuti na “Spremi”.
Što se adrese tiče stavio sam uvjet da se prikaže ispravna vrijednost neovisno o tome ima li prikazana adresa uz broj i podbroj tj. slovo
(res.sjedista[0].kucni_podbroj?(res.sjedista[0].kucni_podbroj):'') .
Npr. u adresi Dragutina Žanića Karle 27a je ‘a’
podbroj .
Cilj blog posta “*ngFor u Angularu za početnike” je napraviti uvod u ngFor Angular direktivu jer ona je osnova koju svaki, Angular, developer treba i mora znati.
*ngFor direktiva se primarno koristi za prikaz niza podataka (array) i početnicima može predstavljati poseban izazov. Također, može se koristiti i za prikaz objekata uz pomoć KeyValuePipe.
Projekt je vidljiv na adresi http://localhost:4200/
Uvod
*ngFordirektiva u Angularu, osim što služi za prikaz niza podataka, je optimizirana da minimalno utječe na DOM (Document Object Model).
To će se najbolje vidjeti u nastavku kada budem koristio
leti=index pri čemu ću uklanjati elemente niza bez da ga cijelog ponovno osvježavam.
Angular će se pobrinuti za to da samo taj jedan element izbaci dok sve drugo ostaje isto. Isti slučaj bi bio i kada bi htio dodati novi element u niz.
U slučaju kada podatke dohvaćamo putem nekog API-ja dogodit će se, u slučaju kada se neki podataka obriše ili doda, da Angular više neće znati što treba biti na kojoj poziciji. U tom slučaju koristim
trackBy putem čega Angularu mogu reći koji parametar da koristi kako bi identificirao elemente.
*ngFor – prikaz niza podataka
Ako npr. imam sljedeći niz podatka za pretpostaviti je da ih želim na ekranu prikazati kao popis. U ovom će slučaju to biti jednostavan popis osoba. Podaci su fiksno određeni unutar niza, ali logika je ista čak i da stižu putem nekog API-ja.
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
simpleArray=[
{
id:4,
name:'Tomislav',
country:'Croatia'
},
{
id:5,
name:'Jomislav',
country:'Croatia'
},
{
id:6,
name:'Valsimot',
country:'Croatia'
},
]
Gore navedeni popis podataka želim prikazati na sljedeći način:
XHTML
1
2
3
4
5
<ul>
<li>Tomislav, Croatia</li>
<li>Jomislav, Croatia</li>
<li>Valsimot, Croatia</li>
</ul>
To znači da nekako moram postići da se za svaki objekt unutar niza kreira novi
<li></li> element.
Upravo tu uskače *ngFor sa vrlo jednostavnom sintaksom
*ngFor="let <value> of <collection>" pri čemu
<value> označava naziv varijable koji proizvoljno određujem, dok
<collection> označava izvor podataka što je u ovom slučaju niz
simpleArray.
XHTML
1
2
3
<ul>
<li *ngFor="let data of simpleArray">{{data.name}}, {{data.country}}</li>
</ul>
Konačni rezultat je sljedeći:
Ako želim imati redne brojeve mogu koristiti ol tag. Ovo spominjem samo iz razloga što ću u nastavku pokazati kako je redne brojeve moguće dobiti i pomoću indexa elementa.
*ngFor + element index
index se definira kao varijabla
leti=index i uvijek počinje od 0. Mogu ga koristiti kako bi prikazao redne brojeve elemenata.
XHTML
1
2
3
<ul>
<li *ngFor="let data of simpleArray; let i = index">{{i+1}} - {{data.name}}, {{data.country}}</li>
</ul>
Na ekranu to izgleda ovako:
index mogu, ali i ne moram prikazati na ekranu. U oba ga slučaja mogu koristiti kako bi pristupio pojednom elementu niza.
U sljedećem ću primjeru pomoću funkcije
removeByIndex(i) ukloniti neke elemente iz niza.
JavaScript
1
2
3
4
5
removeByIndex(i){
console.log(i);
this.simpleArray.splice(i,1);
console.log(this.simpleArray);
}
Funkciju pozivam klikom na pojedini element.
XHTML
1
2
3
<ul>
<li *ngFor="let data of simpleArray; let i = index"(click)="removeByIndex(i)">{{i}} - {{data.name}}, {{data.country}}</li>
</ul>
U praksi to izgleda ovako:
*ngFor + trackBy
trackBy se definira kao
;trackBy:id.
XHTML
1
2
3
<ul>
<li *ngFor="let data of simpleArray; let i = index; trackBy: id"(click)="trackElement(i,data.id)">{{data.name}}, {{data.country}}</li>
</ul>
Pomoću funkcije
trackElement(i,data.id) dohvaćam unikatni ID svakog elementa niza.
*ngFor direktiva u Angularu nudi još jednu zanimljivu mogućnost, a to je dohvaćanje prvog i zadnjeg elementa niza pomoću
;letfirst=first;letlast=last.
XHTML
1
2
3
<ul>
<li *ngFor="let data of simpleArray; let first = first; let last = last"[ngClass]="{ firstClass: first, lastClass: last }">{{data.name}}, {{data.country}}</li>
</ul>
Na taj se način prvi i zadnji element mogu npr. urediti CSS-om.
CSS
1
2
3
4
5
6
.firstClass {
color:red;
}
.lastClass {
color:blue;
}
U praksi to izgleda ovako:
Iako ovo još nisam koristio u nekoj produkcijskoj aplikaciji izgleda vrlo zanimljivo.
*ngFor – parni i neparni elementi niza
Kada već spominjem uređivanje elementata CSS-om, postoji još jedna zanimljiva funkcionalnost korištenjem
;leteven=even;letodd=odd.
XHTML
1
2
3
<ul>
<li *ngFor="let data of simpleArray; let even = even; let odd = odd"[ngClass]="{ evenClass: even, oddClass: odd }">{{data.name}}, {{data.country}}</li>
</ul>
Na taj se način parni i neparni elementi mogu npr. urediti CSS-om.
CSS
1
2
3
4
5
6
.evenClass {
color:red;
}
.oddClass {
color:blue;
}
U praksi to izgleda ovako:
*ngFor – niz unutar niza
Osim prikaza osnovnog niza mogu prikazati i napredni niz tj.
countryList niz unutar
nestedArray niza.
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
nestedArray:any[]=[
{
id:4,
name:'Tomislav',
countryList:[
{
shortCode:'HR',
fullName:'Croatia'
},
{
shortCode:'UK',
fullName:'United Kingdom'
}
]
},
{
id:5,
name:'Jomislav',
countryList:[
{
shortCode:'HR',
fullName:'Croatia'
},
{
shortCode:'UK',
fullName:'United Kingdom'
}
]
},
{
id:6,
name:'Valsimot',
countryList:[
{
shortCode:'HR',
fullName:'Croatia'
},
{
shortCode:'UK',
fullName:'United Kingdom'
}
]
},
]
U ovom slučaju
*ngFor ide unutar
<ul>.
XHTML
1
2
3
4
5
6
7
8
<ul *ngFor="let data of nestedArray">
<li>{{data.name}}</li>
<ul>
<li *ngFor="let country of data.countryList">
{{country.fullName}}
</li>
</ul>
</ul>
U praksi to izgleda ovako:
Zaključak
U ovom blog postu, pod nazivom “*ngFor u Angularu za početnike“, naveo sam osnovne funkcionalnosti *ngFor direktive s kojom svaki developer može napraviti funkcionalno rješenje. Sve dalje ovisi o specifičnim potrebama projekta.
Iako u testnom okruženju, plaćanje kreirano na ovaj način biti će uspješno provedeno što će se moći vidjeti unutar PayPal testnog sučelja i prikazano u nastavku ovog blog posta.
Ipak, kako je vidljivo u službenoj dokumentaciji potrebno je napraviti i serverski tj. backend dio koji će služiti kao potvrda uspješnog plaćanja. Serverski dio u ovom blog postu neće biti detaljnije obrađen.
Smart Payment Buttons funkcionira na sljedeći način:
Gumb za plaćanje prikazan je na web/mobilnoj aplikaciji
Kupac klikne na gumb
Poziva se PayPal Orders API koji priprema transakciju
Prikazuje se PayPal Checkout forma za prijavu/plaćanje
Kupac odobrava plaćanje
Poziva se PayPal Orders API koji izvršava transakciju
Kupcu se prikazuje poruka o uspješnoj transakciji
PayPal Sandbox & App Name
Kako bi mogao testirati PayPal naplatu potrebni su mi: testni PayPal korisnički račun na koji će sredstva biti uplaćena, testni PayPal korisnički račun koji će izvršavati plaćanje kao i profil aplikacije putem koje će se plaćanje izvršavati.
Moguće je kreirati testni račun fizičke ili pravne osobe tj. tvrtke. U ovom ću primjeru kreirati poslovni PayPal račun.
Valuta tog računa biti će u američkim dolarima (USD), a plaćanje ću kasnije izvršavati u dolarima i eurima (EUR). PayPal automatski radi konverziju valuta.
Klikom na „Create Account“ kreiram Sandbox PayPal račun fortuno@example.com.
Kao što se može vidjeti, ovdje mi je potreban ranije kreiran Client ID. Ako drugačije ne navedem zadana valuta biti će USD. U jednom od primjera kao valutu ću dodati EUR, parametar
currency.
<p>Thank you for your payment. Your transaction has been completed, and a receipt for your purchase has been emailed to you. Log into your PayPal account to view transaction details.</p>
</ion-card>
</ion-col>
</ion-row>
</ion-content>
Koristim ngIf direktivu kako bi nakon uspješnog plaćanja umjesto gumba za plaćanje prikazao odgovarajuću poruku.
S obzirom da je u pitanju demo aplikacija na ekranu se neće nalaziti ništa drugo osim gumba za plaćanje na vrhu ekrana. U suprotnom bi se više moralo razmisliti o optimalnom mjestu za postavljanje gumba. Više o tome na poveznici https://developer.paypal.com/docs/checkout/best-practices/feature-paypal/#
Inicijalizacija transakcije vrši se klikom na gumb “PayPal” tj. funkcijom
createOrder unutar koje ću proslijediti samo iznos koji želim na/platiti.
JavaScript
1
2
3
4
5
6
7
8
9
createOrder:function(data,actions){
returnactions.order.create({
purchase_units:[{
amount:{
value:_this.paymentAmount
}
}]
});
},
Kada kupac odobri transakciju poziva se funkcija
onApprove.
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
onApprove:function(data,actions){
returnactions.order.capture()
.then(function(details){
console.log(details);
if(details.status=="COMPLETED"){
// Show a success message to the buyer
//alert('Transaction completed by ' + details.payer.name.given_name + '!');
_this.placanjeUspjesno=true;
}else{
alert("Neuspješno plaćanje!");
}
})
.catch(err=>{
console.log(err);
})
}
Kompletna funkcionalnost izgleda ovako:
home.page.ts
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import{Component}from'@angular/core';
declarevar window:any;
@Component({
selector:'app-home',
templateUrl:'home.page.html',
styleUrls:['home.page.scss'],
})
exportclassHomePage{
paymentAmount:string="10";
placanjeUspjesno:boolean=false;
constructor(){
this.paymentOptions();
}
paymentOptions(){
let _this=this;
setTimeout(()=>{
// Render the PayPal button into #paypal-button-container
window.paypal.Buttons({
// Set up the transaction
createOrder:function(data,actions){
returnactions.order.create({
purchase_units:[{
amount:{
value:_this.paymentAmount
}
}]
});
},
// Finalize the transaction
onApprove:function(data,actions){
returnactions.order.capture()
.then(function(details){
console.log(details);
if(details.status=="COMPLETED"){
// Show a success message to the buyer
//alert('Transaction completed by ' + details.payer.name.given_name + '!');
_this.placanjeUspjesno=true;
}else{
alert("Neuspješno plaćanje!");
}
})
.catch(err=>{
console.log(err);
})
}
}).render('#paypal-button-container');
},500)
}
}
Demo prikaz
Sada ću proći kroz čitav proces naplate i prikazati ga slikama.
Klikom na žuti gumb „PayPal“ pokrećem postupak plaćanja. Prijavljujem se pomoću PayPal Sandbox računa.
Biram na koji način želim platiti navedeni iznos. To mogu učiniti sa svojeg ukupnog balansa, kreditnom ili debitnom karticom koje su povezane s PayPal računom.
Klikom na “Pay Now” potvrđujem plaćanje. Plaćanje je uspješno izvršeno ako dobijem (Order) ID. U ovom slučaju to je
"id":"99D86747XH516732E".
PayPal će mi vratiti sljedeći odgovor, u kojemu imam sve potrebno kako bi kasnije mogao raditi provjeri plaćanja, nakon što je plaćanje uspješno prošlo:
Osim toga, potvrdu o uspješnom plaćanju mogu vidjeti ako se prijavim unutar PayPal Sandbox računa na adresi https://www.sandbox.paypal.com/ sa korisničkim imenom tomislavstankovic1-buyer@gmail.com i pripadajućom lozinkom.
Ovdje mogu vidjeti koliki mi je trenutni tj. ukupni dostupan iznos na PayPal Sandbox računu kao i popis svih transakcija.
Klikom na „Informatika Fortuno’s Test Store“ mogu vidjeti detalje navedene transakcije.
Zaključak
Što se klijentskog dijela aplikacije tiče to bi bilo sve.
Ostaje još napraviti serverski, backend, dio gdje će se vršiti provjera plaćanja. Na taj API šaljem ranije spomenuti ID"id":"99D86747XH516732E".
U ovom koraku trebam postaviti temelj tj. na
HomePage komponenti gdje ću kreirati dva gumba kako bi mogao prikazati dva načina za prosljeđivanje parametara.
Sada napokon mogu pokazati kako proslijediti podatke tj. parametre sa
HomePage na
DetailsPage na dva načina.
Prosljeđenim ću parametrima pristupiti kroz ActivatedRoute.
Query Params
Ovaj način je najčešći s kojim sam se susretao i ok je ako se radi mobilna aplikacija kojoj će se pristupati kroz npr. Google Play Store jer se u tom slučaju neće vidjeti URL svake od stranica.
Kako bi ovo funkcioniralo potrebno je koristiti Angular 7.2 ili noviju verziju.
State passed to any navigation. This value will be accessible through the extras object returned from router.getCurrentNavigation() while a navigation is executing. Once a navigation completes, this value will be written to history.state when the location.go or location.replaceState method is called before activating of this route. Note that history.state will not pass an object equality test because the navigationId will be added to the state before being written.
While history.state can accept any type of value, because the router adds the navigationId on each navigation, the state must always be an object. – NavigationExtras
Ovo rješenje je slično onome iznad s tom razlikom što izgleda ljepše kada je vidljiv URL jer se parametri ne vide. To je posebno korisno kada se radi Ionic Progressive Web App.