1
#-*-coding: utf-8 -*-
2
from flask import Flask, request, render_template, g, redirect, jsonify, make_response
3
from bson import Code
4
from urllib import quote_plus, unquote_plus
5
from lxml.html import html5parser
6
import urllib2, StringIO, lxml.html, pymongo, conf, oursql
7
app = Flask(__name__)
8
@app.before_request
9
def first():
10
    g.connection = pymongo.Connection('localhost',27017) #Create the object once and use it.
11
    g.db = g.connection[conf.MONGODB[0]]
12
@app.teardown_request
13
def close(exception):
14
    g.connection.disconnect()
15
@app.route('/')
16
def start_page() :
17
    d = {}
18
    d['foruri'] = request.args['foruri']
19
    myhandler1 = urllib2.Request(d['foruri'],headers={'User-Agent':"Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11"}) #A fix to send user-agents, so that sites render properly.
20
    try:
21
        a = urllib2.urlopen(myhandler1)
22
        if a.geturl() != d['foruri']:
23
            return "There was a server redirect, please click on the <a href='http://dev.a11y.in/web?foruri={0}'>link</a> to continue.".format(quote_plus(a.geturl()))
24
        else:
25
            page = a.read()
26
            a.close()
27
    except ValueError:
28
        return "The link is malformed, click <a href='http://dev.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'])
29
    except urllib2.URLError:
30
        return render_template('error.html')
31
    try:
32
        page = unicode(page,'utf-8')  #Hack to fix improperly displayed chars on wikipedia.
33
    except UnicodeDecodeError:
34
        pass #Some pages may not need be utf-8'ed
35
    try:
36
        g.root = lxml.html.parse(StringIO.StringIO(page)).getroot()
37
    except ValueError:
38
        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
39
    if request.args.has_key('lang') == False and request.args.has_key('blog') == False:
40
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
41
        for i in g.root.iterlinks():
42
            if i[1] == 'href' and i[0].tag != 'link':
43
                try:
44
                    i[0].attrib['href'] = 'http://{0}?foruri={1}'.format(conf.DEPLOYURL[0],quote_plus(i[0].attrib['href']))
45
                except KeyError:
46
                    i[0].attrib['href'] = '{0}?foruri={1}'.format(conf.DEPLOYURL[0],quote_plus(i[0].attrib['href'].encode('utf-8')))
47
        setScripts() 
48
        g.root.body.set("onload","a11ypi.loadOverlay();")
49
        return lxml.html.tostring(g.root)
50
51
    elif request.args.has_key('lang') == True and request.args.has_key('interactive') == True and request.args.has_key('blog') == False:
52
        setScripts()
53
        if request.args['interactive'] == '1':
54
            setSocialScript()
55
            g.root.body.set("onload","a11ypi.ren();a11ypi.tweet(); a11ypi.facebook(); a11ypi.loadOverlay();")
56
        else:
57
            g.root.body.set("onload","a11ypi.ren();")
58
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
59
        return lxml.html.tostring(g.root)
60
        
61
    elif request.args.has_key('lang') == True and request.args.has_key('blog') == False:
62
        script_jq_mini = g.root.makeelement('script')
63
        g.root.body.append(script_jq_mini)
64
        script_jq_mini.set("src", conf.JQUERYURL[0] + "/jquery-1.7.min.js")
65
        script_jq_mini.set("type", "text/javascript")
66
        d['lang'] = request.args['lang']
67
        script_test = g.root.makeelement('script')
68
        g.root.body.append(script_test)
69
        script_test.set("src", conf.APPURL[0] + "/server/ui.js")
70
        script_test.set("type", "text/javascript")
71
        g.root.body.set("onload","a11ypi.ren()");
72
        return lxml.html.tostring(g.root)
73
74
    elif request.args.has_key('interactive') == True and request.args.has_key('blog') == True and request.args.has_key('lang') == True:
75
        setScripts()
76
        setSocialScript()
77
        g.root.body.set("onload","a11ypi.filter(); a11ypi.tweet(); a11ypi.facebook(); a11ypi.loadOverlay();");
78
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
79
        return lxml.html.tostring(g.root)
80
81
    elif request.args.has_key('interactive') == False and request.args.has_key('blog') == True:    
82
        setScripts()
83
        g.root.make_links_absolute(d['foruri'], resolve_base_href = True)
84
        g.root.body.set('onload', 'a11ypi.loadOverlay();')
85
        return lxml.html.tostring(g.root)
86
87
def setScripts():
88
    script_test = g.root.makeelement('script')
89
    script_edit = g.root.makeelement('script')
90
    g.root.body.append(script_test)
91
    g.root.body.append(script_edit)
92
    script_test.set("src", conf.APPURL[0] + "/server/ui.js")
93
    script_test.set("type", "text/javascript")
94
    script_edit.set("src", conf.APPURL[0] + "/server/wsgi/pageEditor.js")
95
    script_edit.set("type","text/javascript")
96
    script_config = g.root.makeelement('script')
97
    g.root.body.append(script_config)
98
    script_config.set("src", conf.APPURL[0] + "/server/config.js")
99
    script_config.set("type", "text/javascript")
100
101
    
102
    script_jq_mini = g.root.makeelement('script')
103
    g.root.body.append(script_jq_mini)
104
    script_jq_mini.set("src", conf.JQUERYURL[0] + "/jquery-1.7.min.js")
105
    script_jq_mini.set("type", "text/javascript")
106
    
107
    style = g.root.makeelement('link')
108
    g.root.body.append(style)
109
    style.set("rel","stylesheet")
110
    style.set("type", "text/css")
111
    style.set("href", conf.APPURL[0] + "/server/stylesheet.css")
112
113
    script_jq_cust = g.root.makeelement('script')
114
    g.root.body.append(script_jq_cust)
115
    script_jq_cust.set("src", conf.JQUERYUI[0] + "/jquery-ui.min.js")
116
    script_jq_cust.set("type", "text/javascript")
117
118
    style_cust = g.root.makeelement('link')
119
    style_cust.set("rel","stylesheet")
120
    style_cust.set("type", "text/css")
121
    style_cust.set("href", conf.JQUERYCSS[0] + "/jquery-ui.css")
122
    g.root.body.append(style_cust)
123
    
124
def setSocialScript():
125
    info_button = g.root.makeelement('button')
126
    g.root.body.append(info_button)
127
    info_button.set("id", "info")
128
    info_button.set("class", "alipi")
129
    info_button.set("onClick", "a11ypi.showInfo(a11ypi.responseJSON);")
130
    info_button.text =  "Info"
131
    info_button.set("title", "Have a look at the information of each renarrated element")
132
    
133
    share_button = g.root.makeelement('button')
134
    g.root.body.append(share_button)
135
    share_button.set("id", "share")
136
    share_button.set("class", "alipi")
137
    share_button.set("onClick", "a11ypi.share();")
138
    share_button.text =  "Share"
139
    share_button.set("title", "Share your contribution in your social network")
140
    
141
    see_orig = g.root.makeelement('button')
142
    g.root.body.append(see_orig)
143
    see_orig.set("id", "orig-button")
144
    see_orig.set("class", "alipi")
145
    see_orig.set("onClick", "a11ypi.showOriginal();")
146
    see_orig.text = "Original Page"
147
    see_orig.set("title", "Go to Original link, the original page of this renarrated")
148
    
149
    tweetroot = g.root.makeelement("div")
150
    tweetroot.set("id", "tweet-root")
151
    tweetroot.set("class", "alipi")
152
    tweetroot.set("style", "display:none;padding:10px;")
153
    g.root.body.append(tweetroot)
154
155
    tweet = g.root.makeelement("a")
156
    tweet.set("id", "tweet")
157
    tweet.set("href", "https://twitter.com/share")
158
    tweet.set("class", "alipi twitter-share-button")
159
    tweet.set("data-via", "a11ypi")
160
    tweet.set("data-lang", "en")
161
    tweet.set("data-url", "http://dev.a11y.in/web?foruri={0}&lang={1}&interactive=1".format(quote_plus(request.args['foruri']),request.args['lang']))
162
    tweet.textContent = "Tweet"
163
    tweetroot.append(tweet)
164
165
    fblike = g.root.makeelement("div")
166
    fblike.set("id", "fb-like")
167
    fblike.set("class", "alipi fb-like")
168
    fblike.set("style", "display:none;padding:10px;")
169
    fblike.set("data-href", "http://dev.a11y.in/web?foruri={0}&lang={1}&interactive=1".format(quote_plus(request.args['foruri']),request.args['lang']))
170
    fblike.set("data-send", "true")
171
    fblike.set("data-layout", "button_count")
172
    fblike.set("data-width", "50")
173
    fblike.set("data-show-faces", "true")
174
    fblike.set("data-font", "arial")
175
    g.root.body.append(fblike)
176
    
177
    style = g.root.makeelement('link')
178
    g.root.body.append(style)
179
    style.set("rel","stylesheet")
180
    style.set("type", "text/css")
181
    style.set("href", "http://dev.a11y.in/server/stylesheet.css")
182
183
    
184
@app.route('/directory')
185
def show_directory():
186
    collection = g.db['post']
187
    query = collection.group(
188
        key = Code('function(doc){return {"about" : doc.about,"lang":doc.lang}}'),
189
        condition={"about":{'$regex':'^[/\S/]'}},
190
        initial={'na': []},
191
        reduce=Code('function(doc,out){out.na.push(doc.blog)}')
192
        )
193
    query.reverse()
194
    return render_template('directory.html', name=query, mymodule = quote_plus, myset=set, mylist= list)
195
196
@app.route('/getLoc', methods=['GET'])
197
def get_loc():
198
199
    term = request.args['term']
200
    connection = oursql.Connection(conf.DBHOST[0],conf.DBUSRNAME[0],conf.DBPASSWD[0],db=conf.DBNAME[0])
201
    cursor = connection.cursor(oursql.DictCursor)
202
    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))
203
    r = cursor.fetchall()
204
    connection.close()
205
    d = {}
206
    d['return'] = r
207
    response = jsonify(d)
208
    response.headers['Access-Control-Allow-Origin'] = '*'
209
    return response
210
@app.route('/getLang', methods=['GET'])
211
def get_lang():
212
    term = request.args['term']
213
    connection = oursql.Connection(conf.DBHOST[0],conf.DBUSRNAME[0],conf.DBPASSWD[0],db=conf.DBNAME[0])
214
    cursor = connection.cursor(oursql.DictCursor)
215
    cursor.execute('select * from `languages` as l  where l.name like ? limit ?', (term+'%',5))
216
    r = cursor.fetchall()
217
    connection.close()
218
    d = {}
219
    d['return'] = r
220
    response = jsonify(d)
221
    response.headers['Access-Control-Allow-Origin'] = '*'
222
    return response
223
@app.route('/blank', methods=['GET'])
224
def serve_blank():
225
    return render_template('blank.html')
226
227
@app.route('/info', methods=['GET'])
228
def serve_info():
229
    coll = g.db['post']
230
    d = {}
231
    cntr = 0
232
    for i in coll.find({"about":unquote_plus(request.args['about']),"lang":request.args['lang']}):
233
        i['_id'] = str(i['_id'])
234
        d[cntr] = i
235
        cntr+=1
236
    response = jsonify(d)
237
    response.headers['Access-Control-Allow-Origin'] = '*'
238
    return response
239
@app.route("/replace", methods=['GET'])
240
def replace():
241
    collection = g.db['post']
242
    lang = request.args['lang']
243
    url = request.args['url']
244
    if request.args['type'] == 'renarration':
245
        query = collection.group(
246
            key = Code('function(doc){return {"xpath" : doc.xpath, "about": doc.url}}'),
247
            condition={"about" : url, "lang" : lang,"elementtype":"text","type":"renarration"},
248
            initial={'narration': []},
249
            reduce=Code('function(doc,out){out.narration.push(doc);}') 
250
            )
251
    
252
        audio_query =collection.group(
253
            key = Code('function(doc){return {"xpath" : doc.xpath, "about": doc.url}}'),
254
            condition={"about" : url, "lang" : lang, 'elementtype':"audio/ogg","type":"renarration"},
255
            initial={'narration': []},
256
            reduce=Code('function(doc,out){out.narration.push(doc);}') 
257
            )
258
259
        image_query =collection.group(
260
            key = Code('function(doc){return {"xpath" : doc.xpath, "about": doc.url}}'),
261
            condition={"about" : url, "lang" : lang, 'elementtype':"image", "type":"renarration"},
262
            initial={'narration': []},
263
            reduce=Code('function(doc,out){out.narration.push(doc);}') 
264
            )
265
        try:
266
            for i in audio_query:
267
                query.append(i)
268
        except IndexError:
269
            pass
270
        try:
271
            for i in image_query:
272
                query.append(i)
273
        except IndexError:
274
            pass
275
276
    elif request.args['type'] == 'comment':
277
        query = []
278
        query = collection.group(
279
            key = Code('function(doc){return {"xpath" : doc.xpath, "about": doc.url}}'),
280
            condition={"about" : url, "lang" : lang,"type":"comment"},
281
            initial={'narration': []},
282
            reduce=Code('function(doc,out){out.narration.push(doc);}') 
283
            )
284
    for i in query:
285
        for y in i['narration']:
286
            del(y['_id'])
287
    d = {}
288
    d['r'] = query
289
    response = jsonify(d)
290
    response.headers['Access-Control-Allow-Origin'] = '*'
291
    return response
292
293
@app.route('/feeds', methods=['GET'])
294
def serve_feed_temp():
295
    return render_template("feeds.html")
296
297
@app.route('/feed', methods=['GET'])
298
def serve_feed():
299
    coll = g.db['post']
300
    d = {}
301
    cntr = 0
302
    for i in coll.find().sort('_id',direction=-1):
303
        if i['data'] != '<br/>':
304
            i['_id'] = str(i['_id'])
305
            d[cntr] = i
306
            cntr+=1
307
    response = jsonify(d)
308
    response.headers['Access-Control-Allow-Origin'] = '*'
309
    return response
310
311
@app.route('/feeds/write', methods=['POST'])
312
def save_feed():
313
    coll = g.db['feed']
314
    d = {}
315
    d['about'] = request.form['about']
316
    d['blog'] = request.form['blog']
317
    d['bxpath'] = request.form['bxpath']
318
    d['xpath'] = request.form['xpath']
319
    d['author'] = request.form['author']
320
    d['type'] = request.form['type']
321
    d['lang']  = request.form['lang']
322
    d['location'] = request.form['location']
323
    coll.insert(d)
324
    if d['type'] == 'comment':
325
        collection = g.db['post']
326
        root = html5parser.parse(d['blog']).getroot()
327
        tree = root.getroottree()
328
        if tree.docinfo.doctype == '':
329
            lxml.html.xhtml_to_html(root)
330
        d['data'] = lxml.html.tostring(root.xpath(d['bxpath'])[0]) #TODO implement a function like lxml.html.make_links_absolute
331
        collection.insert(d)
332
    response = make_response()
333
    response.data = repr(request.form['blog'])
334
    response.headers['Access-Control-Allow-Origin'] = '*'
335
    return response
336
337
@app.route("/menu",methods=['GET'])
338
def menuForDialog():
339
    if request.args.has_key('option') == False:
340
        collection = g.db['post']
341
        c = {}
342
        cntr = 0
343
        for i in collection.find({"about":request.args['url']}).distinct('lang'):
344
            for j in collection.find({"about":request.args['url'],'lang':i}).distinct('type'):
345
                d = {}
346
                d['lang'] = i
347
                d['type'] = j
348
                c[cntr] = d
349
                cntr += 1
350
        return jsonify(c)
351
    else:
352
        collection = g.db['post']
353
        #get the ren languages for the received url
354
        langForUrl = collection.group(
355
            key = Code('function(doc){return {"about" : doc.about}}'),
356
            condition={"about" : d['url'],"blog":{'$regex':'/'+d['option']+'.*/'}},
357
            initial={'lang': []},
358
            reduce=Code('function(doc, out){if (out.lang.indexOf(doc.lang) == -1) out.lang.push(doc.lang)}') #here xpath for test
359
            )
360
        
361
        #send the response
362
        if (langForUrl):
363
            connection.disconnect()
364
            return json.dumps(langForUrl[0]['lang'])
365
        
366
        else:
367
            connection.disconnect()
368
            return "empty"
369
370
371
import logging,os
372
from logging import FileHandler
373
374
fil = FileHandler(os.path.join(os.path.dirname(__file__),'logme'),mode='a')
375
fil.setLevel(logging.ERROR)
376
app.logger.addHandler(fil)
377
378
if __name__ == '__main__':
379
    app.run(debug=True, host='0.0.0.0')