anonymous group photoblog software
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

633 lines
19 KiB

  1. import model
  2. import staff_interface
  3. from template import Template
  4. from util import WakaError
  5. from staff_interface import StaffInterface
  6. from staff_tasks import StaffAction
  7. from board import Board
  8. from misc import get_cookie_from_request, kwargs_from_params, make_cookies
  9. from wakapost import WakaPost
  10. def no_task(environ, start_response):
  11. board = environ['waka.board']
  12. start_response('302 Found', [('Location', board.url)])
  13. return []
  14. def init_database():
  15. model.metadata.create_all(model.engine)
  16. # Cache building
  17. def task_rebuild(environ, start_response):
  18. request = environ['werkzeug.request']
  19. kwargs = kwargs_from_params(request,
  20. admin=True,
  21. )
  22. kwargs['board'] = environ['waka.board']
  23. kwargs['action'] = 'rebuild'
  24. return StaffAction(**kwargs).execute()
  25. def task_rebuildglobal(environ, start_response):
  26. request = environ['werkzeug.request']
  27. kwargs = kwargs_from_params(request,
  28. admin=True,
  29. )
  30. kwargs['action'] = 'rebuild_global'
  31. return StaffAction(**kwargs).execute()
  32. # Posting
  33. def task_post(environ, start_response):
  34. request = environ['werkzeug.request']
  35. board = environ['waka.board']
  36. if request.method != 'POST':
  37. raise WakaError("POST only accepted")
  38. cookie = get_cookie_from_request(request, 'wakaadmin')
  39. wakapost = WakaPost.from_request(request)
  40. if wakapost.admin_post:
  41. return StaffAction(cookie, 'admin_post', wakapost=wakapost,
  42. board=board).execute()
  43. # not admin, so let's check for hcaptcha
  44. style_cookie = get_cookie_from_request(request,
  45. board.options.get('STYLE_COOKIE', 'wakastyle'))
  46. hcaptcha = request.values.get('hcaptcha', '').lower()
  47. is_nokosage = wakapost.email.lower() in ['noko', 'sage']
  48. import config
  49. if (config.HCAPTCHA and
  50. hcaptcha != config.HCAPTCHA_ANSWER and
  51. not (config.HCAPTCHA_COOKIE_BYPASS and style_cookie != '') and
  52. not (config.HCAPTCHA_NOKOSAGE_BYPASS and is_nokosage)):
  53. return Template('hcaptcha_failed',
  54. question=config.HCAPTCHA_QUESTION,
  55. answer=config.HCAPTCHA_ANSWER,
  56. )
  57. return board.post_stuff(wakapost)
  58. # Post Deletion
  59. def task_delpostwindow(environ, start_response):
  60. request = environ['werkzeug.request']
  61. board = environ['waka.board']
  62. kwargs = {}
  63. kwargs['post_num'] = request.values.get('num', '')
  64. return board.delete_gateway_window(**kwargs)
  65. def task_delete(environ, start_response, archiving=False):
  66. # TODO review compatibility with wakaba or refactor
  67. request = environ['werkzeug.request']
  68. board = environ['waka.board']
  69. singledelete = (request.values.get("singledelete", '') == 'OK')
  70. formparams = ['password', 'file_only', 'from_window', 'admindelete']
  71. kwargs = kwargs_from_params(request,
  72. form=formparams,
  73. admin=True,
  74. )
  75. if singledelete:
  76. # NOTE: from_window parameter originates from pop-up windows
  77. # brought up by clicking "Delete" without JS enabled.
  78. params_single = ['postpassword', 'postfileonly', 'from_window']
  79. for param, single in map(None, formparams[:3], params_single):
  80. kwargs[param] = request.form.get(single, '')
  81. kwargs['posts'] = [request.values.get('deletepost', '')]
  82. else:
  83. kwargs['posts'] = request.form.getlist('num')
  84. kwargs['archiving'] = archiving
  85. if kwargs['admindelete']:
  86. kwargs['board'] = board
  87. kwargs['action'] = 'admin_delete'
  88. return StaffAction(**kwargs).execute()
  89. del kwargs['cookie']
  90. return board.delete_stuff(**kwargs)
  91. def task_deleteall(environ, start_response):
  92. request = environ['werkzeug.request']
  93. kwargs = kwargs_from_params(request,
  94. form=['ip', 'mask', 'global'],
  95. admin=True,
  96. )
  97. if kwargs.pop('global'):
  98. kwargs['action'] = 'delete_by_ip_global'
  99. else:
  100. kwargs['board'] = environ['waka.board']
  101. kwargs['action'] = 'delete_by_ip'
  102. # Perform action: returns nothing.
  103. StaffAction(**kwargs).execute()
  104. return task_mpanel(environ, start_response)
  105. def task_archive(environ, start_response):
  106. return task_delete(environ, start_response, archiving=True)
  107. # Post Editing
  108. def task_edit(environ, start_response):
  109. request = environ['werkzeug.request']
  110. board = environ['waka.board']
  111. kwargs = kwargs_from_params(request,
  112. form=['num'],
  113. )
  114. kwargs['post_num'] = kwargs.pop('num')
  115. return board.edit_gateway_window(**kwargs)
  116. def task_editpostwindow(environ, start_response):
  117. # This is displayed in a "pop-up window" UI.
  118. environ['waka.fromwindow'] = True
  119. request = environ['werkzeug.request']
  120. board = environ['waka.board']
  121. kwargs = kwargs_from_params(request,
  122. form=['num', 'password', 'admineditmode'],
  123. admin=True,
  124. )
  125. kwargs['admin_mode'] = kwargs.pop('admineditmode')
  126. kwargs['post_num'] = kwargs.pop('num')
  127. return board.edit_window(**kwargs)
  128. def task_editpost(environ, start_response):
  129. request = environ['werkzeug.request']
  130. board = environ['waka.board']
  131. if request.method != 'POST':
  132. raise WakaError("POST only accepted")
  133. cookie = get_cookie_from_request(request, 'wakaadmin')
  134. request_post = WakaPost.from_request(request)
  135. if request_post.admin_post:
  136. return StaffAction(cookie, 'admin_edit', request_post=request_post,
  137. board=board).execute()
  138. else:
  139. return board.edit_stuff(request_post)
  140. def task_report(environ, start_response):
  141. request = environ['werkzeug.request']
  142. board = environ['waka.board']
  143. num = request.form.getlist('num')
  144. from_window = request.values.get('popupwindow', '')
  145. return board.make_report_post_window(num, from_window)
  146. def task_confirmreport(environ, start_response):
  147. request = environ['werkzeug.request']
  148. board = environ['waka.board']
  149. kwargs = kwargs_from_params(request,
  150. form=['num', 'comment', 'referer'],
  151. )
  152. kwargs['posts'] = kwargs.pop('num').split(', ')
  153. return board.report_posts(**kwargs)
  154. def task_resolve(environ, start_response):
  155. request = environ['werkzeug.request']
  156. kwargs = kwargs_from_params(request,
  157. form=['delete'],
  158. admin=True,
  159. )
  160. posts = {}
  161. for post in request.form.getlist('num'):
  162. (board_name, num) = post.split('-')
  163. try:
  164. posts[board_name].append(num)
  165. except KeyError:
  166. posts[board_name] = [num]
  167. kwargs['posts'] = posts
  168. kwargs['action'] = 'report_resolve'
  169. return StaffAction(**kwargs).execute()
  170. def task_restorebackups(environ, start_response):
  171. request = environ['werkzeug.request']
  172. board = environ['waka.board']
  173. kwargs = kwargs_from_params(request,
  174. form=['handle'],
  175. admin=True,
  176. )
  177. kwargs['posts'] = request.form.getlist('num')
  178. kwargs['restore'] = kwargs.pop('handle').lower() == 'restore'
  179. kwargs['board'] = board
  180. kwargs['action'] = 'backup_remove'
  181. return StaffAction(**kwargs).execute()
  182. def _toggle_thread_state(environ, start_response, operation):
  183. request = environ['werkzeug.request']
  184. board = environ['waka.board']
  185. kwargs = kwargs_from_params(request,
  186. admin=True,
  187. )
  188. kwargs['num'] = request.values.get('thread', 0)
  189. kwargs['board'] = board
  190. kwargs['action'] = 'thread_' + operation
  191. return StaffAction(**kwargs).execute()
  192. def task_sticky(environ, start_response):
  193. return _toggle_thread_state(environ, start_response, 'sticky')
  194. def task_unsticky(environ, start_response):
  195. return _toggle_thread_state(environ, start_response, 'unsticky')
  196. def task_lock(environ, start_response):
  197. return _toggle_thread_state(environ, start_response, 'lock')
  198. def task_unlock(environ, start_response):
  199. return _toggle_thread_state(environ, start_response, 'unlock')
  200. # Panels
  201. def task_entersetup(environ, start_response):
  202. request = environ['werkzeug.request']
  203. admin = request.values.get('berra', '')
  204. return staff_interface.make_first_time_setup_page(admin)
  205. def task_setup(environ, start_response):
  206. request = environ['werkzeug.request']
  207. kwargs = kwargs_from_params(request,
  208. form=['admin', 'username', 'password'],
  209. )
  210. return staff_interface.do_first_time_setup(**kwargs)
  211. def task_loginpanel(environ, start_response):
  212. request = environ['werkzeug.request']
  213. kwargs = kwargs_from_params(request,
  214. form=['nexttask', 'nexttask', 'berra', 'desu', 'savelogin'],
  215. cookies=['wakaadminsave'], admin=True,
  216. )
  217. # Why are we doing this again?
  218. kwargs['username'] = kwargs.pop('desu')
  219. kwargs['password'] = kwargs.pop('berra')
  220. # Login saving.
  221. wakaadminsave = kwargs.pop('wakaadminsave')
  222. savelogin = kwargs.pop('savelogin')
  223. kwargs['save_login'] = wakaadminsave or savelogin
  224. return staff_interface.do_login(**kwargs)
  225. task_admin = task_loginpanel
  226. def task_logout(environ, start_response):
  227. request = environ['werkzeug.request']
  228. cookie = get_cookie_from_request(request, 'wakaadmin')
  229. return staff_interface.do_logout(cookie)
  230. def si_task_factory(dest, *form):
  231. '''Factory of task functions for StaffInterface'''
  232. def task(environ, start_response):
  233. request = environ['werkzeug.request']
  234. kwargs = kwargs_from_params(request,
  235. form=form,
  236. admin=True,
  237. )
  238. kwargs['dest'] = getattr(staff_interface, dest)
  239. return StaffInterface(**kwargs)
  240. return task
  241. task_mpanel = si_task_factory('HOME_PANEL', 'page')
  242. task_bans = si_task_factory('BAN_PANEL', 'ip')
  243. task_baneditwindow = si_task_factory('BAN_EDIT_POPUP', 'num')
  244. task_banpopup = si_task_factory('BAN_POPUP', 'ip', 'delete')
  245. task_staff = si_task_factory('STAFF_PANEL')
  246. task_spam = si_task_factory('SPAM_PANEL')
  247. task_reports = si_task_factory('REPORTS_PANEL',
  248. 'page', 'perpage', 'sortby','order')
  249. task_postbackups = si_task_factory('TRASH_PANEL', 'page')
  250. task_sql = si_task_factory('SQL_PANEL', 'sql', 'nuke')
  251. task_proxy = si_task_factory('PROXY_PANEL')
  252. task_security = si_task_factory('SECURITY_PANEL')
  253. task_deleteuserwindow = si_task_factory('DEL_STAFF_CONFIRM', 'username')
  254. task_disableuserwindow = si_task_factory('DISABLE_STAFF_CONFIRM', 'username')
  255. task_enableuserwindow = si_task_factory('ENABLE_STAFF_CONFIRM', 'username')
  256. task_edituserwindow = si_task_factory('EDIT_STAFF_CONFIRM', 'username')
  257. task_searchposts = si_task_factory('POST_SEARCH_PANEL',
  258. 'search', 'caller', 'text')
  259. task_deleteall_confirm = si_task_factory('DELETE_ALL_CONFIRM',
  260. 'ip', 'mask', 'global')
  261. def task_addip(environ, start_response):
  262. request = environ['werkzeug.request']
  263. kwargs = kwargs_from_params(request,
  264. form=['type', 'comment', 'ip', 'mask', 'total', 'expiration'],
  265. admin=True,
  266. )
  267. kwargs['option'] = kwargs.pop('type')
  268. kwargs['action'] = 'admin_entry'
  269. return StaffAction(**kwargs).execute()
  270. def task_addipfrompopup(environ, start_response):
  271. request = environ['werkzeug.request']
  272. board = environ['waka.board']
  273. kwargs = kwargs_from_params(request,
  274. form=['ip', 'mask', 'total', 'expiration', 'comment', 'delete',
  275. 'deleteall_confirm', 'globaldeleteall_confirm'],
  276. admin=True,
  277. )
  278. kwargs['action'] = 'admin_entry'
  279. kwargs['option'] = 'ipban'
  280. kwargs['caller'] = 'window'
  281. delete = kwargs.pop('delete')
  282. delete_all = kwargs.pop('deleteall_confirm')
  283. globaldelete_all = kwargs.pop('globaldeleteall_confirm')
  284. try:
  285. if globaldelete_all:
  286. StaffAction(kwargs['cookie'], 'delete_by_ip_global',
  287. ip=kwargs['ip'], caller='internal').execute()
  288. elif delete_all:
  289. StaffAction(kwargs['cookie'], 'delete_by_ip',
  290. ip=kwargs['ip'], board=board).execute()
  291. elif delete:
  292. StaffAction(kwargs['cookie'], 'admin_delete', board=board,
  293. posts=[delete], from_window=True, password='',
  294. file_only=False, archiving=False, caller='internal')\
  295. .execute()
  296. except WakaError:
  297. pass
  298. make_cookies(ban_mask=kwargs['mask'], ban_expiration=kwargs['expiration'],
  299. ban_comment=kwargs['comment'])
  300. return StaffAction(**kwargs).execute()
  301. def task_addstring(environ, start_response):
  302. request = environ['werkzeug.request']
  303. kwargs = kwargs_from_params(request,
  304. form=['type', 'string', 'comment'],
  305. admin=True,
  306. )
  307. kwargs['action'] = 'admin_entry'
  308. kwargs['option'] = kwargs.pop('type')
  309. kwargs['sval1'] = kwargs.pop('string')
  310. return StaffAction(**kwargs).execute()
  311. def task_adminedit(environ, start_response):
  312. request = environ['werkzeug.request']
  313. kwargs = kwargs_from_params(request,
  314. form=['num', 'ival1', 'ival2', 'sval1', 'total', 'year',
  315. 'month', 'day', 'hour', 'min', 'sec', 'comment',
  316. 'noexpire'],
  317. admin=True,
  318. )
  319. kwargs['action'] = 'edit_admin_entry'
  320. return StaffAction(**kwargs).execute()
  321. def task_removeban(environ, start_response):
  322. request = environ['werkzeug.request']
  323. kwargs = kwargs_from_params(request,
  324. form=['num'],
  325. admin=True,
  326. )
  327. kwargs['action'] = 'remove_admin_entry'
  328. return StaffAction(**kwargs).execute()
  329. def task_addproxy(environ, start_response):
  330. request = environ['werkzeug.request']
  331. kwargs = kwargs_from_params(request,
  332. form=['type', 'ip', 'timestamp'],
  333. admin=True,
  334. )
  335. kwargs['action'] = 'add_proxy_entry'
  336. return StaffAction(**kwargs).execute()
  337. def task_removeproxy(environ, start_response):
  338. request = environ['werkzeug.request']
  339. kwargs = kwargs_from_params(request,
  340. form=['num'],
  341. admin=True,
  342. )
  343. kwargs['action'] = 'remove_proxy_entry'
  344. return StaffAction(**kwargs).execute()
  345. # Interboard management.
  346. def task_updatespam(environ, start_response):
  347. request = environ['werkzeug.request']
  348. kwargs = kwargs_from_params(request,
  349. form=['spam'],
  350. admin=True,
  351. )
  352. kwargs['action'] = 'update_spam'
  353. return StaffAction(**kwargs).execute()
  354. def task_createuser(environ, start_response):
  355. request = environ['werkzeug.request']
  356. kwargs = kwargs_from_params(request,
  357. form=['mpass', 'usertocreate', 'passtocreate', 'account', 'reign'],
  358. admin=True,
  359. )
  360. kwargs['reign'] = kwargs.pop('reign').split(',')
  361. return staff_interface.add_staff_proxy(**kwargs)
  362. def task_deleteuser(environ, start_response):
  363. request = environ['werkzeug.request']
  364. kwargs = kwargs_from_params(request,
  365. form=['mpass', 'username'],
  366. admin=True,
  367. )
  368. return staff_interface.del_staff_proxy(**kwargs)
  369. def task_disableuser(environ, start_response):
  370. request = environ['werkzeug.request']
  371. kwargs = kwargs_from_params(request,
  372. form=['mpass', 'username'],
  373. admin=True,
  374. )
  375. kwargs['disable'] = True
  376. return staff_interface.edit_staff_proxy(**kwargs)
  377. def task_enableuser(environ, start_response):
  378. request = environ['werkzeug.request']
  379. kwargs = kwargs_from_params(request,
  380. form=['mpass', 'username'],
  381. admin=True,
  382. )
  383. kwargs['disable'] = False
  384. return staff_interface.edit_staff_proxy(**kwargs)
  385. def task_edituser(environ, start_response):
  386. request = environ['werkzeug.request']
  387. kwargs = kwargs_from_params(request,
  388. form=['mpass', 'usernametoedit', 'newpassword', 'newclass',
  389. 'originalpassword'],
  390. admin=True,
  391. )
  392. kwargs['username'] = kwargs.pop('usernametoedit')
  393. kwargs['reign'] = request.form.getlist('reign')
  394. return staff_interface.edit_staff_proxy(**kwargs)
  395. def task_move(environ, start_response):
  396. request = environ['werkzeug.request']
  397. kwargs = kwargs_from_params(request,
  398. admin=True
  399. )
  400. kwargs['parent'] = request.values.get('num', '')
  401. kwargs['src_brd_obj'] = environ['waka.board']
  402. kwargs['dest_brd_obj'] = Board(request.values.get('destboard', ''))
  403. kwargs['action'] = 'thread_move'
  404. return StaffAction(**kwargs).execute()
  405. def task_stafflog(environ, start_response):
  406. request = environ['werkzeug.request']
  407. kwargs = kwargs_from_params(request,
  408. form=['sortby', 'order', 'iptoview', 'view', 'perpage',
  409. 'page', 'actiontoview', 'posttoview', 'usertoview'],
  410. admin=True,
  411. )
  412. kwargs['sortby_name'] = kwargs.pop('sortby')
  413. kwargs['sortby_dir'] = kwargs.pop('order')
  414. kwargs['ip_to_view'] = kwargs.pop('iptoview')
  415. kwargs['post_to_view'] = kwargs.pop('posttoview')
  416. kwargs['action_to_view'] = kwargs.pop('actiontoview')
  417. kwargs['user_to_view'] = kwargs.pop('usertoview')
  418. kwargs['dest'] = staff_interface.STAFF_ACTIVITY_PANEL
  419. return StaffInterface(**kwargs)
  420. # Error-handling
  421. def error(environ, start_response, error=None):
  422. message = error.message if error else 'Unhandled exception'
  423. if not (error and error.plain):
  424. mini = '_mini' if environ['waka.fromwindow'] else ''
  425. try:
  426. return Template('error_template' + mini, error=message)
  427. except:
  428. # if for some reason we can't render templates,
  429. # fallback to text/plain error reporting
  430. pass
  431. environ['waka.headers']['Content-Type'] = 'text/plain'
  432. return [str(message)]
  433. # Initial setup
  434. def check_setup(environ, start_response):
  435. import os, config
  436. import interboard
  437. from template import TEMPLATES_DIR, CACHE_DIR
  438. issues = []
  439. ENV_CHECKS = ['DOCUMENT_ROOT', 'SCRIPT_NAME', 'SERVER_NAME']
  440. MISSING_ENV = [x for x in ENV_CHECKS if x not in environ]
  441. if MISSING_ENV:
  442. return ['Environment not complete. Missing: %s\n' %
  443. ', '.join(MISSING_ENV)]
  444. full_board_dir = os.path.join(environ['DOCUMENT_ROOT'], config.BOARD_DIR)
  445. if not os.access(full_board_dir, os.W_OK):
  446. issues.append("No write access to DOCUMENT_ROOT+BOARD_DIR (%s)" %
  447. full_board_dir)
  448. include_dir = os.path.join(environ['DOCUMENT_ROOT'],
  449. config.BOARD_DIR, "include")
  450. if not os.access(include_dir, os.F_OK | os.R_OK):
  451. issues.append("No read access to includes dir (%s). Wrong BOARD_DIR?" %
  452. include_dir)
  453. script_name_dir = os.path.join(environ['DOCUMENT_ROOT'],
  454. os.path.dirname(environ['SCRIPT_NAME']).lstrip("/"))
  455. if not os.access(script_name_dir, os.W_OK):
  456. issues.append("No write access to DOCUMENT_ROOT+SCRIPT_NAME dir (%s)" %
  457. script_name_dir)
  458. templates_dir = os.path.abspath(TEMPLATES_DIR)
  459. if not os.access(templates_dir, os.W_OK):
  460. issues.append("No write access to templates dir (%s)" % templates_dir)
  461. cache_dir = os.path.abspath(CACHE_DIR)
  462. if not os.access(cache_dir, os.W_OK):
  463. issues.append("No write access to templates cache dir (%s)" % cache_dir)
  464. try:
  465. model.metadata.create_all(model.engine)
  466. interboard.remove_old_bans()
  467. interboard.remove_old_backups()
  468. except model.OperationalError, e:
  469. issues.append("Error writing to database: %s" % e.args[0])
  470. if issues:
  471. return ["<p>Setup issues found:</p> <ul>"] + \
  472. ["<li>%s</li>\n" % x for x in issues] + ["</ul>"]
  473. elif model.Session().query(model.account).count() == 0:
  474. return Template("first_time_setup")
  475. else:
  476. return ["Nothing to do."]