Zadanie

Konzultacie a otazky pocas cviceni.

Kazdy tim musi byt pripraveny odovzdat zadanie 12.12. 2019 na cviceni.

Tie timy, ktore nestihnu odovzdat 12.12.2019 budu odovzdavat 16.12.2019 na cviceni v ramci nahrady vyucby.

Ukazka pre accessToken na spodku stranky.

  • Registracia pouzivatela - meno , heslo
  • Prihlasenie pouzivatela - meno, heslo
  • Odlhasenie pouzivatela
  • Po prihlaseni ma zostat prihlaseny az do odhlasenia
  • Po prihlaseni, ako aj po otvoreni aplikacii ak je prihlaseny sa otvori obrazovka so zoznamom WiFi miestnosti
  • Obrazovka so zoznamom WiFi sieti obsahuje
    • vsetky miestnosti, v ktorych pridal aspon jednu spravu,
    • miestnost konkretnej WiFi siete ku ktorej je pripojeny,
    • verejnu miestnost, ktoru je vidno vzdy.
    • V pripade, ak jednotlive WiFi siete nemaju skryte SSID a nemaju prazdne SSID, tak vsetky s rovnakym SSID patri do jednej WiFi miestnosti s nazvom SSID.
    • V pripade, ak jednotlive WiFi siete maju skryte SSID alebo maju prazdne SSID, tak nazov WiFi miestnosti je BSSID a do miestnosti patria len WiFi siete s rovnakym BSSID (pozn. vzdy len jedna WiFi siet)
  • Obrazovka so zoznamom kontaktov obsahuje
    • vsetkych pouzivatelov, ktorim poslal aspon jednu spravu,
    • vsetkych pouzivatelov, od ktorich dostal aspon jednu spravu
  • Obrazovka WiFi miestnosti
    • obsahuje zoznam prispevkov od pouzivatelov, najnovsi hore.
    • obsahuje hore moznost pridania prispevku. Kliknutim sa otvori nova obrazovka pre pridanie prispevku.
    • Pridavanie prispevku je umoznene len v pripade, ze pouzivatel je pripojeny na jednu z WiFi sieti patriacich miestnosti.
    • upozorni pouzivatela, ze nemoze pridat prispevok do miestnosti, kym sa nepripoji na jednu WiFi siet patriacu miestnosti
    • umoznuje kliknutim na profilovy obrazok alebo meno, otvorit obrazovku konverzacii s pouzivatelom.
    • umoznuje kopirovat cast textu alebo cely text prispevku
    • Povolene znaky pre vytvaranie FCM "topics" pre WiFi miestnosti su len a-zA-Z0-9-_.~%, vsetky ostatne budeme nahradzat znakom _. Takto nahradene SSID alebo BSSID budu pouzite ako ID pre miestnosti alebo FCM topics

  • Obrazovka pre pridanie prispevku umoznuje
    • vlozenie textu a pridanie prispevku po stlaceni na tlacidlo "odoslat"
    • kliknutim na tlacidlo "+" zobrazit novu obrazovku so zoznamom gif obrazkov pomocou GIPHY s moznostou vyhladavat. Po kliknuti sa Gif odosle ako prispevok.
    • Pri odosielani Gifu v requeste povinne dodrzat format gif:ID (napriklad. gif:lnyPptAfGwHeTdoQDk)
    • Pri zobrazovani sprav zistovat typ spravy Text/Gif, ak sa prve 4 znaky rovnaju "gif:" tak za nim nasleduje id gifu
    • Zobrazit Gif sa odporuca vo fixnej sirke tj. https://media2.giphy.com/media/GIF_ID/200w.gif pripadne GIF_ID/100w.gif
  • Obrazovka konverzacie
    • obsahuje spravy medzi dvoma pouzivatelmi (prihlasenym a prijimatelovi) najnovsie dole.
    • umoznuje napisanie novej textovej spravy pouzivatelovi kedykolvek na spodku obrazovky.
    • umoznuje napisanie novej spravy obsahujucej len jeden gif pouzivatelovi kedykolvek na spodku obrazovky.
    • Pri odosielani Gifu v requeste povinne dodrzat format gif:ID (napriklad. gif:lnyPptAfGwHeTdoQDk)
    • Pri zobrazovani sprav zistovat typ spravy Text/Gif, ak sa prve 4 znaky rovnaju "gif:" tak za nim nasleduje id gifu
    • Zobrazit Gif sa odporuca vo fixnej sirke tj. https://media2.giphy.com/media/GIF_ID/200w.gif pripadne GIF_ID/100w.gif
  • Uložiť FID (Id pre firebase cloud messaging) na server pomocou webservisu user/fid.php
  • Odoslanie notifikacie používateľovi (FCM nižšie), ktorému sme poslali privátnu správu. Zachytenie a zobrazenie notifikácii u príjemcu. (Použiť FID, ktoré vráti webservis pri čítaní konverzácii)
  • Odoslanie notifikacie WiFi skupine (FCM nižšie), do ktorej sme poslali príspevok. Zachytenie a zobrazenie notifikácii u člena skupiny len v prípade, že je aktuálne pripojený na WiFi sieť skupiny. (Použiť FID, ako názov WiFi skupiny)
  • Verejna skupina ma ID XsTDHS3C2YneVmEW5Ry7

    Je povinne pouzivat architekturu MVVM (Model View ViewModel) a poskytnute REST API spolu s GIPHY api pre pracu s Gif obrazkami.

    Pozn. Ak zabudne heslo, nie je mozna obnova (vytvori si novy ucet).

    Firebase Cloud Messaging

    https://firebase.google.com/docs/cloud-messaging

    Povolene znaky pre vytvaranie FCM "topics" pre WiFi miestnosti su len a-zA-Z0-9-_.~%, vsetky ostatne budeme nahradzat znakom _

    Navrh

    zadanie

    Notifikacie

    Na cviceni bola otazka ako odoslat notifikaciu pomocou requestu. Tu uvadzam ilustrativnu ukazku ako jeden zo sposobom, ktory pouzivam osobne.

    POST https://fcm.googleapis.com/fcm/send
    Content-Type: application/json
    Authorization: key=[token pre cloud messaging z console.firebase.com ]
    
    {
      "to": "/topics/testkanal",
        "data" : {
          "body" : "This is a Firebase Cloud Messaging Topic Message!",
          "title" : "FCM Message"
        }
    
    }
    

    Giphy

    GET https://api.giphy.com/v1/gifs/search?api_key=[API_KEY]&q=[SEARCH QUERY]&limit=25
    
    {"data": [], "pagination": {}, "meta": {} ]
    
    

    Kde vo vnutri data je

    json

    Do requesty je povinne ukladat ID na GIF.

    Do requestu sa odosiela v tvare gif:ID (napriklad. gif:lnyPptAfGwHeTdoQDk)

    API

    Vsetky requesty musia obsahovat v jsone aj atribut: "api_key": "c95332ee022df8c953ce470261efc695ecf3e784".

    Autorizacny token sa meni po prihlaseni, registracii ci refreshTokene. Autorizacny token ma obmedzenu dobu platnosti, po vyprsani je potrebne pouzit refresh token na ziskanie noveho tokenu.

    
    POST http://zadanie.mpage.sk/user/create.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    
    {
      "name": "testuser",
      "password": "heslo123"
    }
    
    {"uid":"135","access":"533b84b168ebde5c7ad061244a3f11fb2c391d98","refresh":"5eab569695595831fadfef20c8d3e5994669f48d"}
    
    Response code: 200 (OK)
    
    ###
    
    POST http://zadanie.mpage.sk/user/login.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    
    {
      "name": "testuser",
      "password": "heslo123"
    }
    
    {"uid":"11","access":"c180184dfd49ca04cb71b4932ac230c65e38e47e","refresh":"7ffbe617446a3f21b817119af2ef168368499d97"}
    
    Response code: 200 (OK); 
    
    ###
    
    POST http://zadanie.mpage.sk/user/refresh.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    
    {
      "uid": "4",
      "refresh": "1ae01ceac244a6efbff029c6073c4a1919a6bd04"
    }
    
    {"uid":"11","access":"e8c77880a7b1e7d5f3bc24c3d9670feab88ad9a4","refresh":"ff3bf8714f383b139f848deb238655e0233cfdd5"}
    
    Response code: 200 (OK)
    
    ###
    
    
    POST http://zadanie.mpage.sk/room/list.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    Authorization: Bearer 548aee2bc074733a982bee48aa80c4b09e8db5fc
    
    {
      "uid": "4"
    }
    
    
    [{"roomid":"Ynet","time":"2019-11-20 12:25:03"},{"roomid":"wifitest","time":"2019-11-07 13:51:47"}]
    
    Response code: 200 (OK)
    
    ###
    
    POST http://zadanie.mpage.sk/room/message.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    Authorization: Bearer 548aee2bc074733a982bee48aa80c4b09e8db5fc
    
    {
      "uid": "4",
      "room": "SSID (alebo BSSID ak siet ma skryte SSID)", //povolene znaky a-zA-Z0-9-_.~% vsetky ostatne nahradit znakom _
      "message": "aha" //text ak sprava, v pripade gif treba povinne dodrzat format: gif:ID (napriklad. gif:lnyPptAfGwHeTdoQDk)
    }
    
    
    
    
    Response code: 200 (OK)
    
    
    
    ###
    
    
    POST http://zadanie.mpage.sk/room/read.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    Authorization: Bearer 1442f33a1f2c220e431d83d0cad8007b73cf2cd8
    
    {
      "uid": "11",
      "room": "SSID (alebo BSSID ak siet ma skryte SSID)" //povolene znaky a-zA-Z0-9-_.~% vsetky ostatne nahradit znakom _
    }
    
    [{"uid":"6","roomid":"Ynet","message":"Init message","time":"2019-11-10 19:41:02","name":"useroNew@test.com"},...]
    
    Response code: 200 (OK)
    
    ###
    
    POST http://zadanie.mpage.sk/contact/message.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    Authorization: Bearer 548aee2bc074733a982bee48aa80c4b09e8db5fc
    
    {
      "uid": "4",
      "contact": "1 (uid kontaktu komu piseme)",
      "message": "aha spat" //text ak sprava, v pripade gif treba povinne dodrzat format: gif:ID (napriklad. gif:lnyPptAfGwHeTdoQDk)
    }
    
    
    
    
    Response code: 200 (OK)
    
    ###
    
    
    POST http://zadanie.mpage.sk/contact/list.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    Authorization: Bearer 548aee2bc074733a982bee48aa80c4b09e8db5fc
    
    
    {
      "uid": "4"
    }
    
    [{"name":"maros4@test.com","id":"7"},...]
    
    Response code: 200 (OK);
    
    ###
    
    POST http://zadanie.mpage.sk/contact/read.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    Authorization: Bearer 1442f33a1f2c220e431d83d0cad8007b73cf2cd8
    
    
    {
      "uid": "11",
      "contact": "7 (uid kontaktu s kym si piseme)"
    }
    
    
    [{"uid":"11","contact":"7","message":"test","time":"2019-11-07 13:35:27","uid_name":"maros","contact_name":"maros4@test.com","uid_fid":"aha","contact_fid":""},...]
    
    Response code: 200 (OK)
    
    ###
    
    POST http://zadanie.mpage.sk/user/fid.php
    Accept: application/json
    Cache-Control: no-cache
    Content-Type: application/json
    Authorization: Bearer 114638e46fc703bde0ab08a16c916d83f7cdfa28
    
    {
      "uid": "11",
      "fid": "id for firebase cloud messaging",
      "api_key": "c95332ee022df8c953ce470261efc695ecf3e784"
    }
    
    
    
    
    Response code: 200 (OK)
    
    

    Ukazka pre Access Token

    interface ZadanieApi{
    
        @POST(URL.USER_LOGIN_URL)
        suspend fun userLogin(@Body body: UserLoginRequest): Response
    
        @POST(URL.ROOM_LIST)
    	@Headers("ZadanieApiAuth: accept")
        suspend fun roomList(@Body body: RoomListRequest): Response
    
        @POST(URL.TOKEN_REFRESH_URL)
        fun tokenRefreshCall(@Body body: RefreshTokenRequest): Call
    
    	
        companion object {
    
            fun create(context: Context): ZadanieApi {
    
                val client = OkHttpClient.Builder()
                    .addInterceptor(AuthInterceptor(context))
                    .authenticator(TokenAuthenticator(context))
                    .build()
    
                val retrofit = Retrofit.Builder()
                        .baseUrl(URL.BASE_URL)
                        .client(client)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build()
    
                return retrofit.create(ZadanieApi::class.java)
            }
        }
    }
    
    
    
    class TokenAuthenticator(val context: Context) : Authenticator {
        override fun authenticate(route: Route?, response: okhttp3.Response): Request? {
            if (response.request().header("OpinAuth")?.compareTo("accept")==0)
                && response.code()==401)
            {
    			val userAccessToken = //get stored user accessToken
    
                if (!response.request().header("Authorization").equals("Bearer $userAccessToken")){
                    return null
                }
    			
    			val refreshToken= //get stored user refreshToken
    
                val tokenResponse = ZadanieApi.create(context).tokenRefreshCall(RefreshTokenRequest(user_id,refreshToken)).execute()
    
                if (tokenResponse.isSuccessful){
    			    userAccessToken=tokenResponse.body()!!.accessToken
                    uloz(tokenResponse.body()!!.accessToken) // store new access token
    				uloz(tokenResponse.body()!!.refreshToken) // store new refresh token
                    
                    return response.request().newBuilder()
                        .header("Authorization","Bearer $userAccessToken")
                        .build()
                }
    
            }
            return null
        }
    }
    
    
    
    class AuthInterceptor(val context: Context) : Interceptor{
    
    
        override fun intercept(chain: Interceptor.Chain): Response {
            val request = chain.request()
                .newBuilder()
                .addHeader("User-Agent","Zadanie-Android/1.0.0")
                .addHeader("Accept","application/json")
                .addHeader("Content-Type","application/json")
    
            if (chain.request().header("ZadanieApiAuth")?.compareTo("accept")==0) {
    		     val accessToken = //get stored accessToken
                request.addHeader("Authorization","Bearer $accessToken")
            }
    
            return chain.proceed(request.build())
        }
    }