6 import tornado.httpserver
9 from tornado.options import define,options
10 from tinydb import TinyDB,Query,where
11 from tinydb.operations import delete
12 from datetime import datetime
15 define('port',default=8000,help='run on the given port',type=int)
17 class BaseHandler(tornado.web.RequestHandler):
18 def get_current_user(self):
19 user = self.get_secure_cookie('admin_user')
20 return tornado.escape.utf8(user)
22 def set_current_user(self,username):
23 self.set_secure_cookie('admin_user',username)
25 def clear_current_user(self):
26 self.clear_cookie('admin_user')
28 class IndexHandler(BaseHandler):
29 def get(self,dbname,page='0'):
30 params = self.application.db.get(where('kinds') == 'conf')
31 if params['mentenance'] == True:
32 self.render('mentenance.htm',title=params['title'],db=dbname)
33 if self.application.collection(dbname) == False:
34 if self.current_user == b'admin':
35 self.application.db.table(dbname)
37 raise tornado.web.HTTPError(404)
39 key = self.get_argument('key','')
41 table = self.application.db.table(dbname)
42 rec = table.get(where('number') == int(key))
44 self.render('article.htm',record=rec)
47 raise tornado.web.HTTPError(404)
50 na = tornado.escape.url_unescape(self.get_cookie("username",u"誰かさん"))
51 pos = self.application.gpos(dbname,page)
52 table = self.application.db.table(dbname)
58 rec = sorted(table.all(),key=lambda x: x['number'])[start:start+i]
59 if len(table) >= 10*i:
60 self.render('modules/full.htm',position=pos,records=rec,data=params,db=dbname)
62 self.render('modules/index.htm',position=pos,records=rec,data=params,username=na,db=dbname)
64 class LoginHandler(BaseHandler):
66 self.render('login.htm')
69 pw = self.application.db.get(where('kinds') == 'conf')
70 if self.get_argument('password') == pw['password']:
71 self.set_current_user('admin')
72 dbname = self.get_argument('record')
73 self.redirect('/'+dbname+'/admin/0/')
75 class LogoutHandler(BaseHandler):
77 self.clear_current_user()
78 self.redirect('/login')
80 class NaviHandler(tornado.web.RequestHandler):
82 self.render('top.htm',coll=sorted(self.name()),full=self.full)
85 for x in self.application.db.tables():
89 def full(self,dbname):
90 if dbname in self.application.db.tables():
91 i = 10*self.application.db.get(where('kinds') == 'conf')['count']
92 table = self.application.db.table(dbname)
97 class TitleHandler(NaviHandler):
99 rec = sorted(self.title(),key=lambda x: x['date2'])
100 self.render('title.htm',coll=rec,full=self.full)
103 for x in self.name():
106 table = self.application.db.table(x)
109 if table.contains(where('number') == 1) == True:
110 s = table.get(where('number') == 1)['title']
118 rec = sorted(table.all(),key=lambda k: k['number'])
121 i = datetime.strptime(s,'%Y/%m/%d %H:%M')
122 year = datetime.now().year-i.year
129 item['date2'] = j+31*(i.month-1)+i.day
132 class RegistHandler(tornado.web.RequestHandler):
133 def post(self,dbname):
134 if self.application.collection(dbname) == False:
135 raise tornado.web.HTTPError(404)
137 self.database = dbname
138 rec = self.application.db.get(where('kinds') == 'conf')
139 words = rec['bad_words']
140 out = rec['out_words']
141 na = self.get_argument('name')
142 sub = self.get_argument('title')
143 com = self.get_argument('comment',None,False)
150 error = error + u'禁止ワード.'
152 for line in com.splitlines(True):
156 if word in line.lower():
157 error = error + u'タグ違反.('+word+')'
159 obj = re.finditer('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', line)
161 if x.group() not in url:
162 url.append(x.group())
163 if re.match(' ',line):
164 line = line.replace(' ',' ',1)
165 text = text+'<p>'+self.link(line)+'<br></p>'
168 s = s+'<tr><td><a class=livepreview target=_blank href={0}>{0}</a></td></tr>'.format(x)
170 text = text+'<table><tr><td>検出URL:</td></tr>'+s+'</table>'
171 pw = self.get_argument('password')
173 error = error + u'本文がありません.'
175 error = error +u'文字数が1,000をこえました.'
176 article = self.application.db.table(dbname)
177 if len(article) == 0:
180 item = sorted(article.all(),key=lambda x: x['number'])[len(article)-1]
181 no = item['number']+1
186 reg = {'number':no,'name':na,'title':sub,'comment':text,'raw':com,'password':pw,'date':s.strftime('%Y/%m/%d %H:%M')}
188 self.set_cookie('username',tornado.escape.url_escape(na))
189 self.redirect('/'+dbname+'#article')
191 self.render('regist.htm',content=error)
193 def link(self,command):
196 obj = re.finditer('>>[0-9]+',command)
198 s = '<a class=minpreview data-preview-url=/{0}?key={1} href=/{0}#{1}>>>{1}</a>'.format(self.database,x.group()[2:])
199 text = text+command[i:x.start()]+s
202 text = text+command[i:]
205 class AdminHandler(BaseHandler):
206 @tornado.web.authenticated
207 def get(self,dbname,page='0'):
209 dbname = self.get_argument('record','')
210 if self.application.collection(dbname) == False:
211 raise tornado.web.HTTPError(404)
213 table = self.application.db.table(dbname)
214 rec = sorted(table.all(),key=lambda x: x['number'])
215 mente = self.application.db.get(where('kinds') == 'conf')
216 if mente['mentenance'] == True:
217 check = 'checked=checked'
220 pos = self.application.gpos(dbname,page)
227 self.render('modules/admin.htm',position=pos,records=rec[start:start+i],mente=check,password=mente['password'],db=dbname)
229 class AdminConfHandler(BaseHandler):
230 @tornado.web.authenticated
231 def post(self,dbname,func):
233 param = self.application.db.get(where('kinds') == 'conf')['mentenance']
234 if self.get_argument('mente','') == 'on':
242 word = self.get_argument('pass','')
244 self.render('regist.htm',content='パスワードを設定してください')
247 self.application.db.update({'mentenance':mente,'password':word},where('kinds') == 'conf')
249 table = self.application.db.table(dbname)
250 for x in self.get_arguments('item'):
251 table.remove(where('number') == int(x))
252 self.redirect('/'+dbname+'/admin/0/')
255 self.application.db.close()
256 shutil.copy(st.json,st.bak)
257 self.application.db = TinyDB(st.json)
260 database = self.application.db
262 for x in database.tables():
263 if self.application.collection(x) == True:
264 database.purge_table(x)
265 if x in bak.tables():
266 table = database.table(x)
267 table.insert_multiple(bak.table(x).all())
269 class UserHandler(tornado.web.RequestHandler):
270 def post(self,dbname):
271 num = self.get_argument('number')
272 if num.isdigit() == True:
274 pas = self.get_argument('password')
275 table = self.application.db.table(dbname)
277 obj = table.get(qwr.number == num)
278 if obj and(obj['password'] == pas):
279 table.remove(qwr.number == num)
280 self.redirect('/'+dbname)
282 class SearchHandler(tornado.web.RequestHandler):
283 def post(self,dbname):
284 self.word = tornado.escape.url_unescape(self.get_argument('word1'))
285 self.radiobox = self.get_argument('filter')
286 self.set_cookie('search',tornado.escape.url_escape(self.word))
287 rec = sorted(self.search(dbname),key=lambda x: x['number'])
288 self.render('modules/search.htm',records=rec,word1=self.word,db=dbname)
290 def get(self,dbname):
291 if self.application.collection(dbname) == False:
292 raise tornado.web.HTTPError(404)
294 word = self.get_cookie('search','')
295 word = tornado.escape.url_unescape(word)
296 self.render('modules/search.htm',records=[],word1=word,db=dbname)
298 def search(self,dbname):
299 table = self.application.db.table(dbname)
300 element = self.word.split()
301 if len(element) == 0:
303 while len(element) < 3:
304 element.append(element[0])
305 if self.radiobox == 'comment':
306 query = (Query().raw.search(element[0])) | (Query().raw.search(element[1])) | (Query().raw.search(element[2]))
308 query = (Query().name == element[0]) | (Query().name == element[1]) | (Query().name == element[2])
309 if self.radiobox == 'comment':
310 for x in table.search(query):
312 for text in x['raw'].splitlines(True):
313 for word in self.word.split():
314 if text.find(word) > -1:
315 com = com +'<p style=background-color:yellow>'+text+'<br></p>'
318 com = com+'<p>'+text+'<br></p>'
322 for x in table.search(query):
325 class FooterModule(tornado.web.UIModule):
326 def render(self,number,url,link):
327 return self.render_string('modules/footer.htm',index=number,url=url,link=link)
329 class HeadlineApi(tornado.web.RequestHandler):
332 for x in self.application.db.tables():
334 response[x] = self.get_data(x)
335 self.write(json.dumps(response,ensure_ascii=False))
337 def get_data(self,dbname):
338 table = self.application.db.table(dbname)
343 rec = sorted(table.all(),key=lambda x: x['number'])[i-1]
344 return {'title':rec['title'],'name':rec['name'],'comment':rec['raw'][0:19]}
346 class ArticleApi(tornado.web.RequestHandler):
347 def get(self,dbname,number):
348 if self.application.collection(dbname) == True:
349 table = self.application.db.table(dbname)
350 response = table.get(where('number') == int(number))
355 self.write(json.dumps(response,ensure_ascii=False))
357 tornado.web.HTTPError(404)
359 def post(self,dbname):
360 name = self.get_argument('name',u'誰かさん')
361 title = self.get_argument('title',u'タイトルなし')
362 comment = self.get_argument('comment')
363 table = self.application.db.table(dbname)
364 table.insert({'name':name,'title':title,'comment':comment})
366 class Application(tornado.web.Application):
368 self.db = TinyDB(st.json)
369 handlers = [(r'/',NaviHandler),(r'/login',LoginHandler),(r'/logout',LogoutHandler),(r'/title',TitleHandler),
370 (r'/headline/api',HeadlineApi),(r'/read/api/([a-zA-Z0-9_]+)/([0-9]+)',ArticleApi),(r'/write/api/([a-zA-Z0-9_]+)',ArticleApi),
371 (r'/([a-zA-Z0-9_]+)',IndexHandler),(r'/([a-zA-Z0-9_]+)/([0-9]+)/',IndexHandler),
372 (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),
373 (r'/([a-zA-Z0-9_]+)/search',SearchHandler),(r'/([a-zA-Z0-9_]+)/regist',RegistHandler)]
374 settings = {'template_path':os.path.join(os.path.dirname(__file__),'pybbs'),
375 'static_path':os.path.join(os.path.dirname(__file__),'static'),
376 'ui_modules':{'Footer':FooterModule},
377 'cookie_secret':'bZJc2sWbQLKos6GkHn/VB9oXwQt8SOROkRvJ5/xJ89E=',
382 tornado.web.Application.__init__(self,handlers,**settings)
384 def gpos(self,dbname,page):
385 params = self.db.get(where('kinds') == 'conf')
389 elif (pos-1)*params['count'] >= len(self.db.table(dbname)):
393 def collection(self,name):
394 if name in self.db.tables():
400 json = 'static/db/db.json'
401 bak = 'static/db/bak.json'
404 if __name__ == '__main__':
405 tornado.options.parse_command_line()
406 http_server = tornado.httpserver.HTTPServer(Application())
407 http_server.listen(options.port)
408 tornado.ioloop.IOLoop.instance().start()