OSDN Git Service

2重送信防止
[pybbs/pybbs.git] / pybbs.py
1 # -*- coding:utf-8 -*-
2 import os,re,glob
3 from tornado import escape,web,ioloop,httpserver,httpclient
4 import pymongo, urllib
5 from datetime import datetime,timedelta
6 import json
7 from bson.objectid import ObjectId #don't remove
8 from linebot.api import LineBotApi
9 from linebot.exceptions import (InvalidSignatureError)
10 from linebot.models import (TextSendMessage)
11
12
13 class BaseHandler(web.RequestHandler):
14     def get_current_user(self):
15         user = self.get_secure_cookie('admin_user')
16         return escape.utf8(user)
17     
18     def set_current_user(self,username):
19         self.set_secure_cookie('admin_user',username)
20         
21     def clear_current_user(self):
22         self.clear_cookie('admin_user')
23
24 class IndexHandler(BaseHandler):
25     def main(self,dbname,page):
26         params = self.application.db['params'].find_one({'app':'bbs'})
27         if params['mentenance'] is True:
28             self.render('mentenance.htm',title=params['title'],db=dbname)
29             return
30         if dbname not in self.application.mylist():
31             if self.current_user == b'admin':
32                 coll = self.application.db[dbname]
33                 coll.insert({})
34                 coll.remove({})
35             else:
36                 raise web.HTTPError(404)
37         key = self.get_argument('key','')
38         if key != '':
39             table = self.application.db[dbname]
40             rec = table.find_one({'number':int(key)})
41             if rec:
42                 self.render('article.htm',record=rec)
43                 return
44             else:
45                 raise web.HTTPError(404)
46         self.rule = escape.url_unescape(self.get_cookie('aikotoba',''))
47         self.na = escape.url_unescape(self.get_cookie('username',u'誰かさん'))
48         self.pos = self.application.gpos(dbname,page)
49         table = self.application.db[dbname]
50         i = params['count']
51         start = (self.pos-1)*i
52         if start < 0:
53             start = table.count()-i
54             if start < 0:
55                 start = 0
56         rec = table.find()
57         self.bool = (dbname == params['info name'])
58         if self.bool is True:
59             rec.sort('number',-1)
60         else:
61             rec.sort('number')
62         self.rec = rec.skip(start).limit(i)
63
64     def get(self,dbname,page='0'):
65         self.main(dbname,page)
66         db = self.application.db
67         table = db[dbname].find()
68         params = db['params'].find_one({'app':'bbs'})
69         if table.count() >= 10*params['count']:
70             self.render('modules/full.htm',position=self.pos,records=self.rec,data=params,db=dbname)
71         if self.bool is True and self.current_user != b'admin':
72             self.render('modules/info.htm',position=self.pos,records=self.rec,data=params,db=dbname,error='')
73         else:
74             self.render('modules/index.htm',position=self.pos,records=self.rec,data=params,username=self.na,title='',
75             comment='',db=dbname,aikotoba=self.rule,error='',check='checked')
76
77 class LoginHandler(BaseHandler):
78     def get(self):
79         info = self.application.db['params'].find_one({'app':'bbs'})
80         query = self.get_query_argument('next','/'+info['info name'])
81         i = query[1:].find('/')
82         if i == -1:
83             qs = query[1:]
84         else:
85             qs = query[1:i+1]
86         self.render('login.htm',db=escape.url_unescape(qs))
87         
88     def post(self):
89         dbname = self.get_argument('record','')
90         if dbname == '':
91             self.redirect('/login')
92             return
93         pw = self.application.db['params'].find_one({'app':'bbs'})
94         if self.get_argument('password') == pw['password']:
95             self.set_current_user('admin')
96         if dbname == 'master':
97             self.redirect('/master')
98         else:
99             self.redirect('/'+dbname+'/admin/0/')
100         
101 class LogoutHandler(BaseHandler):
102     def get(self):
103         self.clear_current_user()
104         self.redirect('/login')
105  
106 class JumpHandler(BaseHandler):
107     def get(self):
108         self.clear_current_user()
109         self.redirect('/')
110         
111 class NaviHandler(web.RequestHandler):
112     def get(self):
113         if 'params' not in self.application.mylist():
114             item = {"mentenance":False,"out_words":[u"阿保",u"馬鹿",u"死ね"],"password":"admin",
115                     "title2":"<h1 style=color:maroon;font-style:italic;text-align:center>とるね~ど号</h1>",
116                     "bad_words":["<style","<link","<script","<img","<a"],"count":30,
117                     "title":u"とるね~ど号","info name":"info",'app':'bbs'}
118             self.application.db['params'].insert(item)
119             self.application.db['info'].find()
120         table = self.application.db['params'].find_one({'app':'bbs'})
121         if table['mentenance'] is True:
122             self.render('mentenance.htm',title=table['title'],db=table['info name'])
123             return
124         coll = self.application.coll()
125         na = table['info name']
126         self.render('top.htm',coll=coll,name=na,full=self.full)
127
128     def full(self,dbname):
129         if dbname in self.application.coll():
130             i = 10*self.application.db['params'].find_one({'app':'bbs'})['count']
131             table = self.application.db[dbname]
132             if table.count() >= i:
133                 return True
134         return False
135
136 class TitleHandler(NaviHandler):
137     def get(self):
138         rec = sorted(self.title(),key=lambda x: x['date2'])
139         self.render('title.htm',coll=rec,full=self.full)  
140         
141     def title(self):
142         for x in self.application.coll():
143             item = {}
144             item['name'] = x
145             table = self.application.db[x]
146             i = table.count()
147             item['count'] = i            
148             tmp = table.find_one({'number':1})
149             if tmp:
150                 s = tmp['title']
151             else:
152                 s = ''
153             item['title'] = s   
154             if i == 0:
155                 item['date'] = ''
156                 item['date2'] = 0
157             else:
158                 rec = table.find().sort('number')
159                 s = rec[i-1]['date']
160                 item['date'] = s
161                 i = datetime.strptime(s,'%Y/%m/%d %H:%M')
162                 year = datetime.now().year-i.year
163                 if year == 0:
164                     j = 800
165                 elif year == 1:
166                     j = 400
167                 else:
168                     j = 0
169                 item['date2'] = j+31*(i.month-1)+i.day
170             yield item
171         
172 class RegistHandler(IndexHandler):
173     def post(self,dbname):
174         self.main(dbname,'0')
175         if dbname not in self.application.coll(info=True):
176             raise web.HTTPError(404)
177         params = self.application.db['params'].find_one({'app':'bbs'})
178         words = params['bad_words']
179         out = params['out_words']
180         rule = self.get_argument('aikotoba')
181         na = self.get_argument('name')
182         sub = self.get_argument('title')
183         com = self.get_argument('comment',None,False)
184         text = ''
185         i = 0
186         url = []
187         error = ''
188         kinsi = False
189         for line in com.splitlines():
190             if kinsi is False:
191                 for word in out:
192                     if word in line:
193                         error += u'禁止ワード.<br>'
194                         kinsi = True
195                         break
196             for word in words:
197                 if word in line.lower():
198                     tag = escape.xhtml_escape(word)
199                     error += u'タグ違反.('+tag+')<br>'
200             i += len(line)
201             obj = re.finditer('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', line)
202             for x in obj:
203                 if x.group() not in url:
204                     url.append(x.group())
205             j = 0
206             for x in line:
207                 if x == ' ':
208                     j += 1
209                 else:
210                     break
211             if j > 0: 
212                 line = line.replace(' ','&nbsp;',j)     
213             if len(line) == 0:
214                 text += '<p><br>\n</p>'
215             else:
216                 text += '<p>'+self.link(line,dbname)+'\n</p>'
217         if rule != u'げんき':
218             error += u'合言葉未入力.<br>'
219         s = ''
220         for x in url:
221             s = s+'<tr><td><a href={0} class=livepreview target=_blank>{0}</a></td></tr>'.format(x)
222         if s != '':
223             text = text+'<table><tr><td>検出url:</td></tr>'+s+'</table>'
224         pw = self.get_argument('password')
225         if i > 1000:
226             error += u'文字数が1,000をこえました.<br>'
227         if na == '':
228             na = u'誰かさん'
229         if sub == '':
230             sub = u'タイトルなし.'
231         article = self.application.db[dbname]
232         if article.count() == 0:
233             no = 1
234         else:            
235             items = article.find()
236             item = items.sort('number')[article.count()-1]
237             no = item['number']+1
238         s = datetime.now()
239         k = '%Y%m%d%H%M%S'
240         if self.get_argument('show', 'false') == 'true':
241             ch = 'checked'
242         else:
243             ch = ''
244             t = self.get_cookie('time')
245             if t and s - datetime.strptime(escape.url_unescape(t),k) < timedelta(seconds=10):
246                 error += u'二重送信.'
247         if error == '':
248             if ch == 'checked':
249                 error = '<p style=font-size:2.5em;color:blue>↓↓プレビュー↓↓</p>\n' + text
250                 ch = ''
251             else:
252                 reg = {'number': no, 'name': na, 'title': sub, 'comment': text, 'raw': com, 'password': pw,
253                     'date': s.strftime('%Y/%m/%d %H:%M')}
254                 article.insert(reg)
255                 self.set_cookie('aikotoba', escape.url_escape(rule))
256                 self.set_cookie('username', escape.url_escape(na))
257                 self.set_cookie('time',escape.url_escape(s.strftime(k)))
258                 self.redirect('/' + dbname + '#article')
259                 return
260         else:
261             error = '<p style=color:red>' + error + '</p>'
262         self.render('modules/index.htm', position=0, records=self.rec, data=params,title=sub,
263             username=na, comment=com, db=dbname, aikotoba=rule, error=error, check=ch)
264
265     def link(self,command,database):
266         i = 0
267         text = ''
268         obj = re.finditer('>>[0-9]+',command)
269         for x in obj:
270             s = '<a class=minpreview data-preview-url=/{0}?key={1} href=/{0}/userdel?job={1}>>>{1}</a>'.format(database,x.group()[2:])
271             text = text+command[i:x.start()]+s
272             i = x.end()
273         else:
274             text = text+command[i:]
275         return text
276     
277 class AdminHandler(BaseHandler):
278     @web.authenticated               
279     def get(self,dbname,page='0'):
280         if dbname == '':
281             dbname = self.get_argument('record','')
282         table = self.application.db[dbname]
283         rec = table.find().sort('number')                   
284         mente = self.application.db['params'].find_one({'app':'bbs'})
285         if mente['mentenance'] is True:
286             check = 'checked=checked'
287         else:
288             check = ''
289         pos = self.application.gpos(dbname,page)
290         i = mente['count']
291         start = (pos-1)*i
292         if start < 0:
293             start = table.count()-i
294             if start < 0:
295                 start = 0
296         rec.skip(start).limit(i)
297         self.render('modules/admin.htm',position=pos,records=rec,mente=check,password=mente['password'],db=dbname)
298
299 class AdminConfHandler(BaseHandler):
300     @web.authenticated
301     def post(self,dbname,func):
302         if func == 'set':
303             param = self.application.db['params'].find_one({'app':'bbs'})
304             if self.get_argument('mente','') == 'on':
305                 mente = True
306             else:
307                 mente = False  
308             word = self.get_argument('pass','')
309             if word == '':
310                 self.render('regist.htm',content='パスワードを設定してください')
311                 return
312             else:
313                 param['mentenance']=mente
314                 param['password']=word  
315                 self.application.db['params'].save(param)
316         elif func == 'del':
317             table = self.application.db[dbname]
318             for x in self.get_arguments('item'):
319                 table.remove({'number':int(x)})
320         self.redirect('/'+dbname+'/admin/0/')
321           
322 class UserHandler(web.RequestHandler):
323     def get(self,dbname):
324         q = self.get_query_argument('job','0',strip=True)
325         self.redirect(self.application.page(dbname,q))
326         
327     def post(self,dbname):
328         number = self.get_argument('number')
329         if number.isdigit() is True:
330             num = int(number)
331             url = self.application.page(dbname,number)
332             if 'password' in self.request.arguments.keys():
333                 pas = self.get_argument('password')
334             else:
335                 self.redirect(url)
336                 return
337             table = self.application.db[dbname]
338             obj = table.find_one({'number':num})
339             if obj and(obj['password'] == pas):
340                 table.update({'number':num},{'$set':{'title':u'削除されました','name':'','comment':u'<i><b>投稿者により削除されました</b></i>','raw':''}})
341                 self.redirect(url)
342                 return
343         self.redirect('/'+dbname)
344
345 class SearchHandler(web.RequestHandler):
346     def post(self,dbname=''):
347         arg = self.get_argument('word1')
348         self.word = arg[:]
349         self.andor = self.get_argument('type')
350         self.radiobox = self.get_argument('filter')       
351         if dbname == '':
352             rec = []
353             for x in self.application.coll():
354                 moji = self.search(x)
355                 for y in sorted(moji,key=lambda k: k['number']):
356                     y['dbname'] = x
357                     rec.append(y) 
358         else:
359             rec = sorted(self.search(dbname),key=lambda x: x['number'])
360         self.render('modules/search.htm',records=rec,word1=arg,db=dbname)
361
362     def get(self,dbname=''):
363         if dbname not in self.application.coll(info=True) and dbname != '':
364             raise web.HTTPError(404)
365         self.render('modules/search.htm',records=[],word1='',db=dbname)
366     
367     def search(self,dbname):
368         table = self.application.db[dbname]    
369         andor = self.andor == 'OR'
370         element = self.word.split()
371         elm = []
372         for x in element:
373             if x != '':
374                 elm.append(re.escape(x))
375         if self.radiobox == 'comment':
376             query = []
377             for qu in elm:
378                 query.append({'raw':re.compile(qu,re.IGNORECASE)})
379             if len(query) == 0:
380                 return
381             if andor:    
382                 result = table.find({'$or':query})
383                 color = 'yellow'
384             else:
385                 result = table.find({'$and':query})
386                 color = 'aqua'
387             for x in result:
388                 com = ''
389                 i = 0
390                 for text in x['raw'].splitlines():
391                     for y in text:
392                         if y == ' ':
393                             i += 1
394                         else:
395                             break
396                     text = text.replace(' ','&nbsp;',i)                  
397                     for y in element:                        
398                         if y.lower() in text.lower():
399                             com += '<p style=background-color:'+color+'>'+text+'<br></p>'  
400                             break                          
401                     else:
402                         if text == '':
403                             com += '<br>'
404                         else:
405                             com += '<p>'+text+'</p>'
406                 x['comment'] = com
407                 yield x       
408         else:
409             query = []
410             for x in element:
411                 if x != '':
412                     query.append({'name':x})
413             if len(query) == 0:
414                 return
415             for x in table.find({'$or':query}):
416                 yield x  
417                 
418 class HelpHandler(web.RequestHandler):
419     def get(self):
420         self.render('help.htm',req='')
421     
422     def post(self):
423         com = self.get_argument('help','')
424         line = com.splitlines(True)
425         com = ''
426         for x in line:
427             com += '<p>'+x
428         time = datetime.now()
429         db = self.application.db['master']
430         db.insert({'comment':com,'time':time.strftime('%Y/%m/%d')})
431         self.render('help.htm',req='送信しました')
432        
433 class MasterHandler(BaseHandler):
434     @web.authenticated  
435     def get(self):
436         if self.current_user == b'admin':
437             com = self.application.db['master'].find()
438             sum = self.application.db['temp'].find().count()
439             self.render('master.htm',com=com,sum=sum)
440         else:
441             raise web.HTTPError(404)
442     
443 class AlertHandler(web.RequestHandler):
444     def get(self):
445         db = self.get_query_argument('db')
446         num = self.get_query_argument('num')
447         table = self.application.db[db]
448         tb = table.find_one({'number':int(num)})
449         com = tb['comment']
450         time = datetime.now().strftime('%Y/%m/%d')
451         link = self.application.page(db,num)
452         jump = '<p><a href={0}>{0}</a>'.format(link)
453         d = datetime.now().weekday()
454         table = self.application.db['temp']
455         table.remove({'date':{'$ne':d}})
456         result = table.insert(
457             {'comment':com+jump,'time':time,'link':link,'date':d,'db':db,'num':num})
458         self.render('alert.htm',com=com+jump,num=str(result))
459         
460     def post(self):
461         id = ObjectId(self.get_argument('num'))
462         table = self.application.db['temp']
463         tb = table.find_one({'_id':id})      
464         link = tb['link']
465         com = self.get_argument('com')
466         table.remove({'_id':id})
467         if self.get_argument('cancel','') == 'cancel':
468             self.redirect(link)
469             return
470         if com != '':
471             tb['comment'] = com+tb['comment']
472         del tb['date']
473         table = self.application.db['master']
474         table.insert(tb)
475         self.redirect(link)
476         
477 class CleanHandler(web.RequestHandler):
478     def post(self):
479         bool = self.get_argument('all', 'false').lower()
480         table = self.application.db['master']
481         if bool == 'true':
482             table.remove()
483             self.application.db['temp'].remove()
484         elif bool == 'false':
485             for x in list(table.find()):           
486                 if not 'num' in x.keys():
487                     table.remove({'_id':x['_id']})
488                 else:
489                     item = self.application.db[x['db']].find_one({'number':int(x['num'])})
490                     if (not item)or(item['raw'] == ''):
491                         table.remove({'_id':x['_id']})   
492         com = self.application.db['master'].find()
493         sum = self.application.db['temp'].find().count()
494         self.render('master.htm', com=com, sum=sum)
495                                         
496 class FooterModule(web.UIModule):
497     def render(self,number,url,link):
498         return self.render_string('modules/footer.htm',index=number,url=url,link=link)
499     
500 class HeadlineApi(web.RequestHandler):
501     def get(self):
502         response = {}
503         for coll in self.application.coll():
504             table = self.application.db[coll]
505             if table.count() == 0:
506                 mydict = {}
507             else:
508                 text = table.find().sort('number')[table.count()-1]
509                 mydict = {'number':text['number'],'name':text['name'],'title':text['title'],'comment':text['raw'][0:20]}
510             response[coll] = mydict                 
511         self.write(json.dumps(response,ensure_ascii=False))
512         
513 class ArticleApi(web.RequestHandler):
514     def get(self,dbname,number):
515         response = None
516         if dbname in self.application.coll():
517             table = self.application.db[dbname]
518             response = table.find_one({'number':int(number)})      
519         if not response:
520             response = {}
521         else:
522             del response['_id']
523             del response['comment']
524             del response['password']
525         self.write(json.dumps(response,ensure_ascii=False))      
526
527 class ListApi(web.RequestHandler):
528     def get(self,dbname):
529         response = None
530         if dbname in self.application.coll():
531             table = self.application.db[dbname]
532             response = {}
533             for data in table.find().sort('number'):
534                 response[data['number']] = data['raw'][0:20]
535         if not response:
536             response = {}
537         self.write(json.dumps(response,ensure_ascii=False))
538
539 class WebHookHandler(web.RequestHandler):
540     def main(self, no):
541         #pz = pytz.timezone('Asia/Tokyo')
542         now = datetime.now()#pz)
543         t = now.hour
544         w = now.weekday()
545         if (w < 5)and(t >= 9)and(t < 16):
546             return u'仕事中.'
547         table, na = self.users()
548         item = table.find({'no':re.compile(no,re.IGNORECASE)})
549         if item.count() == 1:
550             x = item[0]
551             ans = x['name']+'\n'+x['no']
552         elif item.count() > 1:
553             ans = ''    
554             obj = list(item)
555             list1 = sorted(obj, key=lambda k:k['name'])
556             for x in list1:
557                 if x['name'] == list1[0]['name']:
558                     ans += x['name']+'\n'+x['no']+'\n'
559                 else:
560                     break
561             else:
562                 return ans       
563             ans = self.itr(sorted(list1, key=lambda k:k['no']))
564         else:
565             ans = self.itr(table.find().sort('no'))
566             ans = '-*-'+na+' list-*-\n'+ans
567         return ans
568     
569     def itr(self, item):
570         ans = ''
571         for x in item:
572             ans += '【'+x['no']+'】 '
573         return ans
574     
575     def help(self):
576         s = '-*-database names-*-\n'
577         out = ['objectlabs-system','objectlabs-system.admin.collections','users_bot']
578         for x in self.application.mylist():
579             if x not in out and x[-4:] == '_bot' and x != '_bot':
580                 s += x[:-4]+'\n'
581         return s
582     
583     def setting(self, dbname):
584         dbname = dbname.lower()+'_bot'
585         ca = self.application.mylist()
586         if 'users_bos' in ca:
587             ca.remove('users_bot')
588         if dbname in ca:
589             db = self.application.db['users_bot']
590             item = db.find_one({'name':self.uid})
591             if item['dbname'] == dbname:
592                 return False
593             else:
594                 db.update({'name':self.uid}, {'name':self.uid, 'dbname':dbname})
595                 return True
596         return False
597
598     def users(self):
599         db = self.application.db['users_bot']
600         item = db.find_one({'name':self.uid})
601         x = item['dbname']
602         return self.application.db[x], x[:-4]
603                           
604     def post(self):
605         '''
606         signature = self.request.headers['X-Line-Signature']
607         body = self.request.body
608         parser = WebhookParser(self.application.ch)
609         try:
610             parser.parse(body, signature)
611         except InvalidSignatureError:
612             web.HTTPError(404)
613             return
614         '''
615         dic = escape.json_decode(self.request.body)              
616         for event in dic['events']:
617             if 'replyToken' in event.keys():
618                 self.uid = event['source']['userId']
619                 bot = 'users_bot'               
620                 if event['type'] == 'unfollow':
621                     self.application.db[bot].remove({'name':self.uid})
622                     return
623                 elif event['type'] != 'message' or event['message']['type'] != 'text':
624                     return
625                 item = self.application.db['params'].find_one({'app':'bot'})
626                 if item:
627                     de = item['default']
628                 else:
629                     de = '_bot'         
630                 if item and 'access_token' in item.keys():
631                     token = item['access_token']
632                 else:      
633                     token =self.application.tk
634                 if bot not in self.application.mylist() or not self.application.db[bot].find_one({'name':self.uid}):
635                     db = self.application.db[bot]
636                     db.insert({'name':self.uid, 'dbname':de})
637                 x = event['message']['text']     
638                 if self.setting(x):
639                     te = u'設定完了.'
640                 elif x == '?':
641                     te = self.help()
642                 else:
643                     te = self.main(x)
644                 linebot = LineBotApi(token)            
645                 linebot.reply_message(event['replyToken'], TextSendMessage(text=te))
646
647 class InitHandler(web.RequestHandler):
648     def get(self):        
649         de = self.get_argument('default', '')     
650         if de == '':
651             names = self.application.mylist()
652             db = []
653             for x in names:
654                 if x[-4:] == '_bot' and x != 'users_bot':
655                     db.append(x[:-4])
656             self.render('init.htm',db=db)
657             return
658         tb = self.application.db['params']
659         if tb.find_one({'app':'bot'}):
660             tb.update({'app':'bot'}, {'app':'bot', 'default':de+'_bot'})
661         else:
662             tb.insert({'app':'bot', 'default':de+'_bot'})
663         for x in glob.glob('./*.txt'):
664             f = open(x)
665             data = f.read()
666             f.close()
667             self.main(x[2:-4].lower(), data)
668     
669     def main(self, name, data):
670         if name == 'requirements':
671             return
672         item = []
673         dic = None
674         for x in data.split('\n'):
675             if len(x) > 0 and x[0] == '@':
676                 dic = {}
677                 dic['name'] = x[1:]
678             elif dic:
679                 dic['no'] = x
680                 item.append(dic)
681         table = self.application.db[name+'_bot']
682         table.remove()
683         for x in item:
684             table.insert(x) 
685             
686 class TokenHandler(web.RequestHandler):
687     def on_response(self, response):
688         dic = escape.json_decode(response.body)
689         token = dic['access_token']
690         table = self.application.db['params']
691         data = {'app':'bot', 'access_token':token}
692         if table.find_one({'app':'bot'}):
693             table.save(data)
694         else:
695             table.insert(data)
696         self.finish()
697
698     #@web.asynchronous
699     def get(self):
700         url = 'https://api.line.me/v2/oauth/accessToken'
701         headers = 'application/x-www-form-urlencoded'
702         data = {'grant_type':'client_credentials', 'client_id':self.application.id, 'client_secret':self.application.ch}
703         body = urllib.parse.urlencode(data)
704         req = httpclient.HTTPRequest(url=url,method='POST',headers=headers,body=body)
705         http = httpclient.AsyncHTTPClient()
706         http.fetch(req, callback=self.on_response)
707
708 class Application(web.Application):
709     ch = os.environ['Channel_Secret']
710     uri = os.environ['MONGODB_URI']
711     ac = os.environ['ACCOUNT']
712     tk = os.environ['Access_Token']
713     db = pymongo.MongoClient(uri)[ac]
714     def __init__(self):
715         handlers = [(r'/',NaviHandler),(r'/login',LoginHandler),(r'/logout',LogoutHandler),(r'/title',TitleHandler),
716                     (r'/headline/api',HeadlineApi),(r'/read/api/([a-zA-Z0-9_%]+)/([0-9]+)',ArticleApi),
717                     (r'/write/api/([a-zA-Z0-9_%]+)/()/()/()',ArticleApi),(r'/list/api/([a-zA-Z0-9_%]+)',ListApi),
718                     (r'/help',HelpHandler),(r'/master',MasterHandler),(r'/alert',AlertHandler),(r'/jump',JumpHandler),
719                     (r'/callback',WebHookHandler),(r'/init',InitHandler),(r'/search',SearchHandler),(r'/clean',CleanHandler),(r'/token',TokenHandler),
720                     (r'/([a-zA-Z0-9_%]+)',IndexHandler),(r'/([a-zA-Z0-9_%]+)/([0-9]+)/',IndexHandler),
721                     (r'/([a-zA-Z0-9_%]+)/admin/([0-9]+)/*',AdminHandler),(r'/([a-zA-Z0-9_%]+)/admin/([a-z]+)/*',AdminConfHandler),(r'/([a-zA-Z0-9_%]+)/userdel',UserHandler),
722                     (r'/([a-zA-Z0-9_%]+)/search',SearchHandler),(r'/([a-zA-Z0-9_%]+)/regist',RegistHandler)]
723         settings = {'template_path':os.path.join(os.path.dirname(__file__),'templates'),
724                         'static_path':os.path.join(os.path.dirname(__file__),'static'),
725                         'ui_modules':{'Footer':FooterModule},
726                         'cookie_secret':os.environ['cookie'],
727                         'xsrf_cookies':False,
728                         #'debug':True,
729                         'login_url':'/login'
730                         }
731         super().__init__(handlers,**settings)
732  
733     def gpos(self,dbname,page):
734         params = self.db['params'].find_one({'app':'bbs'})
735         pos = int(page)
736         if pos <= 0:
737             pos = 0
738         elif (pos-1)*params['count'] >= self.db[dbname].count():
739             pos = 0
740         return pos
741
742     def page(self,dbname,number):
743         table = self.db[dbname]
744         rec = table.find({'number':{'$lte':int(number)}}).count()
745         s = self.db['params'].find_one({'app':'bbs'})
746         conf = int(s['count'])
747         if table.find().count() - rec >= conf:
748             return '/'+dbname+'/'+str(1+rec//conf)+'/#'+number
749         else:
750             return '/'+dbname+'#'+number
751
752     def mylist(self):
753         return self.db.list_collection_names()[:]
754
755     def coll(self,info=False):
756         name = self.mylist()
757         item = self.db['params'].find_one({'app':'bbs'})
758         target = ['objectlabs-system', 'objectlabs-system.admin.collections', 'system.indexes',
759             'params', 'master', 'temp']
760         if info is False:
761             target.append(item['info name'])
762         for x in target:
763             name.remove(x)
764         for x in name:
765             if x[-4:] == '_bot':
766                 name.remove(x)
767         return sorted(name)
768    
769 if __name__ == '__main__':
770     app = Application()
771     http_server = httpserver.HTTPServer(app)
772     port = int(os.environ.get('PORT',5000))
773     http_server.listen(port)
774     ioloop.IOLoop.instance().start()