view frontend/mfrontend/db.py @ 17:57a48d2aee18

Małe poprawki na liście zadań i mały dopisek do dokumentacji n.t. systemu szablonów
author Michał Rudowicz <michal.rudowicz@fl9.eu>
date Sun, 03 Apr 2011 14:07:19 +0200
parents c87f82a15606
children 9916d46ff096 b75a9ae3a060
line wrap: on
line source

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sqlite3
from flask import g
import ConfigParser
from mfrontend import utils, exceptions
from contextlib import closing
import os.path

config = ConfigParser.SafeConfigParser()
config.read('config.ini')

## Opisy wszystkich stanów zadań
states = {0 : u'Oczekujące',
          1 : u'Trwa',
          2 : u'Zakończone'}

def connect_db():
    """Funkcja łącząca się z bazą danych."""
    g.db = sqlite3.connect(config.get('Basic','Database'))

def disconnect_db():
    """Funkcja zamykająca połączenie z bazą danych"""
    g.db.close()

def init_db():
    """Funkcja przeprowadzająca inicjalizację bazy danych zgodnie
       z plikiem schema.sql. Na podstawie kodu ze strony
       http://flask.pocoo.org/docs/patterns/sqlite3/#initial-schemas
       Instalacja powiedzie się tylko wtedy, gdy w obecnym katalogu
       nie istnieje plik '.installed'. Plik taki jest tworzony
       po każdej instalacji, aby zapobiec operacjom na
       istniejących bazach.
       
       :returns:    True, jeśli instalacja została wykonana,
                    False, jeśli plik '.installed' istnieje.
    """
    if not os.path.isfile('.installed'):
        with open('schema.sql', 'r') as f:
            g.db.cursor().executescript(f.read())
        g.db.commit()
        open('.installed', 'w').close()
        return True
    else:
        return False

def query_db(query, args=(), one=False):
    """ Funkcja ułatwiająca odpytywanie bazy danych, źródło:
        http://flask.pocoo.org/docs/patterns/sqlite3/

        :param query:   Zapytanie SQL. Wszelkie niewiadome należy
                        zastępować znakiem zapytania ("?"), a
                        wartości umieszczać na liście w parametrze
                        args.
        :param args:    Lista zawierająca argumenty do zappytania.
        :param one:     Jeśli ustawione na True, to funkcja zwróci
                        tylko jeden element z bazy, w przeciwnym wypadku
                        wszystkie spełniające warunek zapytania.
    """
    cur = g.db.execute(query, args)
    rv = [dict((cur.description[idx][0], value)
               for idx, value in enumerate(row)) for row in cur.fetchall()]
    return (rv[0] if rv else None) if one else rv

def user_can_login(username, password):
    """Funkcja sprawdzająca, czy podany użytkownik może sie zalogować
       po podaniu danego w argumencie hasła.
       
       :param username: Nazwa użytkownika
       :param password: Hasło
       :returns:        Prawda, jeśli podane dane są akceptowalne, w przeciwnym
                        razie fałsz.
    """
    user = query_db('select * from users where username = ?',
                   [username], one=True)
    if user is None:    # Brak użytkownika o takiej nazwie
        return False
    if user['password'] == utils.hashPassword(password):
        if not user['activated']:
            raise exceptions.UserNotActivated()
        return True     # Jeśli aktywny i hasło dobre, to wpuszczamy
    # Najwyraźniej jest taki użytkownik, ale hasło się nie zgadza
    return False

def register_user(username, password):
    """ Funkcja rejestrująca nowego użytkownika w systemie.
        
        :param username:    Nazwa nowego użytkownika
        :param password:    Hasło w czystym tekście, funkcja sama
                            zajmie się hashowaniem
    """
    user = query_db('select * from users where username = ?;',
                    [username], one=True)
    if user is not None:
        raise exceptions.UserExists
    hashedPassword = utils.hashPassword(password)
    # teraz właściwe dodawanie danych do bazy
    query_db('INSERT INTO users (username, password, activated) VALUES (?,?,0);',
            [username, hashedPassword])
    g.db.commit()

def get_jobs(owner_id, hash, state):
    """ Funkcja pobiera informacje o zadaniach. Możliwe jest filtrowanie zadań.
        
        :param owner_id:    Pobiera informacje jedynie o zadaniach stworzonych przez
                            użytkownika o podanym id. Jeśli parametr ten jest ustawiony
                            na None, to pobiera zadania wszystkich użytkowników.
        :param hash:        Pobiera informacje o zadaniu o podanym hashu. Jeśli jest ustawione
                            na None, to pobiera informacje o wszystkich hashach.
        :param state:       Pobiera informacje o zadaniach będących w określonym stanie.
                            Jeśli jest ustawione na None, to pobiera informację o zadaniach
                            znajdujących się w każdym stanie.
        :returns:           Informacje o zadaniach z uwzględnieniem podanych w
                            parametrach filtrów.
    """
    parameters = []
    sqlLine = ""
    if owner_id is not None:
        sqlLine += "owner_id = ?"
        parameters.append(owner_id)
    if hash is not None:
        if not sqlLine == "":
            sqlLine += " AND "
        sqlLine += "hash = ?"
        parameters.append(hash)
    if state is not None:
        if not sqlLine == "":
            sqlLine += " AND "
        sqlLine += "state = ?"
        parameters.append(state)
    if sqlLine == "":
        sqlLine = "select * from jobs;"
    else:
        sqlLine = "select * from jobs where " + sqlLine + ";"
    result = query_db(sqlLine,parameters)
    # teraz trochę upiększamy wynik, np. pobierając nazwy użytkowników
    for job in result:
        job['username'] = get_user_name(job['owner_id'])
        job['state_text'] = states[job['state']]
    return result

def get_waiting_job():
    """ Funkcja zwraca dane o najstarszym oczekującym zadaniu.
        
        :returns: Dane o zadaniu.
    """
    return query_db("SELECT * FROM jobs WHERE state = 0 ORDER BY id ASC",[],one=True)

def get_job_by_id(job_id):
    """ Funkcja zwraca wszystkie informacje o wybranym zadaniu na podstawie
        numeru identyfikacyjnego.
        
        :param job_id: Identyfikator żądanego zadania
        :returns: Informacje o żądanym zadaniu.;q
    """
    return query_db("SELECT * FROM jobs WHERE id = ?;",
                   [job_id], one=True)

def edit_job(job_id, options):
    """ Funkcja modyfikująca właściwości zadania o podanym identyfikatorze.
        
        :param  job_id:  Identyfikator zadania, które chcemy zmodyfikować.
        :param  options: Słownik z nowymi wartościami kolumn w tabeli.
    """
    # klucze, których zmianę dopuszczamy
    keys = ["label", "state", "result", "percent", "last_checked"]
    for key in keys:
       if key in options:
           query_db("UPDATE jobs SET " + key + " = :value WHERE id = :id",
                    {"value":options["state"],"id":job_id})
    g.db.commit()

def get_user_name(user_id):
    """ Funkcja pobiera nazwę użytkownika o podanym identyfikatorze.
        
        :param user_id: Identyfikator użytkownika, którego nazwa jest pożądana.
        :returns:       String zawierający nazwę użytkownika, lub None,
                        jeśli użytkownik nie istnieje.
    """
    return query_db("SELECT username FROM users WHERE id = ?;",
                    [user_id], one=True)["username"]

def get_user_id(user_name):
    """ Funkcja pobiera identyfikator użytkownika na podstawie nazwy.
        
        :param user_name:    Nazwa użytkownika, którego indentyfikator ma zostać zwrócony.
        :returns:            Identyfikator użytkownika.
    """
    return query_db("SELECT id FROM users WHERE username = ?;",
                    [user_name], one=True)["id"]

def new_job(id, label, hash, method):
    """ Funkcja tworzy nowe zadanie i zapisuje je w bazie danych.
        
        :param id:      Identyfikator użytkownika, który ma zostać oznaczony
                        jako właściciel zadania.
        :param label:   Opis zadania.
        :param hash:    Hash do zdekodowania.
        :param method:  Metoda łamania haseł.
    """
    query_db("INSERT INTO jobs (owner_id, label, hash, method) VALUES (?,?,?,?);",
            [id, label, hash,method])
    g.db.commit()