Example app for purpose of WarsawJS workshop #31
{
data: [
date: string(format=YYYY-MM-DD),
events: [
{
id: string(format=guid)
title: string
}
]
]
}
{
data: [
{
id: string(format=guid)
title: string
description: string
time: string(format=YYYY-MM-DDThh:mm)
notification: boolean
}
]
}
{
title: string
description: string
time: string(format=YYYY-MM-DDTHH:mm)
notification: boolean
}
{
id: string
}
{
title: string
description: string
time: string(format=YYYY-MM-DDTHH:mm)
notification: boolean
}
{
id: string
}
{
id: string
}
{
id: string
}
{
data: {
endpoint: URL
expirationTime: Date
keys: {
p256dh: string
auth: string
}
}
}
201 || resource create
Serwer w tym stanie serwuje pliki statyczne z folderu public.
Po uruchomieniu serwera, aplikację można zobaczyć w przeglądarce pod adresem localhost:5000.
Pierwszym zadaniem, będzie dodanie routingu do serwera.
Na podstawie kontraktu API, opisanego w pliku README na branchu master, dodać należy wszystkie endpointy wykorzystywane przez klienta.
Na razie nie mamy danych, więc będziemy zwracać zamockowane dane w postaci odpowiadającej projektowi api.
Wszystkie endpointy warto zgrupować przy pomocy wspólnego routera.
Po prawidłowym dodaniu endpointów, nie powinniśmy widzieć błędów w konsoli Network w przeglądarce.
Kroki:
- dodać do zależności
body-parseroraz dodać wykorzystanie do serweraexpress - stworzyć nowy plik na router główny aplikacji, wewnątrz utworzyć nowy router i wyekportować do użycia przez serwer
- stworzyć nowy plik na router api, wewnątrz utwrzoyć nowy router i wyekportować do użycia że przez router główny
- w pliku z routerem api, zdefiniować wymagane do pracy klienta endpointy zwracające zamockowane dane
Do logowania wykorzystamy OAuth ze strategią GitHub.
Potrzebne będą zależności passport oraz passport-github.
Rozwiązanie jjest oparte na sesji więc należy dodać do express obsługę sesji.
Wykorzystamy do tego zależność express-session.
Kroki:
- dodać do zależności
express-session,passport,passport-github - stworzyć plik zawierający kod inicjalizujący passport
- dodać metodę serializującą użytkownika
- dodać metodę deserializującą użytkownika
- użyć strategii
passport-github- dodanie nowej aplikacji github oauth https://github.com/settings/applications/new
- wykorzystanie
clientID,clientSecretz utworzonej aplikacji gh - zdefiniowanie callbacka
- zaimportować plik w
index.js
- dodanie do serwera wykorzystania
express-session - inicjalizacja
passport - dodanie routingu
GET:/, który przekierowuje niezalogowanych użytkowników do/auth/github - dodanie do głównego routera routingu na:
/logout- wylogowanie użytkownika i redirect na logowanie/auth/github- wykorzystuje middlewarepassportzgithub/auth/github/callback- wykorzystuje middlewarepassportzgithubz konfiguracjąfailureRedirectorazsuccessRedirect
- dodanie do routera api middleware czy użytkownik jest zalogowany
Do przechowywania danych użyjemy MongoDB. Jako sterownik posłuży nam mongoose.
Do pracy będziemy potrzebować 2 modeli i schem - UserModel oraz EventModel.
Wszystkie operacje na kolekcjach będziemy wykonywać przez moduł proxy api.
Dzięki temu warstwa bazy danych zostanie wyraźnie odcięta od domeny serwera.
Następnie wykorzystamy nowe api do integracji z apiRouter.
Kroki
-
dodanie do zależności
moment-timezoneorazmongoose -
stworzenie nowego pliku z kodem odpowiedzialnym za połączenie z bazą danych
-
dodanie importu wcześniej stworzonego pliku do
index.js -
stworzenie pliku na UserModel oraz definicja schemy i modelu mongoose
- identyfikator użytkownika powinień być unikalnym indexem
-
stworzenie pliku na EventModel oraz definicja schemy i modelu mongoose
-
stworzenie pliku na api i zdefiniowanie metod wymaganych do integracji z routerem api
-
getOrCreateUser - jako argumenty przyjmuje id użytkownika oraz callback
- zwraca wywołanie callback z błędem oraz obiekt
{ userId } - wykorzystać w strategii
oauthpodczas logowania - zamiast zwracaćprofile.idbezpośrednio wykorzystamy UserModel
- zwraca wywołanie callback z błędem oraz obiekt
-
getMonth - jako argumenty przyjmuje id użytkownika i datę w formacie 'YYYY-MM' zwraca:
- zwracamy 6 tygodni, zaczynając od początku tygodnia 1 dnia miesiąca
data: [ date: string(format=YYYY-MM-DD), events: [ { id: string(format=guid) title: string } ] ] -
getDayEvents - jako argumenty przyjmuje id użytkownika i datę w formacie 'YYYY-MM'
- zwraca listę wydarzeń danego dnia w postaci:
data: [ { id: string(format=guid) title: string description: string time: string(format=YYYY-MM-DDTHH:mm) notification: boolean } ] -
addEvent - jako argumenty przyjmuje id użytkownika i dane wydarzenia w postaci:
-
title: string description: string time: string(format=YYYY-MM-DDTHH:mm) notification: boolean
zwraca id wydarzenia
-
-
updateEvent - jako argumenty przyjmuje id użytkownika i dane wydarzenia w postaci:
-
title: string description: string time: string(format=YYYY-MM-DDTHH:mm) notification: boolean
zwraca id wydarzenia
-
-
deleteEvent - jako argumenty przyjmuje id wydarzenia
- zwraca id wydarzenia
-
-
użycie metod api w routerze
Teraz dodamy do aplikacji obsługę powiadomień przy wykorzystaniu web-push - zależność należy dodać do projektu.
Do prawidłowego funkcjonowania wymagane jest wygenerowanie poprawnych kluczy VAPID.
https://www.npmjs.com/package/web-push#using-vapid-key-for-applicationserverkey
Aplikacja kliencka wysyła obiekt rejestracji subskrycji za każdym razem gdy zainstaluje albo zauktualizuje service worker.
Aby wywołać w prosty sposób instalację SW najlepiej zatrzymać aktywny SW i przeładować stronę.
Za każdym razem gdy serwer otrzyma subskrycję powinień wysłać powiadomienie powitalne i zapisać subskrycję w bazie.
Kroki:
- dodanie zależności
web-push - stworzenie nowego pliku z kodem inicjalizującym
web-push- wygenerowanie VAPID keys zdognie z linkiem powyżej
- wykorzystanie metody
setVapidDetailsdo inicjalizacji - dodanie importu pliku do
index.js
- Dodanie SubscriptionModel, model zawiera pola na id użytwnika i dane subskrycji
- Dodanie do api metodę dodającą nową subskrycję użytkownika
- argumentami tej metody są id użytwnika i dane subskrycji
- metoda zwraca
_iddokumnetu
- dodać do endpointu
/api/notifications- zapisanie nowej subskrycji użytkownika
- wysłanie zwrotne powiadomienia na bazie zapisywanej subskrycji
Na koniec zadbamy aby do każdego wydarzenia w kalendarzu, które ma aktywne powiadomienie, zostało wysłane powiadomienie.
Zadbać należy aby powiadomienia były jednorazowe - jedno per wydarzenia.
Do stworzenia joba wykorzystamy agenda, którą należy dodać do zależności.
Następnie musimy uruchomić środowisko oraz zdefiniować job do wykonania oraz określić jego cykl.
Kroki
- dodać do api metodę
deleteSubscription- argument - id subskrycji
- zwrotka - id subskrycji
- dodać do api metodę pobierającą wydzarzenia, które wymagają powiadomienia w danym momencie.
- dodać do zależności
agenda - stworzyć nowy plik na kod związany z
agenda, dodać import doindex.js - zdefiniować timezone dla
moment-timezone - stworzyć nową istancję Agendy łącząć z bazą danych
- dodać nasłuchiwanie na event
ready, wewnątrz eventu:- rozpocząć pracę Agendy
- usunąć stare joby
- zdefiniować job
- powinien pobierać wszystkie wydarzenia, które wymagają powiadomienia
- po wysłaniu do danego powiadomienia, aktualizujemy model wydarzenia, tak aby nie miał już aktywnych powiadomień
- jeśli subskrycja jest zła - kasujemy ją
- odpalić job w określonym intervale
- zadbać o odpowiednie zakończenie pracy Agendy