OSDN Git Service

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