1
from flask import Flask
2
from flask import request
3
from flask import render_template
4
from flask import make_response
5
import lxml.html
6
import pymongo
7
from bson import Code
8
import urllib2
9
import StringIO
10
from flask import g
11
from flask import redirect
12
from urllib import quote_plus
13
from urllib import unquote_plus
14
import conf
15
import sweetmaker
16
import oursql
17
import requests
18
from flask import jsonify
19
import json
20
from flask import url_for
21
22
app = Flask(__name__)
23
@app.before_request
24
def first():
25
    g.connection = pymongo.MongoClient('localhost',27017) #Create the object once and use it.
26
    g.db = g.connection[conf.MONGODB[0]]
27
28
# @app.after_request
29
# def set_secret(response):
30
#     response.set_cookie("key", conf.SWEET_SECRET_KEY[0])
31
32
33
@app.teardown_request
34
def close(exception):
35
    g.connection.disconnect()
36
37
38
@app.route('/')
39
def start_page() :
40
    d = {}
41
    d['foruri'] = request.args['foruri']
42
    myhandler1 = urllib2.Request(d['foruri'],headers={'User-Agent':"Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0)"}) #A fix to send user-agents, so that sites render properly.
43
    try:
44
        a = urllib2.urlopen(myhandler1)
45
        if a.geturl() != d['foruri']:
46
            return "There was a server redirect, please click on the <a href='http://y.a11y.in/web?foruri={0}'>link</a> to continue.".format(quote_plus(a.geturl()))
47
        else:
48
            page = a.read()
49
            a.close()
50
    except ValueError:
51
        return "The link is malformed, click <a href='http://y.a11y.in/web?foruri={0}&lang={1}&interactive=1'>here</a> to be redirected.".format(quote_plus(unquote_plus(d['foruri'].encode('utf-8'))),request.args['lang'])
52
    except urllib2.URLError:
53
        return render_template('error.html')
54
    try:
55
        page = unicode(page,'utf-8')  #Hack to fix improperly displayed chars on wikipedia.
56
    except UnicodeDecodeError:
57
        pass #Some pages may not need be utf-8'ed
58
    try:
59
        g.root = lxml.html.parse(StringIO.StringIO(page)).getroot()
60
    except ValueError:
61
        g.root = lxml.html.parse(d['foruri']).getroot() #Sometimes creators of the page lie about the encoding, thus leading to this execption. http://lxml.de/parsing.html#python-unicode-strings
62
    if request.args.has_key('lang') == False and request.args.has_key('blog') == False:
63
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
64
        for i in g.root.iterlinks():
65
            if i[1] == 'href' and i[0].tag != 'link':
66
                try:
67
                    i[0].attrib['href'] = 'http://{0}?foruri={1}'.format(conf.DEPLOYURL[0],quote_plus(i[0].attrib['href']))
68
                except KeyError:
69
                    i[0].attrib['href'] = '{0}?foruri={1}'.format(conf.DEPLOYURL[0],quote_plus(i[0].attrib['href'].encode('utf-8')))
70
        setScripts()
71
        g.root.body.set("onload","a11ypi.loadOverlay();")
72
        response = make_response()
73
        response.data = lxml.html.tostring(g.root)
74
        return response
75
76
    elif request.args.has_key('lang') == True and request.args.has_key('interactive') == True and request.args.has_key('blog') == False:
77
        setScripts()
78
        setSocialScript()
79
        g.root.body.set("onload","a11ypi.ren();a11ypi.tweet(); a11ypi.facebook(); a11ypi.loadOverlay();")
80
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
81
        response = make_response()
82
        response.data = lxml.html.tostring(g.root)
83
        return response
84
85
86
    elif request.args.has_key('lang') == True and request.args.has_key('blog') == False:
87
        script_jq_mini = g.root.makeelement('script')
88
        g.root.body.append(script_jq_mini)
89
        script_jq_mini.set("src", conf.JQUERYURL[0] + "/jquery.min.js")
90
        script_jq_mini.set("type", "text/javascript")
91
        d['lang'] = request.args['lang']
92
        script_test = g.root.makeelement('script')
93
        g.root.body.append(script_test)
94
        script_test.set("src", conf.APPURL[0] + "/alipi/ui.js")
95
        script_test.set("type", "text/javascript")
96
        g.root.body.set("onload","a11ypi.ren()");
97
        response = make_response()
98
        response.data = lxml.html.tostring(g.root)
99
        return response
100
101
102
    elif request.args.has_key('interactive') == True and request.args.has_key('blog') == True and request.args.has_key('lang') == True:
103
        setScripts()
104
        setSocialScript()
105
        g.root.body.set("onload","a11ypi.filter(); a11ypi.tweet(); a11ypi.facebook(); a11ypi.loadOverlay();");
106
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
107
        response = make_response()
108
        response.data = lxml.html.tostring(g.root)
109
        return response
110
111
    elif request.args.has_key('interactive') == False and request.args.has_key('blog') == True:
112
        setScripts()
113
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
114
        g.root.body.set('onload', 'a11ypi.loadOverlay();')
115
        response = make_response()
116
        response.data = lxml.html.tostring(g.root)
117
        return response
118
119
120
def setScripts():
121
    script_test = g.root.makeelement('script')
122
    # script_edit = g.root.makeelement('script')
123
    script_auth = g.root.makeelement('script')
124
    g.root.body.append(script_test)
125
    # g.root.body.append(script_edit)
126
    g.root.body.append(script_auth)
127
    script_test.set("src", conf.APPURL[0] + "/alipi/pack.min.js")
128
    script_test.set("type", "text/javascript")
129
    # script_edit.set("src", conf.APPURL[0] + "/alipi/wsgi/pageEditor.js")
130
    # script_edit.set("type","text/javascript")
131
    # script_config = g.root.makeelement('script')
132
    # g.root.body.append(script_config)
133
    # script_config.set("src", conf.APPURL[0] + "/alipi/config.js")
134
    # script_config.set("type", "text/javascript")
135
    script_auth.set("src", conf.SWEETURL[0] + "/authenticate")
136
    script_auth.set("type","text/javascript")
137
138
    # script_jq_mini = g.root.makeelement('script')
139
    # g.root.body.append(script_jq_mini)
140
    # script_jq_mini.set("src", conf.JQUERYURL[0] + "/jquery.min.js")
141
    # script_jq_mini.set("type", "text/javascript")
142
143
    style = g.root.makeelement('link')
144
    g.root.body.append(style)
145
    style.set("rel","stylesheet")
146
    style.set("type", "text/css")
147
    style.set("href", conf.APPURL[0] + "/alipi/pack.min.css")
148
149
    # script_jq_cust = g.root.makeelement('script')
150
    # g.root.body.append(script_jq_cust)
151
    # script_jq_cust.set("src", conf.JQUERYUI[0] + "/jquery-ui.min.js")
152
    # script_jq_cust.set("type", "text/javascript")
153
154
    # style_cust = g.root.makeelement('link')
155
    # style_cust.set("rel","stylesheet")
156
    # style_cust.set("type", "text/css")
157
    # style_cust.set("href", conf.JQUERYCSS[0] + "/jquery-ui.css")
158
    # g.root.body.append(style_cust)
159
160
def setSocialScript():
161
    info_button = g.root.makeelement('button')
162
    g.root.body.append(info_button)
163
    info_button.set("id", "info")
164
    info_button.set("class", "alipi")
165
    info_button.set("onClick", "a11ypi.showInfo(a11ypi.responseJSON);")
166
    info_button.text =  "Info"
167
    info_button.set("title", "Have a look at the information of each renarrated element")
168
169
    share_button = g.root.makeelement('button')
170
    g.root.body.append(share_button)
171
    share_button.set("id", "share")
172
    share_button.set("class", "alipi")
173
    share_button.set("onClick", "a11ypi.share();")
174
    share_button.text =  "Share"
175
    share_button.set("title", "Share your contribution in your social network")
176
177
    see_orig = g.root.makeelement('button')
178
    g.root.body.append(see_orig)
179
    see_orig.set("id", "orig-button")
180
    see_orig.set("class", "alipi")
181
    see_orig.set("onClick", "a11ypi.showOriginal();")
182
    see_orig.text = "Original Page"
183
    see_orig.set("title", "Go to Original link, the original page of this renarrated")
184
185
    tweetroot = g.root.makeelement("div")
186
    tweetroot.set("id", "tweet-root")
187
    tweetroot.set("class", "alipi")
188
    tweetroot.set("style", "display:none;padding:10px;")
189
    g.root.body.append(tweetroot)
190
191
    tweet = g.root.makeelement("a")
192
    tweet.set("id", "tweet")
193
    tweet.set("href", "https://twitter.com/share")
194
    tweet.set("class", "alipi twitter-share-button")
195
    tweet.set("data-via", "a11ypi")
196
    tweet.set("data-lang", "en")
197
    tweet.set("data-url", "http://y.a11y.in/web?foruri={0}&lang={1}&interactive=1".format(quote_plus(request.args['foruri']),(request.args['lang']).encode('unicode-escape')))
198
    tweet.textContent = "Tweet"
199
    tweetroot.append(tweet)
200
201
    fblike = g.root.makeelement("div")
202
    fblike.set("id", "fb-like")
203
    fblike.set("class", "alipi fb-like")
204
    fblike.set("style", "display:none;padding:10px;")
205
    fblike.set("data-href", "http://y.a11y.in/web?foruri={0}&lang={1}&interactive=1".format(quote_plus(request.args['foruri']),(request.args['lang']).encode('unicode-escape')))
206
    fblike.set("data-send", "true")
207
    fblike.set("data-layout", "button_count")
208
    fblike.set("data-width", "50")
209
    fblike.set("data-show-faces", "true")
210
    fblike.set("data-font", "arial")
211
    g.root.body.append(fblike)
212
213
    style = g.root.makeelement('link')
214
    g.root.body.append(style)
215
    style.set("rel","stylesheet")
216
    style.set("type", "text/css")
217
    style.set("href", "http://y.a11y.in/alipi/stylesheet.css")
218
219
220
@app.route('/directory')
221
def show_directory():
222
    collection = g.db['post']
223
    query = collection.group(
224
        key = Code('function(doc){return {"about" : doc.about,"lang":doc.lang}}'),
225
        condition={"about":{'$regex':'^[/\S/]'}},
226
        initial={'na': []},
227
        reduce=Code('function(doc,out){out.na.push(doc.blog)}')
228
        )
229
    query.reverse()
230
    return render_template('directory.html', name=query, mymodule = quote_plus, myset=set, mylist= list)
231
232
@app.route('/getLoc', methods=['GET'])
233
def get_loc():
234
235
    term = request.args['term']
236
    connection = oursql.Connection(conf.DBHOST[0],conf.DBUSRNAME[0],conf.DBPASSWD[0],db=conf.DBNAME[0])
237
    cursor = connection.cursor(oursql.DictCursor)
238
    cursor.execute('select l.name, c.country_name from `location` as l, `codes` as c where l.name like ? and l.code=c.code limit ?', (term+'%', 5))
239
    r = cursor.fetchall()
240
    connection.close()
241
    d = {}
242
    d['return'] = r
243
    response = jsonify(d)
244
    response.headers['Access-Control-Allow-Origin'] = '*'
245
    return response
246
@app.route('/getLang', methods=['GET'])
247
def get_lang():
248
    term = request.args['term']
249
    connection = oursql.Connection(conf.DBHOST[0],conf.DBUSRNAME[0],conf.DBPASSWD[0],db=conf.DBNAME[0])
250
    cursor = connection.cursor(oursql.DictCursor)
251
    cursor.execute('select * from `languages` as l  where l.name like ? limit ?', (term+'%',5))
252
    r = cursor.fetchall()
253
    connection.close()
254
    d = {}
255
    d['return'] = r
256
    response = jsonify(d)
257
    response.headers['Access-Control-Allow-Origin'] = '*'
258
    return response
259
260
@app.route('/blank', methods=['GET'])
261
def serve_blank():
262
    return render_template('blank.html')
263
264
@app.route('/info', methods=['GET'])
265
def serve_info():
266
    coll = g.db['post']
267
    d = {}
268
    cntr = 0
269
    for i in coll.find({"about":unquote_plus(request.args['about']),"lang":request.args['lang']}):
270
        i['_id'] = str(i['_id'])
271
        d[cntr] = i
272
        cntr+=1
273
    response = jsonify(d)
274
    response.headers['Access-Control-Allow-Origin'] = '*'
275
    return response
276
277
278
@app.route("/replace", methods=['GET'])
279
def replace():
280
    collection = g.db['post']
281
    lang = request.args['lang']
282
    url = request.args['url']
283
    query = collection.group(
284
        key = Code('function(doc){return {"xpath" : doc.xpath, "about": doc.url}}'),
285
        condition={"about" : url, "lang" : lang,"elementtype":"text"},
286
        initial={'narration': []},
287
        reduce=Code('function(doc,out){out.narration.push(doc);}')
288
        )
289
290
    print query
291
292
    audio_query =collection.group(
293
        key = Code('function(doc){return {"xpath" : doc.xpath, "about": doc.url}}'),
294
        condition={"about" : url, "lang" : lang, 'elementtype':"audio/ogg"},
295
        initial={'narration': []},
296
        reduce=Code('function(doc,out){out.narration.push(doc);}')
297
        )
298
299
    image_query =collection.group(
300
        key = Code('function(doc){return {"xpath" : doc.xpath, "about": doc.url}}'),
301
        condition={"about" : url, "lang" : lang, 'elementtype':"image"},
302
        initial={'narration': []},
303
        reduce=Code('function(doc,out){out.narration.push(doc);}')
304
        )
305
    try:
306
        for i in audio_query:
307
            query.append(i)
308
    except IndexError:
309
        pass
310
    try:
311
        for i in image_query:
312
            query.append(i)
313
    except IndexError:
314
        pass
315
316
    for i in query:
317
        for y in i['narration']:
318
            del(y['_id'])
319
    d = {}
320
    d['r'] = query
321
    response = jsonify(d)
322
    response.headers['Access-Control-Allow-Origin'] = '*'
323
    return response
324
325
@app.route('/feeds', methods=['GET'])
326
def serve_feed_temp():
327
    return render_template("feeds.html")
328
329
@app.route('/feed', methods=['GET'])
330
def serve_feed():
331
    coll = g.db['post']
332
    d = {}
333
    cntr = 0
334
    for i in coll.find().sort('_id',direction=-1):
335
        if i['data'] != '<br/>':
336
            i['_id'] = str(i['_id'])
337
            d[cntr] = i
338
            cntr+=1
339
    response = jsonify(d)
340
    response.headers['Access-Control-Allow-Origin'] = '*'
341
    return response
342
343
@app.route('/about', methods=['GET'])
344
def serve_authors():
345
    coll = g.db['post']
346
    d = {}
347
    cntr = 0
348
    for i in coll.find({"about":unquote_plus(request.args['about'])}):
349
        i['_id'] = str(i['_id'])
350
        d[cntr] = i
351
        cntr+=1
352
    response = jsonify(d)
353
    response.headers['Access-Control-Allow-Origin'] = '*'
354
    return response
355
#Retrieve all information about a specific $about and a given $author.
356
@app.route('/author', methods=['GET'])
357
def serve_author():
358
    coll = g.db['post']
359
    d = {}
360
    cntr = 0
361
    for i in coll.find({"about":unquote_plus(request.args['about']),"author":unquote_plus(request.args['author'])}):
362
        i['_id'] = str(i['_id'])
363
        d[cntr] = i
364
        cntr += 1
365
    response = jsonify(d)
366
    response.headers['Access-Control-Allow-Origin'] = '*'
367
    return response
368
369
@app.route('/getAllLang', methods=['GET'])
370
def get_all_lang():
371
    term = request.args['term']
372
    connection = oursql.Connection(conf.DBHOST[0],conf.DBUSRNAME[0],conf.DBPASSWD[0],db=conf.DBNAME[0])
373
    cursor = connection.cursor(oursql.DictCursor)
374
    cursor.execute('select * from `languages` as l  where l.name like ?', (term+'%',))
375
    r = cursor.fetchall()
376
    connection.close()
377
    d = {}
378
    d['return'] = r
379
    response = jsonify(d)
380
    response.headers['Access-Control-Allow-Origin'] = '*'
381
    return response
382
383
384
@app.route('/publish', methods=['POST'])
385
def publish():
386
    data = json.loads(request.form['data'])
387
    collection = g.db['post']
388
    page = {}
389
    if type(data) is unicode: #A hack to fix malformed data. FIXME.
390
        data = json.loads(data)
391
    content = []
392
    for i in data: #Create content objects here for posting to blog.  DELETEME.
393
        if 'comments' in i:
394
            page['comments'] = i['comments']
395
        else:
396
            contentobj = {}
397
            contentobj['type'] = i['elementtype']
398
            contentobj['attr'] = {"language":i['lang'], "location":i['location'], "about":i['about'], "xpath":i['xpath']}
399
            contentobj['data'] = i['data']
400
            content.append(contentobj)
401
            i['bxpath'] = ''
402
            collection.insert(i)
403
404
    page['title'] = "Re-narration of " + content[0]['attr']['about']
405
    page['name'] = "About " + content[0]['attr']['about']
406
    page['content'] = content
407
408
    g.response_from_blogger = requests.api.post(conf.CUSTOM_BLOG_POST_URL[0], json.dumps(page), headers={"content-type":"application/json"})
409
    print "response from blogger " + repr(g.response_from_blogger)
410
    sweet(data)
411
    reply = make_response()
412
    return reply
413
414
415
def sweet(data):
416
    """ A function to sweet the data that is inserted.  Accepts a <list of dicts>. """
417
    for i in data:
418
        if 'type' in i:
419
            del(i['_id'])
420
            sweetmaker.sweet(conf.SWEET_STORE_ADD[0], [{"what":i['type'], "who":i['author'], "where":i['about']+i['xpath'], "how":conf.CUSTOM_BLOG_URL[0]+"/#"+g.response_from_blogger.json()['name']+' {lang: '+i["lang"]+',loc: '+i["location"]+'}'}])
421
    return True
422
        # data = json.dumps(data)
423
    # req = requests.api.post(conf.SWEETURL[0]+"/add",{'data':data})
424
    # if req.status_code == 200:
425
    #     reply = make_response()
426
    #     return reply
427
428
429
@app.route("/askSWeeT", methods=['POST'])
430
def askSweet():
431
    data = json.loads(request.form['data'])
432
    for i in data:
433
        response = requests.api.get(conf.SWEETURL[0]+"/query/"+i['id'])
434
        collection = g.db['post']
435
        rep = response.json()
436
        rep['bxpath'] = ''
437
        if response.status_code == 200:
438
            collection.insert(rep)
439
    reply = make_response()
440
    return reply
441
442
@app.route("/menu",methods=['GET'])
443
def menuForDialog():
444
    if request.args.has_key('option') == False:
445
        collection = g.db['post']
446
        c = {}
447
        cntr = 0
448
        print request.args['url']
449
        for i in collection.find({"about":request.args['url']}).distinct('lang'):
450
            for j in collection.find({"about":request.args['url'],'lang':i}).distinct('type'):
451
                d = {}
452
                d['lang'] = i
453
                d['type'] = j
454
                c[cntr] = d
455
                cntr += 1
456
        print c
457
        return jsonify(c)
458
    else:
459
        collection = g.db['post']
460
        #get the ren languages for the received url
461
        langForUrl = collection.group(
462
            key = Code('function(doc){return {"about" : doc.about}}'),
463
            condition={"about" : d['url'],"blog":{'$regex':'/'+d['option']+'.*/'}},
464
            initial={'lang': []},
465
            reduce=Code('function(doc, out){if (out.lang.indexOf(doc.lang) == -1) out.lang.push(doc.lang)}') #here xpath for test
466
            )
467
468
        #send the response
469
        if (langForUrl):
470
            connection.disconnect()
471
            return json.dumps(langForUrl[0]['lang'])
472
        else:
473
            connection.disconnect()
474
            return "empty"
475
476
477
@app.route("/domain")
478
def serve_domain_info():
479
    collection = g.db['post']
480
    url = request.args['url']
481
    #all re-narrations of the same xpath are grouped
482
    query = collection.group(
483
        key = None,
484
        condition={"about" :{'$regex':url+'*'}},
485
        initial={'narration': []},
486
        reduce=Code('function(doc,out){out.narration.push(doc["about"]);}')
487
    )
488
489
    string=''
490
    if len(query)==0:
491
        return jsonify({'0':'empty'})
492
    else:
493
        otherlist = {}
494
        cntr = -1
495
        mylist = query[0]['narration']
496
        for i in mylist:
497
            if i in otherlist:
498
                pass
499
            else:
500
                cntr += 1
501
                otherlist[cntr] = str(i)
502
                return jsonify(otherlist)
503
504
505
import logging,os
506
from logging import FileHandler
507
508
fil = FileHandler(os.path.join(os.path.dirname(__file__),'logme'),mode='a')
509
fil.setLevel(logging.ERROR)
510
app.logger.addHandler(fil)
511
512
if __name__ == '__main__':
513
    app.run(debug=True, host='0.0.0.0')