#!/usr/bin/python # -*- coding: utf-8 -*- from flask import Flask, session, redirect, url_for, escape, request, Response, render_template import hashlib import sys from functools import wraps import sqlite3 import logging import os import werkzeug.exceptions from flask_wtf import FlaskForm from wtforms import Form, BooleanField, StringField, validators, IntegerField, SelectField, widgets, SelectMultipleField, ValidationError, RadioField # debuggausta helpottaa seuraava, joka tekee flask.log-tiedoston logging.basicConfig(filename='../../../log/flask.log',level=logging.DEBUG) from contextlib import closing app = Flask(__name__) app.debug = True # set the secret key. keep this really secret: app.secret_key = '"\xf9$T\x88\xefT8[\xf1\xc4Y-r@\t\xec!5d\xf9\xcc\xa2\xaa' # voidaan napata kiinni palvelimen virheet @app.errorhandler(werkzeug.exceptions.InternalServerError) def handle_internal_server_error(e): return Response(u'Internal Server Error\n' + unicode(e), status=500, content_type="text/plain; charset=UTF-8") def auth(f): ''' Tämä decorator hoitaa kirjautumisen tarkistamisen ja ohjaa tarvittaessa kirjautumissivulle ''' @wraps(f) def decorated(*args, **kwargs): if not 'kirjautunut' in session: return redirect(url_for('kirjaudu')) return f(*args, **kwargs) return decorated @app.route('/kirjaudu', methods=['POST','GET']) def kirjaudu(): try: tunnus = request.form['tunnus'] except: tunnus = "" try: salasana = request.form['salasana'] except: salasana = "" # tähän pitää rakentaa varsinainen salasanan tarkistaminen # koskaan ei pidä tallentaa tai vertailla selkokielisiä salasanoja! # salasanan digest-versio haettaisiin oikeasti esim. tietokannasta # Tässä salasana on nyt vakio m = hashlib.sha512() avain = "omasalainenavain" m.update(avain) m.update(salasana) if len(tunnus) and m.digest() == "6n\x90\xb5\xfe)\xa9\xd9\xc1B\n\xfa3LK\x19\xc4\xd6=\xcd \x0fBKz\x9f\xe32\x8a5-\xa5\x81\x8f\xc0<\xff\xa4c\xc26-\xb3S[a-\xf4\xeb'\xdf3\xd4r\x0f\xbfY)dW\x1a\xd7W.": session['kirjautunut'] = "ok" return redirect(url_for('laskuri')) return render_template('kirjaudu.html') @app.route('/logout') def logout(): session.pop('kirjautunut',None) return redirect(url_for('kirjaudu')) @app.route('/') def hello_world(): return Response(u"Hello World", content_type="text/plain; charset=UTF-8") @app.route('/laskuri', methods=['POST','GET']) @auth def laskuri(): try: luku = int(request.form['luku']) except: luku = 0 try: session['summa'] = session['summa'] + luku except: session['summa'] = 0 return render_template('laskuri.html', luku=luku) @app.route('/nollaa') def nollaa(): session.pop('summa',None) return redirect(url_for('laskuri')) @app.route('/lomake', methods=['POST','GET']) def lomake(): tiedekunnat = {0:"Valitse tiedekunta", 1:"Humanistinen tiedekunta",2:"Informaatioteknologin tiedekunta", 3:"Kasvatustieteiden tiedekunta", 4:"Liikunta- ja terveystieteiden tiedekunta", 5:"Matemaattis-luonnontieteellinen tiedekunta", 6:"Taloustieteiden tiedekunta", 7:"Yhteiskuntatieteellinen tiedekunta"} kentat = {"etunimi":"","sukunimi":"","tdk":""} errors = dict(kentat) #tekee kopion errors2 = {} kentat2 = {} tehtavia = 9 # lisätään tehtäviä varten errors-dictiin paikat if request.method == 'POST': #varmistetaan, että lomake on lähetetty for k in errors: try: kentat[k] = request.form[k] except KeyError: errors[k] = u"!" # ei kelpuuteta välilyöntejä ym. whitespace-merkkejä if not len(kentat[k].strip()): errors[k] = "!" # varmistetaan että tiedekunnan valinta on integer niin voi suoraan vertailla dictin avaimiin try: kentat["tdk"] = int(kentat["tdk"]) except KeyError: kentat["tdk"] = 0 for i in range(1, tehtavia+1): key = "t" + unicode(i) try: pisteet = request.form[key] except: pisteet = "" errors2[key] = "" kentat2[key] = pisteet try: p = int(pisteet) if p < 0 or p > 5: errors2[key] = "virhe" except: if pisteet != "": errors2[key] = "virhe" return render_template('lomake.html', errors=errors, kentat=kentat, tiedekunnat=tiedekunnat, errors2=errors2, tehtavia=tehtavia, kentat2=kentat2) class MultiCheckboxField(SelectMultipleField): """ A multiple-select, except displays a list of checkboxes. Iterating the field will produce subfields, allowing custom rendering of the enclosed checkbox fields. """ widget = widgets.ListWidget(prefix_label=False) option_widget = widgets.CheckboxInput() @app.route('/wtlomake', methods=['POST','GET']) def wtlomake(): # luodaan lomakeluokka funktion sisällä, jotta voidaan sitä huoletta muokata # myös dynaamisesti. CGI-ohjelmassa toimisi myös globaalina, mutta ei tilanteissa # jossa sovellus jää palvelimen muistiin tiedekunnat = [(0,u"Valitse tiedekunta"), (1,u"Humanistinen tiedekunta"),(2,u"Informaatioteknologian tiedekunta"), (3,u"Kasvatustieteiden tiedekunta"), (4,u"Liikunta- ja terveystieteiden tiedekunta"), (5,u"Matemaattis-luonnontieteellinen tiedekunta"), (6,u"Taloustieteiden tiedekunta"), (7,u"Yhteiskuntatieteellinen tiedekunta")] class Arvosanalaskuri(FlaskForm): etunimi = StringField(u'Etunimi', [validators.InputRequired(), validators.Length(min=2, message=u"Liian lyhyt etunimi")]) sukunimi = StringField(u'Sukunimi', [validators.InputRequired(),validators.Length(min=2, message=u"Liian lyhyt sukunimi")]) #Jos haluat käyttääkin radiobuttoneita niin muuta seuraavaan SelectField-tilalle RadioField. Huom. template voi vaatia myös hieman viilailua jos tekee tämän muutoksen tiedekunta = SelectField(u'Tiedekunta', choices=tiedekunnat, validators=[validators.InputRequired(message=u"Virheellinen tiedekunta"), validators.NumberRange(min=1, max=len(tiedekunnat), message=u"Virheellinen valinta")], coerce=int) tiedekunta_multi = SelectMultipleField(u'Tiedekunta multi', choices=tiedekunnat, coerce=int,option_widget=widgets.CheckboxInput(), widget=widgets.ListWidget(prefix_label=False)) def validate_tiedekunta_multi(form, field): if not len(field.data): raise ValidationError(u"Valitse vähintään yksi tiedekunta") for value in field.data: if value < 1 or value > len(tiedekunnat): raise ValidationError(u"Valitse vähintään yksi tiedekunta") lkm = 10 for t in range(1, lkm+1): setattr(Arvosanalaskuri, u"t" + unicode(t), IntegerField(unicode(t), validators=[validators.optional(),validators.NumberRange(min=0, max=5, message=u"Virheellinen arvosana")])) form = Arvosanalaskuri() # validoidaan lomake vasta kun se on oikeasti lähetetty if request.method == 'POST': form.validate() return render_template('wtlomake.html', form=form, lkm=lkm) @app.route('/wtlomake2', methods=['POST','GET']) def wtlomake2(): tiedekunnat = [(0,u"Valitse tiedekunta"), (1,u"Humanistinen tiedekunta"),(2,u"Informaatioteknologian tiedekunta"), (3,u"Kasvatustieteiden tiedekunta"), (4,u"Liikunta- ja terveystieteiden tiedekunta"), (5,u"Matemaattis-luonnontieteellinen tiedekunta"), (6,u"Taloustieteiden tiedekunta"), (7,u"Yhteiskuntatieteellinen tiedekunta")] class Arvosanalaskuri(FlaskForm): etunimi = StringField(u'Etunimi', validators=[validators.InputRequired(),validators.Length(min=2, message=u"Liian lyhyt etunimi")]) sukunimi = StringField(u'Sukunimi', validators=[validators.InputRequired(),validators.Length(min=2, message=u"Liian lyhyt sukunimi")]) tiedekunta = SelectField(u'Tiedekunta', choices=tiedekunnat, coerce=int) lkm = 10 for t in range(1, lkm+1): setattr(Arvosanalaskuri, u"t" + unicode(t), IntegerField(unicode(t), validators=[validators.optional(),validators.NumberRange(min=0, max=5, message=u"Virheellinen arvosana")])) form = Arvosanalaskuri() if request.method == 'POST': form.validate() return render_template('wtlomake2.html', form=form, lkm=lkm) tiedekunnat = [(0,u"Valitse tiedekunta"), (1,u"Humanistinen tiedekunta"),(2,u"Informaatioteknologian tiedekunta"), (3,u"Kasvatustieteiden tiedekunta"), (4,u"Liikunta- ja terveystieteiden tiedekunta"), (5,u"Matemaattis-luonnontieteellinen tiedekunta"), (6,u"Taloustieteiden tiedekunta"), (7,u"Yhteiskuntatieteellinen tiedekunta")] class Arvosanalaskuri2(FlaskForm): etunimi = StringField(u'Etunimi', validators=[validators.InputRequired(),validators.Length(min=2, message=u"Liian lyhyt etunimi")]) sukunimi = StringField(u'Sukunimi', validators=[validators.InputRequired(),validators.Length(min=2, message=u"Liian lyhyt sukunimi")]) tiedekunta = SelectField(u'Tiedekunta', choices=tiedekunnat, coerce=int) lkm = 10 for t in range(1, lkm+1): setattr(Arvosanalaskuri2, u"t" + unicode(t), IntegerField(unicode(t), validators=[validators.optional(),validators.NumberRange(min=0, max=5, message=u"Virheellinen arvosana")])) @app.route('/wtlomake3', methods=['POST','GET']) def wtlomake3(): # Käytettävä samoja attribuuttien nimiä kuin Arvosanalaskuri2-luokassa class Oma(): etunimi = "Tommi_oma_luokka" sukunimi = "Lahtonen_oma_luokka" tiedekunta = 1 oma = Oma() # Jos request.form on olemassa eli lomake on lähetetty niin käytetään sitä # Jos request.formia ei ole niin sitten käytetään oma-objektin sisältöä # jos oma-objektia ei ole annettu niin käytetään data-parametria, joka # kelpuuttaa dictionaryn form = Arvosanalaskuri2(formdata=request.form, obj=oma) # tai # Tässä samat avaimet kuin Arvosanalaskuri2-luokan attribuuttien nimet oletus = {"etunimi": "Tommi_dict", "sukunimi": "Lahtonen_dict", "tiedekunta": 2} form = Arvosanalaskuri2(formdata=request.form, data=oletus) if request.method == 'POST': form.validate() return render_template('wtlomake3.html', form=form, lkm=lkm) if __name__ == '__main__': # debug-moodi ei turvallisuussyistä toimi users.jyu.fi:ssä :-( app.debug = True app.run(debug=True)