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