search APIs are more RESTful

This commit is contained in:
boyska 2013-11-26 14:45:31 +01:00
parent 0348e2cc2e
commit a8406e74be
5 changed files with 145 additions and 173 deletions

View file

@ -1,8 +1,7 @@
# from bottle import hook, response, route, run, static_file, request
import datetime
import logging
from bottle import Bottle, hook, response, request,static_file, redirect
from bottle import Bottle, request, static_file, redirect
from techrec import Rec, RecDB
@ -19,15 +18,10 @@ class RecServer:
def start(self):
self._app.run(host=self._host, port=self._port, debug=True)
@hook('after_request')
def enable_cors(self):
#These lines are needed for avoiding the "Access-Control-Allow-Origin" errors
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'PUT, GET, POST, DELETE, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
def _route(self):
### This is the API part of the app
# TODO: move to namespace /api/
# TODO: create a "sub-application"
self._app.route('/favicon.ico', callback=self.favicon)
self._app.route('/help', callback=self.help)
self._app.route('/help/', callback=self.help)
@ -36,8 +30,10 @@ class RecServer:
# self._app.post('/create', callback=self.create)
self._app.route('/update', method="POST", callback=self.update)
self._app.route('/search', method="POST", callback=self.search)
self._app.route('/search', method=["GET", "POST"], callback=self.search)
self._app.route('/delete', method="POST", callback=self.delete)
## Static part of the site
self._app.route('/static/<filepath:path>',
callback= lambda filepath: static_file(filepath, root='static/'))
self._app.route('/js/<f>',
@ -61,7 +57,6 @@ class RecServer:
"""
# @route('/create', method=['OPTIONS','POST'])
def create(self):
self.enable_cors()
req = dict( request.POST.allitems() )
ret = {}
print "Server:: Create request %s " % req
@ -94,7 +89,6 @@ class RecServer:
"""
# @route('/delete/<recid>') # @route('/delete/<recid>/')
def delete( self, recid = None ):
self.enable_cors()
req = dict( request.POST.allitems() )
logging.info("Server: request delete %s " % ( req ) )
if not req.has_key( "recid" ):
@ -110,7 +104,6 @@ class RecServer:
"""
# @route('/delete/<recid>') # @route('/delete/<recid>/')
def update( self ):
self.enable_cors()
req = dict( request.POST.allitems() )
ret={}
@ -126,18 +119,18 @@ class RecServer:
"""
JSON' RESPONDER
"""
def rec_msg(self, msg): return self.rec_xerr("message", msg)
def rec_err(self, msg): return self.rec_xerr("error", msg)
def rec_xerr(self,_type,_msg): return { _type : _msg }
def rec_msg(self, msg): return {"message": msg, "status": True}
def rec_err(self, msg): return {"error": msg, "status": False}
"""
@route('/search') # @route('/search/') # @route('/search/<key>/<value>')
"""
def search( self, args=None):
self.enable_cors()
req = dict( request.POST.allitems() )
if request.method == 'GET':
req = dict( request.GET.allitems() )
else:
req = dict( request.POST.allitems() )
print "Search request: %s" % (req)
name = "%s" % req["name"]

View file

@ -22,7 +22,7 @@ var txt_start = "Inizia";
var txt_stop = "Ferma";
var txt_download = "Scarica";
var srvaddr = "http://127.0.0.1:8000";
var srvaddr = "/";
var almostone = false;
var noplusbotton = true;
@ -31,18 +31,18 @@ var rec_name_default = "";
/*
TODO: cambiare logica
Quando premo il primo tasto, faccio la crazione,
Quando premo il primo tasto, faccio la crazione,
per ogni altro pulsante, faccio solo e sempre UPDATE
*/
/**
* Perform Ajax async loading
/**
* Perform Ajax async loading
**/
function newformstr ( recid , butflag=false )
function newformstr ( recid , butflag=false )
{
var formid = rs_formid( recid );
var str = "<form id=\""+formid+"\" name=\""+formid+"\" action=\"#\">";
if (butflag) {
str = str + "<input type=\"button\" name=\""+trx_startbut(recid)+"\" id=\""+trx_startbut(recid)+"\" ";
str = str + " class=\"recbutton\" value=\"Inizia\" />";
@ -53,7 +53,7 @@ function newformstr ( recid , butflag=false )
str = str + "<input type=\"submit\" name=\""+trx_endbut(recid)+"\" id=\""+trx_endbut(recid)+"\" ";
str = str + " class=\"recbutton\" value=\"Download\" />";
}
str = str + "<input type=\"hidden\" id=\"recid\" name=\"recid\" value=\""+recid+"\" />";
str = str + "<input type=\"text\" id=\""+rs_trxname(recid)+"\" name=\""+rs_trxname(recid)+"\" />";
str = str + "<input type=\"text\" id=\""+rs_inputstart(recid)+"\" name=\""+rs_inputstart(recid)+"\" />";
@ -69,11 +69,11 @@ function newformstr ( recid , butflag=false )
str = str + "<input type=\"text\" id=\"endtime\" name=\"endtime\" /> ";
*/
str = str + "</form>";
return str;
}
/**
/**
* GetActive Recs
**/
@ -81,46 +81,46 @@ function rec_active( recid ) {
dataString = "";
var request = RecAjax("search", dataString);
request.done( function(data) {
request.done( function(data) {
$.each(data, function(key, val) {
console.log("Key " + key + " > VAL " + val );
$("#"+trx_logarea( recid )).append( "Key " + key + " > VAL " + val + "<br>" );
});
console.log("Req OK: "+ data);
console.log("Req OK: "+ data);
// console.log("request"+ req);
ChangeState(recid, trx_downbut(recid) , trx_endbut(recid));
});
}
/**
* New record
/**
* New record
**/
function rec_new( )
function rec_new( )
{
var myDate = new Date()
console.log("New ID "+ myDate.getTime());
console.log("New ID "+ myDate.getTime());
var recid = "rec-"+ myDate.getTime();
console.log("[rec_new] New Rec " + recid);
$("#buttonscontainer").append( "<div id=\""+rs_trxarea(recid)+"\" class=\"recarea\"> </div>" );
$("#"+rs_trxarea(recid)).append( "<div id=\""+rs_buttonarea(recid)+"\" class=\"buttonarea\"> </div>" );
console.log("[rec_new"+recid+"] add div (TRXArea, ButtonArea) ok " );
var formid = rs_formid( recid );
var str = newformstr(recid, butflag=true);
var str = newformstr(recid, butflag=true);
$("#"+rs_buttonarea(recid)).append( str );
$("#"+trx_stopbut(recid)).hide();
$("#"+trx_downbut(recid)).hide();
$("#"+trx_endbut(recid)).hide();
console.log("[rec_new "+recid+"] Form OK");
$("#"+rs_buttonarea(recid)).append( "<div class=\"dellinkarea\" > <a href=\"#\" id="+rs_dellink(recid)+"> cancella</a> </div>" );
// INSERT AND POPULATE BUTTON AREA
@ -130,53 +130,53 @@ function rec_new( )
$("#"+rs_dellink(recid)).click(function(){
console.log("Remove " + rs_trxarea(recid) + "[ID"+recid+"]");
// $("#"+rs_trxarea(recid)).remove();
recDelete (recid,rs_trxarea(recid));
recDelete (recid,rs_trxarea(recid));
});
// FORM SUBMIT: THE REC IS STOPPEND AND MUST BE PROCESSED
$("#"+formid).submit(function(event){
// Immediately, mark the end time (stop action)
ChangeState(recid, trx_downbut(recid) , trx_endbut(recid));
ChangeState(recid, trx_downbut(recid) , trx_endbut(recid));
// Force a Name
while (true) {
if ( $("#"+rs_trxname(recid)).val() == "" )
if ( $("#"+rs_trxname(recid)).val() == "" )
{
var tmpname = prompt("Nessun nome di trasmissione!!!");
$("#"+rs_trxname(recid)).val(tmpname);
$("#"+trx_logarea(recid)).append("Titolo: <b>"+ tmpname +"</b> <br/>");
}
else { break; }
else { break; }
}
event.preventDefault();
event.preventDefault();
// Update data (send to server) in order to save some information
recUpdate(recid);
recStart(recid);
recUpdate(recid);
recStart(recid);
}); // End of form SUBMIT
// Bind the STOP button
$("#"+trx_stopbut(recid)).click( function(event){
event.preventDefault();
ChangeState(recid, trx_stopbut(recid) , trx_downbut(recid));
$("#"+trx_stopbut(recid)).click( function(event){
event.preventDefault();
ChangeState(recid, trx_stopbut(recid) , trx_downbut(recid));
recUpdate(recid);
}); // End of STOP button
// Bind the START button
$("#"+trx_startbut(recid)).click( function(event){
// Immediately, mark the start time (start action) and send it to Server
$("#"+trx_startbut(recid)).click( function(event){
// Immediately, mark the start time (start action) and send it to Server
ChangeState(recid, trx_startbut(recid) , trx_stopbut(recid));
event.preventDefault();
event.preventDefault();
recNew( recid );
}); // End of START button
console.log("New form has been built.");
}
@ -187,21 +187,21 @@ function recDelete ( recid, targetarea ) {
console.log("Del rec: "+dataString);
var req_del = RecAjax("delete", dataString);
req_del.done (function(data) {
$.each(data, function(del_key, del_val) {
console.log("K:V " + del_key +":"+del_val );
console.log("K:V " + del_key +":"+del_val );
if (del_key == "message") {
$("#"+targetarea).fadeOut( 200, function() { $(this).remove(); });
console.log("delete area "+rs_trxarea(key));
console.log("delete area "+rs_trxarea(key));
}
}
if (del_key == "error") {
alert("Impossibile cancellare elemento:\n" + del_val );
}
});
});
}
@ -212,10 +212,10 @@ function recNew ( recid ) {
var dataString = $("#"+formid).serialize();
console.log("New rec: "+dataString);
var request = RecAjax("create", dataString);
request.done( function(data) {
request.done( function(data) {
$.each(data, function(key, val) {
console.log("Received (K:V) ("+key+":"+val+")") ;
if (key == "msg") {
@ -236,13 +236,13 @@ function recUpdate( recid ) {
var formid = rs_formid( recid );
var dataString = $("#"+formid).serialize();
console.log("Sending Ajax Update request: "+ dataString);
//event.preventDefault();
var request = RecAjax("update", dataString );
request.done( function(data) {
request.done( function(data) {
$.each(data, function(key, val) {
console.log("recUpdate receive (k:v) ("+key+":"+val+")" );
if (key == "message") {
var str = "";
str += "<b>RecID</b> "+ recid + "</br>"
@ -256,22 +256,22 @@ function recUpdate( recid ) {
$("#"+trx_logarea(recid)).append( "<b>In Elaborazione</b>" );
}
}
if (key == "error") {
$("#"+trx_logarea( recid )).append( "Error:" + val +"<br>" );
}
}); // end of each
}); // end of each
}); // end of request.done
}
/*
*
*
* AJAX REQUEST
*
*
*/
function RecAjax(apipath, dataString ) {
var srv = srvaddr + "/" + apipath ;
var srv = srvaddr + apipath ;
var request = $.ajax({
type: "POST",
@ -283,14 +283,14 @@ function RecAjax(apipath, dataString ) {
request.fail(function (jqXHR, textStatus, errorThrown){
console.error("The following error occured: "+ jqXHR.status +"-"+ textStatus + "-" + errorThrown );
if (jqXHR.status == 0 && jqXHR.readyState === 4)
if (jqXHR.status == 0 && jqXHR.readyState === 4)
{
alert("Errore di connessione, impossibile inviare i dati al server "+ srv);
} else {
alert("Error: "+jqXHR.status +"\nTextStatus: "+ textStatus + "\n Ready State "+jqXHR.readyState+"\n" + errorThrown );
}
});
return request;
}
@ -311,7 +311,7 @@ FUNCTION: CHANGE STATE (gui)
function ChangeState(recid, from, to) {
console.log("ChangeState: " + from + " --> " + to );
$("#"+from).css("display", "none");
$("#"+to).css("display", "inline");
@ -320,12 +320,12 @@ function ChangeState(recid, from, to) {
if ( from == trx_startbut(recid) ) {
$("#"+rs_inputstart(recid)).val( displayDate );
console.log("ChangeState: set "+rs_inputstart(recid)+ " to "+ displayDate )
}
if ( from == trx_stopbut(recid) ) {
$("#"+rs_inputend(recid)).val( displayDate );
$("#"+rs_inputend(recid)).val( displayDate );
console.log("ChangeState: set '"+rs_inputend(recid)+ "' to "+ displayDate )
}

View file

@ -8,7 +8,7 @@ $(document).ready(function(){
function (event) {
event.preventDefault();
dataString = $(this).serialize();
var request = RecAjax("search", dataString);
var request = $.getJSON('/search', dataString);
$("#searchresult").html(" ");
request.done( function(data) {

Binary file not shown.

View file

@ -4,7 +4,6 @@ import logging
import sys
import datetime
import json
import yaml
try:
from sqlalchemy import create_engine, Column, Integer, String, DateTime, Boolean
@ -16,23 +15,22 @@ except:
logging.basicConfig(level=logging.INFO)
STATE_ACTIVE = 0
STATE_RUN = 1
STATE_DOWN = 2
STATE_ACTIVE = 0
STATE_RUN = 1
STATE_DOWN = 2
PAGESIZE = 10
"""
This class describe a single Record (Rec() class) and the
records manager (RecDB() class)
This class describe a single Record (Rec() class) and the
records manager (RecDB() class)
"""
Base = declarative_base()
"""
Rec entry
"""
"""
class Rec(Base):
__tablename__ = 'rec'
id = Column(Integer, primary_key=True)
recid = Column(String)
@ -42,9 +40,9 @@ class Rec(Base):
active = Column(Boolean, default = True)
def __init__(self, recid="", name="", starttime=None, endtime=None, asjson=""):
self.error = 0
self.job = None
self.error = 0
self.job = None
if len(asjson) == 0:
self.name = name
self.starttime = starttime
@ -54,17 +52,17 @@ class Rec(Base):
#try:
# dec = json.loads( unicode(asjson) )
# dec = yaml.load( asjson )
dec = json.dumps( asjson )
dec = json.dumps( asjson )
# except:
# self.error = 0
print("dec %s %s" % (dec,type(dec)))
print("asjson %s %s" % (asjson,type(asjson)))
print("dec %s %s" % (dec,type(dec)))
print("asjson %s %s" % (asjson,type(asjson)))
self.recid = asjson[0]['recid']
self.name = asjson[0]['name']
self.name = asjson[0]['name']
self.starttime = asjson[0]['starttime']
self.endtime = asjson[0]['endtime']
self.state = STATE_ACTIVE
@ -72,17 +70,7 @@ class Rec(Base):
def start(self):
self.job = RecJob( self )
"""
def getvalues(self,val=None):
return { "id":self.id,
"recid":self.recid,
"name":self.name,
"starttime":self.starttime,
"endtime":self.endtime,
"active": self.active
}
"""
def err(self):
def err(self):
return self.error
def set_run(self):
@ -95,13 +83,13 @@ class Rec(Base):
return "<Rec(id:'%s',recid:'%s',name:'%s',Start: '%s',End: '%s',Active: '%s')>" \
% (self.id, self.recid, self.name, self.starttime, self.endtime, self.active)
""" ************
""" ************
RecDB
************ """
class RecDB:
def __init__(self):
self.engine = create_engine('sqlite:///techrec.db', echo=False)
self.conn = self.engine.connect()
@ -110,15 +98,15 @@ class RecDB:
logging.getLogger('sqlalchemy.dialects').setLevel(logging.FATAL)
logging.getLogger('sqlalchemy.pool').setLevel(logging.FATAL)
logging.getLogger('sqlalchemy.orm').setLevel(logging.FATAL)
Base.metadata.create_all(self.engine) # create Database
Session = sessionmaker(bind=self.engine)
self.session = Session()
self.session = Session()
self.err = ""
self.recordtimeformat = "%Y/%m/%d %H:%M:%S"
def add(self, simplerecord):
print self.session.add( simplerecord )
self.commit()
@ -126,8 +114,8 @@ class RecDB:
return ( simplerecord )
""""
UPDATE RECORD
""""
UPDATE RECORD
"""
def update(self, recid, rec):
@ -148,19 +136,19 @@ class RecDB:
logging.info("DB:: Update complete")
return True
""""
DELETE RECORD
""""
DELETE RECORD
"""
def delete(self,recid):
_rlist = self._search(recid=recid)
if len(_rlist) == 0:
if len(_rlist) == 0:
logging.info("DB: Delete: no record found!")
self.err = "No rec found"
return False
if len(_rlist) > 1:
if len(_rlist) > 1:
logging.info("DB: Delete: multilpe records found!")
self.err = "multiple ID Found %s" % (_rlist)
return False
@ -169,58 +157,58 @@ class RecDB:
logging.info("DB: Delete: delete complete")
self.commit()
return True
def commit(self):
logging.info("DB: Commit!!")
self.session.commit()
def get_all(self, page=0, page_size=PAGESIZE):
return self._search(page=page, page_size=page_size)
def _search(self, _id=None, name=None, recid=None, starttime=None, endtime=None, active=None, page=0, page_size=PAGESIZE):
logging.info("DB: Search => id:%s recid:%s name:%s starttime:%s endtime=%s active=%s" % (_id,recid,name,starttime,endtime,active))
query = self.session.query(Rec)
if not _id == None: query = query.filter_by(id=_id)
if not recid == None: query = query.filter_by(recid=recid)
if not name == None: query = query.filter(Rec.name.like("%"+name+"%"))
try:
if not starttime == None:
if not starttime == None:
_st = datetime.datetime.strptime(starttime, self.recordtimeformat)
query = query.filter(Rec.starttime > _st )
except:
logging.info("DB: search : no valid starttime")
logging.info("DB: search : no valid starttime")
try:
if not endtime == None:
if not endtime == None:
_et = datetime.datetime.strptime(endtime, self.recordtimeformat)
query = query.filter(Rec.endtime < _et )
except ValueError:
logging.info("DB: search : no valid endtime")
logging.info("DB: search : no valid endtime")
if not active == None: query = query.filter(Rec.active==active)
if page_size: query = query.limit(page_size)
if page: query = query.offset(page*page_size)
print query
ret = query.all()
# print "Sending: %s" % ret
return ret
def get_err(self):
def get_err(self):
print "DB error: %s" % (self.err)
t = self.err
self.err = ""
return t
"""def get_by_id(self,id):
try:
return self._search( _id=id )[0]
except:
return None
"""
"""
# Just for debug
def printall( queryres ):
for record in queryres: print "Record: %s" % record
@ -235,33 +223,24 @@ class RecJob():
self.name = rec.name
self.starttime = rec.starttime
self.endtime = rec.endtime
def extract(self):
if type(self.starttime) != type(datetime.datetime.now()):
logging.info("Starttime format error")
return
if type(self.endtime) != type(datetime.datetime.now()):
logging.info("Endtime format error")
return
if self.starttime >= self.endtime:
logging.info("Starttime > Endtime (%s > %s)" % (self.starttime,self.endtime) )
return
assert type(self.starttime) == type(datetime.datetime.now())
assert type(self.endtime) == type(datetime.datetime.now())
assert self.starttime < self.endtime
start = self.starttime
end = self.endtime
app = self.starttime
while True:
print
print "**** From file %s take:" % ( self._get_recfile(start) )
nexth = self._truncate(start) + datetime.timedelta(minutes=60)
if start > self._truncate(start):
print "FROM: %s for %s seconds" % (start - self._truncate(start), nexth - start )
if end < self._truncate(nexth):
print "FROM: %s for %s seconds" % (0, end - self._truncate(start) )
else:
@ -271,36 +250,36 @@ class RecJob():
print "Start ", start, " end: ", end
break;
start = nexth
def _truncate(self, mytime):
return datetime.datetime(mytime.year,mytime.month,mytime.day,mytime.hour)
def _get_recfile(self, mytime):
return "%s/%s" % (self.fdir,mytime.strftime(self.fnameformat))
def __repr__(self):
return "%s: %s (%s) => %s (%s)" % ( self.name, self.starttime, type(self.starttime) ,self.endtime, type(self.endtime))
"""
TEST
"""
if __name__ == "__main__":
db = RecDB()
_mytime = datetime.datetime(2014,05,24,15,12,17)
_mytime = datetime.datetime(2014,05,23,15,12,17)
_endtime = datetime.datetime(2014,05,24,17,45,17)
a = Rec(name="Mimmo1", starttime=_mytime, endtime=_endtime)
j = RecJob( a )
# print (j)
# j.extract()
print (j)
j.extract()
printall( db._search() )
sys.exit("End test job")
# a = Rec(name="Mimmo1", starttime=_mytime, endtime=None)
print "Aggiunto", db.add( a )
printall( db.get_all(page_size=5,page=0) )
print "Mimmo "
printall( db._search(name="Mimmo1"))
print "Search"
@ -312,4 +291,4 @@ if __name__ == "__main__":
db.delete(4)
db.delete(1)
printall( db._search() )