Sessiot, autentikointi ja tietokannat - Viikkotehtävä 3
Tällä viikolla harjoitellaan Flaskin sessioita ja autentikointia sekä relaatiotietokantojen käsittelyä.
Kaikille tasoille yhteiset vaatimukset:
- Käytetään Python-kieltä. Ohjelmakoodi on kommentoitava.
- Sivut on toteutettava Flask-sovelluksena, joka toimii eu.pythonanywhere.com-palvelimella. Muille palvelimille sijoitetut sovellukset eivät kelpaa.
- Kaikkien sivujen on oltava validia HTML5:sta
- Javascriptiä ei saa käyttää
- Sovellus ei saa kaatua
- Tietojen tallentamiseen on käytettävä MySQL-tietokantaa.
- Sivujen tulee pysyä valideina, vaikka käyttäjä syöttäisi HTML-koodia joihinkin syötekenttiin. Sivuston sisältämä HTML on tuotettava Jinja-templatejen avulla. Python-koodin seassa ei saa esiintyä HTML-koodia. Jinja-koodi on pidettävä mahdollisimman yksinkertaisena.
- Kommentoikaa koodin oleellisimpia osia!
- Käytetään valmista tietokantaa, jonka luontilauseet löytyvät
valmiista
pohjasta tai
mysql.sql-tiedostosta (vrt. sqlite3-versio). Tietokanta on
samantyyppinen kuin viikkotehtävässä 1, mutta rakenne on muutettu
relaatiotietokantaan sopivaksi, mutta ei kuitenkaan täysin normaalimuotoiseksi (vrt. joukkueen jäsenet).
Tietokannan rakennetta ei saa muuttaa.
Joukkueen jäsenlistaus on tallennettu JSON-muodossa joukkueet-tauluun
- HTML-lomakkeessa, jolla aiheutetaan muutoksia (lisäys, muutos, poisto) tietokantaan, ei saa käyttää GET-metodia
- SQL-lauseiden muodostaminen merkkijono-operaatioilla on ehdottomasti kiellettyä ja pudottaa vastauksen pisteet nollaan
- Sivustolla on käytettävä UTF-8-merkistöä kaikkialla.
- Salasanoja ei saa tallentaa selkokielisinä vaan on käytettävä SHA-512-algoritmia.
- Tietokannan taulujen ID-kenttien sisältöä ei pidä näyttää lomakkeissa käyttäjälle eikä kysyä käyttäjältä. Linkeissä ym. id:tä pitää toki käyttää. Tietokannassa on käytetty SERIAL/AUTOINCREMENT-tyyppistä kenttää, jolloin tietokanta keksii ID-kenttien arvot tarvittaessa itse.
- SQL-kyselyissä ei saa käyttää DISTINCT-ominaisuutta. Kyselysi on kirjoitettu väärin, jos luulet DISTINCT-ominaisuudella korjaavasi tilanteen.
- Sovellus on toteutettava käyttäen mysql.connector-kirjastoa. SQLAlchemyn käyttäminen ei ole sallittua.
- Sovelluksen on toimittava riippumatta tietokannan sisällöstä. Et voi hardkoodata mitään tietokannan sisältöön liittyvää. Älä kuvittele, että koko tietokanta mahtuu kerralla esim. sessioon. Sovelluksen on toimittava, vaikka joukkueita olisi satoja ja rastileimauksia kymmeniä tuhansia.
- Sovelluksen on toimittava usealla eri käyttäjällä samaan aikaan.
- Tietokantayhteyden avaamiseen liittyvät tiedot (tietokannan nimi, käyttäjätunnus, salasana ja tietokantapalvelimen osoite) eivät saa esiintyä lähdekoodissa. Sijoita ne erilliseen tiedostoon, josta ne luetaan tarvittaessa. Esim. dbconfig.json
-
Tietokantayhteys täytyy avata yhteyspooliin, joka täytyy säilyttää globaalissa
muuttujassa.
Tietokantayhteys täytyy sulkea (palauttaa pooliin) kaikissa tilanteissa
try: db = pool.get_connection() except: #tämä osa ei ole pakollinen ... .... finally: #tämä suoritetaan aina lopuksi db.close() #palauttaa yhteyden pooliin
UNION
taiUNION ALL
-operaatioiden käyttäminen SQL-kyselyissä on tässä tehtävässä tarpeetonta ja kiellettyä.- Älä turhaan toteuta pythonilla asioita, jotka tietokannanhallintajärjestelmä jo tekee puolestasi. Tutustu kunnolla tietokannan rakenteeseen ja toimintaan
Taso 1
Toteuta tulospalvelusivusto, joka on vastaa toiminnoiltaan ja ulkoasultaan mallivideota.
- Tee fork valmiista pohjasta
- Käytä valmista tietokannan määrittelyä ja sisältöä. Luo vastaava MySQL-tietokanta, jota käytät sovelluksessasi. Tallenna kaikki muutokset samaan tietokantaan. Huom! Tietokannan sisältö ei ole aivan sama kuin aiemmissa tehtävissä. Tässä versiossa on useita samannimisiä joukkueita ja kilpailuja. Voit sovellusta kehittäessä käyttää myös tietokannan sqlite3-versiota, mutta valmiin sovelluksen on käytettävä mysql-tietokantaa.
- Sovellukseen pitää kirjautua valitsemalla lomakkeelta jokin tietokannassa olevista kilpailuista ja
syöttämällä lomakkeelle joukkueen nimi ja salasana. Valittavista kilpailuista on nähtävä selkeästi minkä vuoden
kilpailu on kyseessä. Kilpailut on lomakkeella listattava ensisijaisesti kilpailun nimen mukaan aakkosjärjestyksessä
ja toissijaisesti kilpailun alkuajan kohdan mukaan siten, että vanhin kilpailu on on ensin.
Salasana on kaikilla sama eli ties4080. Salasana ei saa esiintyä selkokielisenä ohjelmakoodissa eikä tiedostoissa!
Joukkueen nimessä ei huomioida isoja ja pieniä kirjaimia eikä mahdollisiä välilyöntejä nimen alussa ja lopussa. Ts. " Kukka kaali " on sama asia kuin "kukka kaali". Huom. SQLitessa UPPER-funktio ei oletuksena tue skandinaavisia merkkejä. kts. SQLITE3 ja lajittelufunktiot - Toteuta sivuston autentikointi siten, että käytät tietokannasta löytyviä
salasanoja. Jokaisella joukkueella on sama salasana (ties4080), jota
vastaava tarkiste löytyy tietokannan joukkueet-taulusta, ja on luotu käyttäen
tietokantaan tallennettua joukkueen id-kenttää seuraavalla tavalla:
import hashlib m = hashlib.sha512() m.update( str(joukkueen_id).encode("UTF-8") ) m.update( 'ties4080'.encode("UTF-8") ) salasana = m.hexdigest()
Salasana on generoitu hexdigest()-funktiolla
- Jos nimi tai salasana oli väärä tai joukkuetta ei löydy valitusta kilpailusta, palautetaan käyttäjä takaisin kirjautumissivulle ja näytetään sivulla virheilmoitus: "Kirjautuminen epäonnistui".
- Jos yrittää tulla jollekin sovelluksen sivulle kirjautumatta, edelleenohjataan automaattisesti kirjautumissivulle.
- Oikeiden kirjautumistietojen syöttämisen jälkeen pääsee automaattisesti (edelleenohjaus, redirect) joukkuelistaussivulle
- Sovelluksen jokaisella alasivulla on sivun ylälaidassa navigointipalkki jossa
on seuraavanlaiset tiedot:
- Linkki sivuston etusivulle
- Kilpailun nimi ja alkamispäivä
- Kirjautuneen joukkueen nimi, josta on linkki sivulle, jossa joukkue voi muokata tietojaan
- Linkki joukkuelistaussivulle
Kirjautumissivulla ei ole navigointilinkkejä.
- Toteuta joukkuelistaussivu jossa on listaus kaikista valitun
kilpailun (kirjautuneen joukkueen kilpailun) joukkueista. Listauksessa näkyvät myös sarjan nimi sekä
joukkueiden jäsenet.
Joukkuelistaus on ensisijaisesti aakkosjärjestyksessa sarjan nimen mukaan ja
toissijaisesti joukkueen nimen mukaan. Joukkueen jäsenten nimet listataan myös
aakkosjärjestyksessä. Järjestäminen on case-insensitive eli ei välitä onko
käytetty isoja tai pieniä kirjaimia. Joukkueiden järjestäminen on tehtävä
SQL-kyselyssä.
Listauksen on oltava seuraavan mallin mukainen:
- Sarjan nimi
- Rennot 2
- Heikki Häkkinen
- Pia Virtanen
- Sari Maaninka
- Retkellä v 13
- Henna Venäläinen
- Katja Vitikka
- ...
- Rennot 2
<ul> <li>Sarjan nimi <ul> <li>Rennot 2 <ul> <li>Heikki Häkkinen</li> <li>Pia Virtanen</li> <li>Sari Maaninka</li> </ul> </li> <li>Retkellä v 13 <ul> <li>Henna Venäläinen</li> <li>Katja Vitikka</li> </ul> </li> <li>...</li> </ul> </li> </ul>
Listauksessa tarvittavat tiedot on haettava tietokannasta yhdellä sql-kyselyllä. Jos yrität hakea erikseen jokaisen joukkueen jäsenen tietoja, pieleen menee.
- Sarjan nimi
- Luo sivu, jossa järjestelmään kirjautunut joukkue voi muuttaa oman joukkueensa
tietoja. Lomakkeella on oltava valmiina joukkueen aiemmat tiedot. Sivulla on
lomake, joka sisältää seuraavat asiat:
- Sarja, joka on valittava tietokannassa tarjolla olevista sarjoista. Sarjan valinta on toteutettava select-elementin (alasvetovalikon) avulla. Valittavana saa olla vain valittuun kilpailuun kuuluvia sarjoja.
- Joukkueen nimi, jota ei saa jättää tyhjäksi
- Samassa sarjassa ei saa olla kahta samannimistä joukkuetta. Nimien vertailu on caseinsensitive eikä mahdollista whitespacea nimen alussa tai lopussa huomioida.
- Joukkueen jäsenet, joita voi olla 2-5 kappaletta. Lomakkeella on valmiina viisi kenttää joihin voi syöttää jäsenten nimiä. Jäsenen nimi ei saa olla tyhjä tai pelkkää whitespacea eli tyhjiä kenttiä ei huomioida. Kaikilla saman joukkueen jäsenillä täytyy olla uniikki nimi (caseinsensitive).
- Käytä mahdollisimman paljon hyväksesi tietokannan omia rajoitteita
- Jos lomakkeen tiedoissa on puutteita, niin virheistä pitää ilmoittaa kyseisen kentän vieressä esitettävällä virheilmoituksella. Esim. joukkueen nimeä ei ole annettu tai jäseniä on syötetty vähemmän kuin kaksi kappaletta. Jos tiedoissa on virheitä tai puutteita, muutoksia ei tallenneta.
- Aiemmin tietokannassa olleiden arvojen täytyy olla lomakkeella valmiina odottamassa muutoksia. Jos syötetyissä tiedoissa on virheitä, lomake muistaa myös virheelliset syötteet.
Taso 3
Toteuta taso 1 -mukainen sovellus seuraavilla muutoksilla ja lisäyksillä:
- Tee sovellukseen sivu (/logout), jolla voi kirjautua ulos sovelluksesta painikkeella. Uloskirjautumisen jälkeen siirrytään takaisin kirjautumissivulle eikä muille sivuille enää pääse. Lisää navigointipalkkiin linkki uloskirjautumissivulle.
- Lisää sovellukseen uusi sivu (/admin), jolla pyydetään kirjautumaan sisään ylläpitäjänä. Sivulla on yksi salasanakenttä. Salasanana toimii admin. Salasana ei saa esiintyä koodissa eikä tiedostoissa selkokielisenä.
- Kirjauduttaessa sovellukseen admin-sivulta muuttuu sovelluksen ulkoasu. Huom. tee aivan uudet sivut ylläpitäjän käyttöön. Älä yritä muokata edellisellä tasolla olevia sivuja. admin-sivuille kirjauduttaessa ei saa päästä edellistasolla toteutetuille sivuille
- Navigointipalkissa lukee joukkueen nimen sijaan sana admin,
josta on linkki sovelluksen etusivulle.
Sovelluksen etusivulla on linkkilistaus tietokannasta löytyvistä kilpailuista aikajärjestyksessä. Sovelluksen on toimittava vaikka kilpailujen nimet olisivat mitä tahansa.
- Jäärogaining 2015-03-15
- Jäärogaining 2016-03-15
- Fillarirogaining 2016-05-08
- Kintturogaining 2017-03-18
- ...
- ...
- Kilpailun nimeä klikattaessa päästään sivulle, jossa listataan
kilpailun sarjat keston mukaan järjestettyinä. Sovellus muistaa valitun kilpailun.
Sovelluksen on toimittava kaikilla mahdollisilla sarjanimillä. Et voi hardkoodata
sarjojen nimiä vaan ne on aina haettava tietokannasta.
Listaus on oltava seuraavan mallin mukainen:
<ul> <li><a href="...">4 h</a></li> <li><a href="...">2 h</a></li> <li><a href="...">8 h</a></li> </ul>
- Valittaessa sarjalistaussivulta sarja päästään sivulle, jossa listataan kaikki
kyseisen sarjan joukkueet. Sovellus muistaa valitun sarjan.
-
Samalla sivulla on lomake, jolla voidaan lisätä uusia joukkueita valittuna olevaan sarjaan.
Joukkueelta kysytään samat tiedot, kuin joukkueen tietojen muutoslomakkeella (kts. taso 1).
Sarjaa ei tarvitse kysyä, koska se on jo valittu.
Myös samat tarkistukset ovat voimassa.
Lisäksi lomakkeella voi antaa joukkueelle halutun salasanan. Joukkueen salasanan
asettaminen on tehtävä transaktion sisällä: Lisää ensin joukkue, tarkista onnistuneen joukkueen lisäämisen jälkeen
mikä on lisätyn joukkueen id (
SELECT LAST_INSERT_ID()
), luo salasanan hash joukkueen id:n perusteella. - Onnistuneen joukkueen lisäämisen jälkeen saadaan listaus sarjan joukkueista. Myös juuri lisätty joukkue täytyy näkyä listauksessa. Sovellus muistaa lisätyn joukkueen.
-
Samalla sivulla on lomake, jolla voidaan lisätä uusia joukkueita valittuna olevaan sarjaan.
Joukkueelta kysytään samat tiedot, kuin joukkueen tietojen muutoslomakkeella (kts. taso 1).
Sarjaa ei tarvitse kysyä, koska se on jo valittu.
Myös samat tarkistukset ovat voimassa.
Lisäksi lomakkeella voi antaa joukkueelle halutun salasanan. Joukkueen salasanan
asettaminen on tehtävä transaktion sisällä: Lisää ensin joukkue, tarkista onnistuneen joukkueen lisäämisen jälkeen
mikä on lisätyn joukkueen id (
- Tee joukkuelistauksessa olevista joukkueiden nimistä linkkejä.
Linkki vie joukkueen omalle sivulle, joka on lähes samanlainen kuin
tasolla 1, mutta ei sama sivu, eli pääsee muokkaamaan joukkueen tietoja.
- Myös salasanan voi vaihtaa
- Joukkueen sarja täytyy valita käyttäen radiopainikkeita.
- Lisää joukkueen muokkauslomakkeeseen myös checkbox, jonka valitsemalla kyseinen joukkue poistetaan tietorakenteesta. Joukkuetta ei kuitenkaan saa poistaa, jos joukkueella on jo rastileimauksia. Anna selkeä virheilmoitus, jos joukkueen poistaminen ei onnistu.
- Kirjauduttaessa järjestelmään joukkueena voi joukkue vaihtaa omalla sivullaan muiden tietojensa lisäksi myös salasanansa.
-
Navigointi admin-tilassa toimii seuraavalla tavalla:
- Kilpailut vie sivulle, jossa listataan kaikki kilpailut. Valittaessa tällä sivulla jokin kilpailu unohdetaan aiemmin valitut sarjat ja joukkueet, jos valittu kilpailu on eri kuin aiemmin valittuna ollut.
- Sarjat vie sivulle, jossa listataan viimeksi valitun kilpailun sarjat. Jos kilpailua ei ole vielä valittu, ohjaudutaan Kilpailut-sivulle
- Joukkueet vie sivulle, jossa listataan viimeksi valitun sarjan joukkueet. Jos sarjaa ei ole vielä valittu, ohjaudutaan Sarjat-sivulle
- Joukkue vie sivulle, jossa muokataan viimeksi valitun tai lisätyn joukkueen tietoja. Jos joukkuetta ei ole vielä kertaakaan valittu tai lisätty, ohjaudutaan Joukkueet-sivulle
- Logout kirjaa ulos järjestelmästä. Uloskirjautumisen jälkeen ei enää päästä muille kuin sisäänkirjautumissivulle.
- Tasolla 3 on osoitettava SQL-liitoskyselyjen toteutustaitoa. Pelkästään IN- tai EXISTS-operaatioilla tehdyt kyselyt eivät kelpaa.
Taso 5
Toteuta taso 3 -mukainen sovellus seuraavilla muutoksilla ja lisäyksillä:
- Muokkaa ADMIN-tilan joukkuelisäyslomaketta siten, että joukkueeseen voi lisätä 1 - N jäsentä. Sinun pitää itse keksiä tähän järkevä toteutustapa. Javascriptia ei saa käyttää. Muuta myös kaikki joukkueen tietojen muokkauslomakkeet toimimaan 1 - N jäsenellä.
- Muuta ADMIN-tilan navigointia siten, että Sarjat-sanan tilalla lukee aina valittuna olevan kilpailun nimi. Muuta myös Joukkueet-sanan sijalle aina valittuna olevan sarjan nimi. Muuta navigointiin myös joukkue-sanan tilalle valittuna olevan joukkueen nimi. Jos jotain osaa ei ole vielä valittu, niin käytä silloin samoja sanoja, kuin kolmostasolla
- Lisää sovelluksen admin-osioon uusi sivu, jossa listataan kilpailun kaikki
rastit kaikkine tietoineen taulukkomuodossa. Kunkin rastin yhteydessä kerrotaan
myös lukumäärä tämän rastin leimauskerroista. Huomioi myös rastit joita ei ole
leimattu kertaakaan! Lisää rastisivulle vievä linkki navigointipalkkiin sekä
sarjalistaussivulle.
Rastilistauksen järjestys on oltava eniten leimauksia keränneestä rastista vähiten keränneeseen rastiin.
Kaikkien rastien listaus on tehtävä SQL-kyselyllä, jossa käytetään sopivaa ulkoliitosta (LEFT OUTER, RIGHT OUTER tai FULL OUTER)
Käyttäjien kommentit