./0000755000076500007650000000000010752415776015741 5ustar00massimodipierromassimodipierro00000000000000ABOUT0000644000076500007650000000130510752420504016361 0ustar00massimodipierromassimodipierro00000000000000This app shows how to user xmlrpc to update a local database from a remote database. Example of usage: 1) install it under two different names: app "peer_one" and app "peer_two" 2) check the database administrative interface. It contains one record 3) visit 4) check the database administrative interface. It contains two copies of the same record. The second copy was fetched from peer_two using xmlrpc. 5) create your own database tables. Edit default.py and xmlrpc.py to use your table (instead of table user) 6) add some try...except in client (grab) to deal with possible errors. Developed with web2py.LICENSE0000644000076500007650000000020710745732752016606 0ustar00massimodipierromassimodipierro00000000000000This is a sample license. You can write here anything you want as long as you do not violate web2py copyright, trademark and license. __init__.py0000644000076500007650000000000010745732752017701 0ustar00massimodipierromassimodipierro00000000000000cache/0000755000076500007650000000000010753772173016645 5ustar00massimodipierromassimodipierro00000000000000cache/cache.lock0000644000076500007650000000000010753772173020550 0ustar00massimodipierromassimodipierro00000000000000controllers/0000755000076500007650000000000010752520627020142 5ustar00massimodipierromassimodipierro00000000000000controllers/appadmin.py0000644000076500007650000001263510751740462022314 0ustar00massimodipierromassimodipierro00000000000000########################################################### ### make sure administrator is on localhost ############################################################ import os, socket import gluon.contenttype import gluon.fileutils http_host = request.env.http_host.split(':')[0] remote_addr = request.env.remote_addr if remote_addr not in (http_host, socket.gethostbyname(remote_addr)): raise HTTP(400) if not gluon.fileutils.check_credentials(request): redirect('/admin') response.view='appadmin.html' response.menu=[['design',False,'/admin/default/design/%s' % request.application], ['db',False,'/%s/%s/index' % (request.application, request.controller)], ['state',False,'/%s/%s/state' % (request.application, request.controller)]] ########################################################### ### list all tables in database ############################################################ def index(): import types as _types _dbs={} for _key,_value in globals().items(): if isinstance(_value,SQLDB): tables=_dbs[_key]=[] for _tablename in _value.tables: tables.append((_key,_tablename)) return dict(dbs=_dbs) ########################################################### ### insert a new record ############################################################ def insert(): try: dbname=request.args[0] db=eval(dbname) table=request.args[1] form=SQLFORM(db[table]) except: redirect(URL(r=request,f='index')) if form.accepts(request.vars,session): response.flash='new record inserted' return dict(form=form) ########################################################### ### list all records in table and insert new record ############################################################ def download(): import os, gluon.contenttype filename=request.args[0] response.headers['Content-Type']=gluon.contenttype.contenttype(filename) return open(os.path.join(request.folder,'uploads/','%s' % filename),'rb').read() def csv(): import gluon.contenttype, csv, cStringIO response.headers['Content-Type']=gluon.contenttype.contenttype('.csv') try: dbname=request.vars.dbname db=eval(dbname) records=db(request.vars.query).select() except: redirect(URL(r=request,f='index')) s=cStringIO.StringIO() writer = csv.writer(s) writer.writerow(records.colnames) c=range(len(records.colnames)) for i in range(len(records)): writer.writerow([records.response[i][j] for j in c]) ### FILL HERE return s.getvalue() def import_csv(table,file): import csv reader = csv.reader(file) colnames=None for line in reader: if not colnames: colnames=[x[x.find('.')+1:] for x in line] c=[i for i in range(len(line)) if colnames[i]!='id'] else: items=[(colnames[i],line[i]) for i in c] table.insert(**dict(items)) def select(): try: dbname=request.args[0] db=eval(dbname) if not request.vars.query: table=request.args[1] query='%s.id>0' % table else: query=request.vars.query except: redirect(URL(r=request,f='index')) if request.vars.csvfile!=None: try: import_csv(db[table],request.vars.csvfile.file) response.flash='data uploaded' except: response.flash='unable to parse csv file' if request.vars.delete_all and request.vars.delete_all_sure=='yes': try: db(query).delete() response.flash='records deleted' except: response.flash='invalid SQL FILTER' elif request.vars.update_string: try: env=dict(db=db,query=query) exec('db(query).update('+request.vars.update_string+')') in env response.flash='records updated' except: response.flash='invalid SQL FILTER or UPDATE STRING' if request.vars.start: start=int(request.vars.start) else: start=0 limitby=(start,start+100) try: records=db(query).select(limitby=limitby) except: response.flash='invalid SQL FILTER' return dict(records='no records',nrecords=0,query=query,start=0) linkto=URL(r=request,f='update/%s'% (dbname)) upload=URL(r=request,f='download') return dict(start=start,query=query,\ nrecords=len(records),\ records=SQLTABLE(records,linkto,upload,_class='sortable')) ########################################################### ### edit delete one record ############################################################ def update(): try: dbname=request.args[0] db=eval(dbname) table=request.args[1] except: redirect(URL(r=request,f='index')) try: id=int(request.args[2]) record=db(db[table].id==id).select()[0] except: redirect(URL(r=request,f='select/%s/%s'%(dbname,table))) form=SQLFORM(db[table],record,deletable=True, linkto=URL(r=request,f='select/'+dbname), upload=URL(r=request,f='download/')) if form.accepts(request.vars,session): response.flash='done!' redirect(URL(r=request,f='select/%s/%s'%(dbname,table))) return dict(form=form) ########################################################### ### get global variables ############################################################ def state(): return dict(state=request.env) controllers/default.py0000644000076500007650000000074610753772444022156 0ustar00massimodipierromassimodipierro00000000000000def index(): redirect(URL(r=request,f='grab')) def grab(): import xmlrpclib client = xmlrpclib.ServerProxy('http://localhost:8000'+URL(r=request,c='xmlrpc',f='handle')) columns,rows=client.search('user.id>0') j=len('user.') for row in rows: items=dict([(columns[i][j:],row[i]) for i in range(len(columns)) if columns[i][-3:]!='id']) db.user.insert(**items) response.flash='records inserted' return dict(records=db(db.user.id>0).select())controllers/xmlrpc.py0000644000076500007650000000021610753772166022030 0ustar00massimodipierromassimodipierro00000000000000def search(query): rows=db(query).select() return rows.colnames, rows.response def handle(): return response.xmlrpc(request,[search])databases/0000755000076500007650000000000010753772466017536 5ustar00massimodipierromassimodipierro00000000000000databases/db.db0000644000076500007650000000600010753772466020426 0ustar00massimodipierromassimodipierro00000000000000SQLite format 3@  <<P++Ytablesqlite_sequencesqlite_sequenceCREATE TABLE sqlite_sequence(name,seq)pCtableuseruserCREATE TABLE user( id INTEGER PRIMARY KEY AUTOINCREMENT, name CHAR(32), phone CHAR(32) ) RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRMarco60283765Claudia234059862n!Massimo8497649764WMarco60283765DClaudia234059862.!Massimo8497649764Marco60283765Claudia234059862!Massimo8497649764Marco60283765Claudia234059862!Massimo8497649764Marco60283765Claudia234059862n!Massimo8497649764W!Massimo8497649764@Marco60283765-Claudia234059862!Massimo8497649764Marco60283765Claudia234059862!Massimo8497649764Marco60283765Claudia234059862!Massimo8497649764Marco60283765mClaudia234059862W!Massimo8497649764@Marco60283765-Claudia234059862!Massimo8497649764!Massimo8497649764 user.databases/f6db3e6e66dc0b6aea6b47a87ef29c1f_user.table0000644000076500007650000000015710752416505026545 0ustar00massimodipierromassimodipierro00000000000000(dp1 S'phone' p2 S'CHAR(32)' p3 sS'id' p4 S'INTEGER PRIMARY KEY AUTOINCREMENT' p5 sS'name' p6 S'CHAR(32)' p7 s.databases/sql.log0000644000076500007650000000021410752416505021021 0ustar00massimodipierromassimodipierro00000000000000timestamp: 2008-02-06T14:49:09.062363 CREATE TABLE user( id INTEGER PRIMARY KEY AUTOINCREMENT, name CHAR(32), phone CHAR(32) ); success! errors/0000755000076500007650000000000010753772176017121 5ustar00massimodipierromassimodipierro00000000000000errors/127.0.0.1.1202713726.04497671738330000644000076500007650000000251110753772176022420 0ustar00massimodipierromassimodipierro00000000000000(dp1 S'output' p2 S'' sS'layer' p3 S'applications/p2p/controllers/default.py' p4 sS'code' p5 S"def index():\n response.flash=T('Welcome to web2py')\n return dict(message=T('Hello World'))\n \n\ndef grab():\n import xmlrpclib\n client = xmlrpclib.ServerProxy(request.vars.url)\n \n columns,rows=client.search('user.id>0')\n j=len('user.')\n for row in rows:\n items=dict([(columns[i][j:],row[i]) for i in range(len(columns)) if columns[i][-3:]!='id'])\n db.user.insert(**items)\n response.flash='records inserted'\n return dict(records=db(db.user.id>0).select())\n\nresponse._vars=grab()" p6 sS'traceback' p7 S'Traceback (most recent call last):\n File "/Users/massimodipierro/Current/Python Programs/web2py/gluon/restricted.py", line 61, in restricted\n exec ccode in environment\n File "applications/p2p/controllers/default.py", line 18, in \n File "applications/p2p/controllers/default.py", line 8, in grab\n client = xmlrpclib.ServerProxy(request.vars.url)\n File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xmlrpclib.py", line 1409, in __init__\n type, uri = urllib.splittype(uri)\n File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/urllib.py", line 1023, in splittype\n match = _typeprog.match(url)\nTypeError: expected string or buffer\n' p8 s.languages/0000755000076500007650000000000010752415776017552 5ustar00massimodipierromassimodipierro00000000000000languages/it..py0000644000076500007650000000005610745777321020616 0ustar00massimodipierromassimodipierro00000000000000{ 'Hello World':'', 'Welcome to web2py':'', } languages/it.py0000644000076500007650000000010710745777321020535 0ustar00massimodipierromassimodipierro00000000000000{ 'Hello World':'Salve Mondo', 'Welcome to web2py':'Ciao da wek2py', } models/0000755000076500007650000000000010752416311017051 5ustar00massimodipierromassimodipierro00000000000000models/db.py0000644000076500007650000000016310752416342020014 0ustar00massimodipierromassimodipierro00000000000000# try something like db=SQLDB("sqlite://db.db") db.define_table('user', SQLField('name'), SQLField('phone'))modules/0000755000076500007650000000000010752415776017254 5ustar00massimodipierromassimodipierro00000000000000modules/__init__.py0000644000076500007650000000000010745732752021351 0ustar00massimodipierromassimodipierro00000000000000private/0000755000076500007650000000000010752415776017256 5ustar00massimodipierromassimodipierro00000000000000sessions/0000755000076500007650000000000010753772173017450 5ustar00massimodipierromassimodipierro00000000000000sessions/127.0.0.1.1202713723.5306011143320000644000076500007650000000000310753772473022620 0ustar00massimodipierromassimodipierro00000000000000(d.static/0000755000076500007650000000000010752415776017073 5ustar00massimodipierromassimodipierro00000000000000static/sorttable.js0000644000076500007650000004102510745732752021430 0ustar00massimodipierromassimodipierro00000000000000/* SortTable version 2 7th April 2007 Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ Instructions: Download this file Add to your HTML Add class="sortable" to any table you'd like to make sortable Click on the headers to sort Thanks to many, many people for contributions and suggestions. Licenced as X11: http://www.kryogenix.org/code/browser/licence.html This basically means: do what you want with it. */ var stIsIE = /*@cc_on!@*/false; sorttable = { init: function() { // quit if this function has already been called if (arguments.callee.done) return; // flag this function so we don't do the same thing twice arguments.callee.done = true; // kill the timer if (_timer) clearInterval(_timer); if (!document.createElement || !document.getElementsByTagName) return; sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; forEach(document.getElementsByTagName('table'), function(table) { if (table.className.search(/\bsortable\b/) != -1) { sorttable.makeSortable(table); } }); }, makeSortable: function(table) { if (table.getElementsByTagName('thead').length == 0) { // table doesn't have a tHead. Since it should have, create one and // put the first table row in it. the = document.createElement('thead'); the.appendChild(table.rows[0]); table.insertBefore(the,table.firstChild); } // Safari doesn't support table.tHead, sigh if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; if (table.tHead.rows.length != 1) return; // can't cope with two header rows // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as // "total" rows, for example). This is B&R, since what you're supposed // to do is put them in a tfoot. So, if there are sortbottom rows, // for backwards compatibility, move them to tfoot (creating it if needed). sortbottomrows = []; for (var i=0; i5' : ' ▴'; this.appendChild(sortrevind); return; } if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { // if we're already sorted by this column in reverse, just // re-reverse the table, which is quicker sorttable.reverse(this.sorttable_tbody); this.className = this.className.replace('sorttable_sorted_reverse', 'sorttable_sorted'); this.removeChild(document.getElementById('sorttable_sortrevind')); sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; this.appendChild(sortfwdind); return; } // remove sorttable_sorted classes theadrow = this.parentNode; forEach(theadrow.childNodes, function(cell) { if (cell.nodeType == 1) { // an element cell.className = cell.className.replace('sorttable_sorted_reverse',''); cell.className = cell.className.replace('sorttable_sorted',''); } }); sortfwdind = document.getElementById('sorttable_sortfwdind'); if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } sortrevind = document.getElementById('sorttable_sortrevind'); if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } this.className += ' sorttable_sorted'; sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; this.appendChild(sortfwdind); // build an array to sort. This is a Schwartzian transform thing, // i.e., we "decorate" each row with the actual sort key, // sort based on the sort keys, and then put the rows back in order // which is a lot faster because you only do getInnerText once per row row_array = []; col = this.sorttable_columnindex; rows = this.sorttable_tbody.rows; for (var j=0; j 12) { // definitely dd/mm return sorttable.sort_ddmm; } else if (second > 12) { return sorttable.sort_mmdd; } else { // looks like a date, but we can't tell which, so assume // that it's dd/mm (English imperialism!) and keep looking sortfn = sorttable.sort_ddmm; } } } } return sortfn; }, getInnerText: function(node) { // gets the text we want to use for sorting for a cell. // strips leading and trailing whitespace. // this is *not* a generic getInnerText function; it's special to sorttable. // for example, you can override the cell text with a customkey attribute. // it also gets .value for fields. hasInputs = (typeof node.getElementsByTagName == 'function') && node.getElementsByTagName('input').length; if (node.getAttribute("sorttable_customkey") != null) { return node.getAttribute("sorttable_customkey"); } else if (typeof node.textContent != 'undefined' && !hasInputs) { return node.textContent.replace(/^\s+|\s+$/g, ''); } else if (typeof node.innerText != 'undefined' && !hasInputs) { return node.innerText.replace(/^\s+|\s+$/g, ''); } else if (typeof node.text != 'undefined' && !hasInputs) { return node.text.replace(/^\s+|\s+$/g, ''); } else { switch (node.nodeType) { case 3: if (node.nodeName.toLowerCase() == 'input') { return node.value.replace(/^\s+|\s+$/g, ''); } case 4: return node.nodeValue.replace(/^\s+|\s+$/g, ''); break; case 1: case 11: var innerText = ''; for (var i = 0; i < node.childNodes.length; i++) { innerText += sorttable.getInnerText(node.childNodes[i]); } return innerText.replace(/^\s+|\s+$/g, ''); break; default: return ''; } } }, reverse: function(tbody) { // reverse the rows in a tbody newrows = []; for (var i=0; i=0; i--) { tbody.appendChild(newrows[i]); } delete newrows; }, /* sort functions each sort function takes two parameters, a and b you are comparing a[0] and b[0] */ sort_numeric: function(a,b) { aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); if (isNaN(aa)) aa = 0; bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); if (isNaN(bb)) bb = 0; return aa-bb; }, sort_alpha: function(a,b) { if (a[0]==b[0]) return 0; if (a[0] 0 ) { var q = list[i]; list[i] = list[i+1]; list[i+1] = q; swap = true; } } // for t--; if (!swap) break; for(var i = t; i > b; --i) { if ( comp_func(list[i], list[i-1]) < 0 ) { var q = list[i]; list[i] = list[i-1]; list[i-1] = q; swap = true; } } // for b++; } // while(swap) } } /* ****************************************************************** Supporting functions: bundled here to avoid depending on a library ****************************************************************** */ // Dean Edwards/Matthias Miller/John Resig /* for Mozilla/Opera9 */ if (document.addEventListener) { document.addEventListener("DOMContentLoaded", sorttable.init, false); } /* for Internet Explorer */ /*@cc_on @*/ /*@if (@_win32) document.write(" {{try:}}{{=uplink}}{{except:}}{{pass}}

{{if request.function=='state':}} Internal state {{else:}} {{if len(request.args)>=1:}} database {{=A(request.args[0],_href=URL(r=request,f='index/'))}} {{if not request.vars.query:}}table {{=A(request.args[1],_href=URL(r=request,f='select/%s/%s'% tuple(request.args[:2])))}} {{=request.function}} {{else:}} generic select/update/delete{{pass}} {{if len(request.args)==3:}} record id {{=A(request.args[2],_href=URL(r=request,f='update/%s/%s/%s'% tuple(request.args[:3])))}} {{pass}} {{else:}} Avalilable databases and tables {{pass}} {{pass}}

{{if request.function=='index':}} {{if len(dbs)==0:}}No databases in this application{{pass}} {{for dbname,items in dbs.items():}} {{for dt in items:}}

{{=A("%s.%s"%dt,_href=URL(r=request,f='select/%s/%s'%dt))}}

[ {{=A('insert new '+dt[1],_href=URL(r=request,f='insert/%s/%s'%dt))}} ]

{{pass}} {{pass}}

{{pass}} {{if request.function=='select' and len(request.args)>1:}} [ {{=A('insert new '+request.args[1],_href=URL(r=request,f='insert/%s/%s'%tuple(request.args[:2])))}} ]

Rows in table


{{elif request.function=='select' and len(request.args)==1:}}

Rows selected


{{pass}} {{if request.function=='select' and len(request.args)>=1:}}
{{if len(request.args)==1:}} {{pass}}
SQL FILTER:
UPDATE STRING: or DELETE ALL: (sure?)
(The SQL FILTER is a condition like "table1.field1='value'". Something like "table1.field1=table2.field2" results in a SQL JOIN. Use AND, OR and (...) to build more complex filters. The UPDATE STRING is an optional expression like "field1='newvalue'". You cannot update or delete the results of a JOIN)


{{if start>0:}}[ {{=A('previous 100 records',_href=URL(r=request,f='select/%s?query=%s&start=%s'%('/'.join(request.args),query,start-100)))}} ]{{pass}} {{if nrecords==100:}}[ {{=A('next 100 records',_href=URL(r=request,f='select/%s?query=%s&start=%s'%('/'.join(request.args),query,start+100)))}} ]{{pass}} {{=records}}

Import/Export


[ export as csv file ] {{if len(request.args)==2:}} {{=FORM('or import from csv file ',INPUT(_type='file',_name='csvfile'),INPUT(_type='submit',_value='import'))}} {{pass}} {{pass}} {{if request.function=='insert' and len(request.args)>1:}}

New Record


{{=form}} {{pass}} {{if request.function=='update' and len(request.args)>2:}}

Edit current record



{{=form}} {{pass}} {{if request.function=='state':}}

Current request

{{=BEAUTIFY(request)}}

Current response

{{=BEAUTIFY(response)}}

Current session

{{=BEAUTIFY(session)}} {{pass}}views/default/0000755000076500007650000000000010746001734020351 5ustar00massimodipierromassimodipierro00000000000000views/default/index.html0000644000076500007650000000041110745771646022361 0ustar00massimodipierromassimodipierro00000000000000{{extend 'layout.html'}}


{{try:}}{{=H1(message)}}{{except:}}{{=BEAUTIFY(response._vars)}}{{pass}}

[ click here for the administrative interface | click here for online examples ]
views/generic.html0000644000076500007650000000006610745732752021243 0ustar00massimodipierromassimodipierro00000000000000{{extend 'layout.html'}} {{=BEAUTIFY(response._vars)}}views/layout.html0000644000076500007650000001377110751740462021145 0ustar00massimodipierromassimodipierro00000000000000 {{if response.title:}}{{=response.title}}{{else:}}{{=URL(r=request)}}{{pass}} {{include 'web2py_ajax.html'}}
{{if response.flash:}}
{{=response.flash}}
{{pass}} {{include}}
views/web2py_ajax.html0000644000076500007650000000475310745732752022051 0ustar00massimodipierromassimodipierro00000000000000