OSDN Git Service

commit from git hub
[pybbs/pybbs.git] / index.py
1
2 import os.path
3 import shutil
4 import tornado.escape
5 import tornado.web
6 import tornado.httpserver
7 import tornado.ioloop
8 import tornado.options
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
13
14 define('port',default=8000,help='run on the given port',type=int)
15
16 class BaseHandler(tornado.web.RequestHandler):
17     def get_current_user(self):
18         user = self.get_secure_cookie('admin_user')
19         return tornado.escape.utf8(user)
20     
21     def set_current_user(self,username):
22         self.set_secure_cookie('admin_user',username)
23         
24     def clear_current_user(self):
25         self.clear_cookie('admin_user')
26
27 class IndexHandler(BaseHandler):
28     def get(self,dbname,page='0'):
29         params = self.application.db.get(where('kinds') == 'conf')
30         if params['mentenance'] == True:
31             self.render('mentenance.htm',title=params['title'],db=dbname)
32         if self.application.collection(dbname) == False:
33             if self.current_user == b'admin':
34                 self.application.db.table(dbname)
35             else:
36                 raise tornado.web.HTTPError(404)
37                 return
38         i = params['count']      
39         na = tornado.escape.url_unescape(self.get_cookie("username",u"誰かさん"))
40         pos = self.application.gpos(dbname,page)
41         table = self.application.db.table(dbname)
42         start = (pos-1)*i
43         if start < 0:
44             start = len(table)-i
45             if start < 0:
46                 start = 0
47         rec = sorted(table.all(),key=lambda x: x['number'])[start:start+i]
48         if len(table) >= 10*i:
49             self.render('modules/full.htm',position=pos,records=rec,data=params,db=dbname)
50             return
51         self.render('modules/index.htm',position=pos,records=rec,data=params,username=na,db=dbname)
52         
53 class LoginHandler(BaseHandler):
54     def get(self):
55         self.render('login.htm')
56         
57     def post(self):
58         pw = self.application.db.get(where('kinds') == 'conf')
59         if self.get_argument('password') == pw['password']:
60             self.set_current_user('admin')
61         dbname = self.get_argument('record')
62         self.redirect('/'+dbname+'/admin/0/')
63         
64 class LogoutHandler(BaseHandler):
65     def get(self):
66         self.clear_current_user()
67         self.redirect('/login')
68         
69 class NaviHandler(tornado.web.RequestHandler):
70     def get(self):
71         self.render('top.htm',coll=sorted(self.name()),full=self.full)
72         
73     def name(self):
74         for x in self.application.db.tables():
75             if x != '_default':
76                 yield x
77                 
78     def full(self,dbname):
79         if dbname in self.application.db.tables():
80             i = 10*self.application.db.get(where('kinds') == 'conf')['count']
81             table = self.application.db.table(dbname)
82             if len(table) >= i:
83                 return True
84         return False
85
86 class TitleHandler(NaviHandler):
87     def get(self):
88         rec = sorted(self.title(),key=lambda x: x['date2'])
89         self.render('title.htm',coll=rec,full=self.full)  
90         
91     def title(self):
92         for x in self.name():
93             item = {}
94             item['name'] = x
95             table = self.application.db.table(x)
96             i = len(table)
97             item['count'] = i            
98             if table.contains(where('number') == 1) == True:
99                 s = table.get(where('number') == 1)['title']
100             else:
101                 s = ''
102             item['title'] = s   
103             if i == 0:
104                 item['date'] = ''
105                 item['date2'] = 0
106             else:
107                 rec = sorted(table.all(),key=lambda k: k['number'])
108                 s = rec[i-1]['date']
109                 item['date'] = s
110                 i = datetime.strptime(s,'%Y/%m/%d %H:%M')
111                 year = datetime.now().year-i.year
112                 if year == 0:
113                     j = 800
114                 elif year == 1:
115                     j = 400
116                 else:
117                     j = 0
118                 item['date2'] = j+31*(i.month-1)+i.day
119             yield item
120         
121 class RegistHandler(tornado.web.RequestHandler):
122     def post(self,dbname):
123         if self.application.collection(dbname) == False:
124             raise tornado.web.HTTPError(404)
125             return
126         rec = self.application.db.get(where('kinds') == 'conf')
127         words = rec['bad_words']
128         out = rec['out_words']
129         na = self.get_argument('name',u'誰かさん')
130         sub = self.get_argument('title',u'タイトルなし')
131         com = self.get_argument('comment')
132         text = ''
133         i = 0
134         error = ''
135         for word in out:
136             if word in com:
137                 error = error + u'禁止ワード.'
138                 break
139         for line in com.splitlines(True):
140             for word in words:
141                 if word in line.lower():
142                     error = error + u'タグ違反.('+word+')'       
143             i += len(line)
144             text = text+'<p>'+self.link(line)+'<br></p>'
145         pw = self.get_argument('password')
146         if i == 0:
147             error = error + u'本文がありません.'
148         elif i > 1000:
149             error = error +u'文字数が1,000をこえました.'
150         article = self.application.db.table(dbname)
151         if len(article) == 0:
152             no = 1
153         else:
154             item = sorted(article.all(),key=lambda x: x['number'])[len(article)-1]
155             no = item['number']+1
156         if error == '':
157             s = datetime.now()
158             reg = {'number':no,'name':na,'title':sub,'comment':text,'raw':com,'password':pw,'date':s.strftime('%Y/%m/%d %H:%M')}
159             article.insert(reg)
160             self.set_cookie('username',tornado.escape.url_escape(na))
161             self.redirect('/'+dbname+'#article')
162         else:
163             self.render('regist.htm',content=error)
164     
165     def link(self,command):
166         y = ''
167         i = 0
168         text = ''
169         for x in command.split():
170             if (y == '>>')and(x.isdecimal() == True):
171                 s = '<a href=#'+x+'>'+x+'</a>'
172                 while -1 < command.find(x,i):
173                     j = command.find(x,i)
174                     tmp = command[i:j]
175                     i = j+len(x)
176                     k = tmp.rsplit(None,1)
177                     if ((len(k) > 1)and(k[1] == y))or(k[0] == y):
178                         text = text+tmp+s                                                                       
179                         break
180                     else:
181                         text = text+tmp+x                        
182             y = x    
183         if text == '':
184             return command
185         else:
186             if len(command) > i:
187                 return text+command[i:]
188             else:
189                 return text
190     
191 class AdminHandler(BaseHandler):
192     @tornado.web.authenticated               
193     def get(self,dbname,page='0'):
194         if dbname == '':
195             dbname = self.get_argument('record','')
196         if self.application.collection(dbname) == False:
197             raise tornado.web.HTTPError(404)
198             return
199         table = self.application.db.table(dbname) 
200         rec = sorted(table.all(),key=lambda x: x['number'])                   
201         mente = self.application.db.get(where('kinds') == 'conf')
202         if mente['mentenance'] == True:
203             check = 'checked=checked'
204         else:
205             check = ''
206         pos = self.application.gpos(dbname,page)
207         i = mente['count']
208         start = (pos-1)*i
209         if start < 0:
210             start = len(table)-i
211             if start < 0:
212                 start = 0
213         self.render('modules/admin.htm',position=pos,records=rec[start:start+i],mente=check,password=mente['password'],db=dbname)
214
215 class AdminConfHandler(BaseHandler):
216     @tornado.web.authenticated
217     def post(self,dbname,func):
218         if func == 'set':
219             param = self.application.db.get(where('kinds') == 'conf')['mentenance']
220             if self.get_argument('mente','') == 'on':
221                 mente = True
222                 if param != mente:
223                     self.store()
224             else:
225                 mente = False  
226                 if param != mente:
227                     self.restore()
228             word = self.get_argument('pass','')
229             if word == '':
230                 self.render('regist.htm',content='パスワードを設定してください')
231                 return
232             else:
233                 self.application.db.update({'mentenance':mente,'password':word},where('kinds') == 'conf')  
234         elif func == 'del':
235             table = self.application.db.table(dbname)
236             for x in self.get_arguments('item'):
237                 table.remove(where('number') == int(x))
238         self.redirect('/'+dbname+'/admin/0/')
239         
240     def store(self):
241         self.application.db.close()
242         shutil.copy(st.json,st.bak)
243         self.application.db = TinyDB(st.json)
244         
245     def restore(self):
246         database = self.application.db
247         bak = TinyDB(st.bak)
248         for x in database.tables():
249             if self.application.collection(x) == True:
250                 database.purge_table(x)
251                 if x in bak.tables():
252                     table = database.table(x)
253                     table.insert_multiple(bak.table(x).all())
254           
255 class UserHandler(tornado.web.RequestHandler):
256     def post(self,dbname):
257         num = self.get_argument('number')
258         if num.isdigit() == True:
259             num = int(num)
260             pas = self.get_argument('password')
261             table = self.application.db.table(dbname)
262             qwr = Query()
263             obj = table.get(qwr.number == num)
264             if obj and(obj['password'] == pas):
265                 table.remove(qwr.number == num)
266         self.redirect('/'+dbname)
267       
268 class SearchHandler(tornado.web.RequestHandler):       
269     def post(self,dbname):
270         self.word = tornado.escape.url_unescape(self.get_argument('word1'))
271         self.radiobox = self.get_argument('filter')
272         self.set_cookie('search',tornado.escape.url_escape(self.word))         
273         rec = sorted(self.search(dbname),key=lambda x: x['number'])
274         self.render('modules/search.htm',records=rec,word1=self.word,db=dbname)
275     
276     def get(self,dbname):
277         if self.application.collection(dbname) == False:
278             raise tornado.web.HTTPError(404)
279             return
280         word = self.get_cookie('search','')
281         word = tornado.escape.url_unescape(word)
282         self.render('modules/search.htm',records=[],word1=word,db=dbname)
283         
284     def search(self,dbname):
285         table = self.application.db.table(dbname)    
286         element = self.word.split()
287         if len(element) == 0:
288             element = ['']
289         while len(element) < 3:
290             element.append(element[0])
291         if self.radiobox == 'comment':
292             query = (Query().raw.search(element[0])) | (Query().raw.search(element[1])) | (Query().raw.search(element[2]))
293         else:
294             query = (Query().name == element[0]) | (Query().name == element[1]) | (Query().name == element[2])
295         if self.radiobox == 'comment':    
296             for x in table.search(query):
297                 com = ''
298                 for text in x['raw'].splitlines(True):                  
299                     for word in self.word.split():                        
300                         if text.find(word) > -1:
301                             com = com +'<p style=background-color:yellow>'+text+'<br></p>'  
302                             break                          
303                     else:
304                         com = com+'<p>'+text+'<br></p>'
305                 x['comment'] = com
306                 yield x       
307         else:
308             for x in table.search(query):
309                 yield x
310                                         
311 class FooterModule(tornado.web.UIModule):
312     def render(self,number,url,link):
313         return self.render_string('modules/footer.htm',index=number,url=url,link=link)
314     
315 class Application(tornado.web.Application):    
316     def __init__(self):
317         self.db = TinyDB(st.json)
318         handlers = [(r'/',NaviHandler),(r'/login',LoginHandler),(r'/logout',LogoutHandler),(r'/title',TitleHandler),
319                     (r'/([a-zA-Z0-9_]+)',IndexHandler),(r'/([a-zA-Z0-9_]+)/([0-9]+)/',IndexHandler),
320                     (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),
321                     (r'/([a-zA-Z0-9_]+)/search',SearchHandler),(r'/([a-zA-Z0-9_]+)/regist',RegistHandler)]
322         settings = {'template_path':os.path.join(os.path.dirname(__file__),'pybbs'),
323                         'static_path':os.path.join(os.path.dirname(__file__),'static'),
324                         'ui_modules':{'Footer':FooterModule},
325                         'cookie_secret':'bZJc2sWbQLKos6GkHn/VB9oXwQt8SOROkRvJ5/xJ89E=',
326                         'xsrf_cookies':True,
327                         'debug':True,
328                         'login_url':'/login'
329                         }
330         tornado.web.Application.__init__(self,handlers,**settings)
331  
332     def gpos(self,dbname,page):
333         params = self.db.get(where('kinds') == 'conf')
334         pos = int(page)
335         if pos <= 0:
336             pos = 0
337         elif (pos-1)*params['count'] >= len(self.db.table(dbname)):
338             pos = 0
339         return pos
340     
341     def collection(self,name):
342         if name in self.db.tables():
343             return True
344         else:
345             return False
346
347 class static():
348     json = 'static/db/db.json'
349     bak = 'static/db/bak.json'
350
351 st = static()
352 if __name__ == '__main__':
353     tornado.options.parse_command_line()
354     http_server = tornado.httpserver.HTTPServer(Application())
355     http_server.listen(options.port)
356     tornado.ioloop.IOLoop.instance().start()