Advertisement
Guest User

Untitled

a guest
Mar 5th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 27.67 KB | None | 0 0
  1. diff --git a/board.py b/board.py
  2. index 30814be..48dab6d 100644
  3. --- a/board.py
  4. +++ b/board.py
  5. @@ -4,13 +4,16 @@ import time
  6.  import random
  7.  import hashlib
  8.  from subprocess import Popen, PIPE
  9. -from urllib import quote_plus, urlencode
  10. +from urllib import quote_plus
  11.  
  12.  import misc
  13.  import str_format
  14.  import oekaki
  15.  import util
  16.  import model
  17. +import staff
  18. +# NOTE: I'm not sure if interboard is a good module to have here.
  19. +import interboard
  20.  import config, config_defaults
  21.  import strings as strings
  22.  from util import WakaError, local
  23. @@ -78,6 +81,13 @@ class Board(object):
  24.          else:
  25.              return os.path.join(base, dir) + hash
  26.  
  27. +    def check_access(self, admin):
  28. +        user = staff.check_password(admin)
  29. +        if user.account == staff.MODERATOR and self.name not in user.reign:
  30. +            raise WakaError('Access to this board (%s) denied.' % board.name)
  31. +
  32. +        return user
  33. +
  34.      def make_url(self, **kwargs):
  35.          '''Alias for make_path to build urls'''
  36.          kwargs['url'] = True
  37. @@ -107,6 +117,38 @@ class Board(object):
  38.  
  39.          return threads
  40.  
  41. +    def get_some_threads(self, page):
  42. +        '''Grab a partial list of threads for pre-emptive pagination.'''
  43. +
  44. +        session = model.Session()
  45. +        table = self.table
  46. +        thread_dict = {}
  47. +        thread_nums = []
  48. +
  49. +        # Query 1: Grab all thread (OP) entries.
  50. +        op_sql = table.select().where(table.c.parent == 0).order_by(
  51. +                    table.c.stickied.desc(),
  52. +                    table.c.lasthit.desc(),
  53. +                    table.c.num.asc()
  54. +                )
  55. +        op_query = session.execute(op_sql)
  56. +
  57. +        for op in op_query:
  58. +            thread_dict[op.num] = [model.CompactPost(op)]
  59. +            thread_nums.append(op.num)
  60. +
  61. +        # Query 2: Grab all reply entries and process.
  62. +        reply_sql = table.select().where(table.c.parent.in_(thread_nums))\
  63. +                    .order_by(table.c.stickied.desc(),
  64. +                        table.c.num.asc()
  65. +                    )
  66. +        reply_query = session.execute(reply_sql)
  67. +
  68. +        for post in reply_query:
  69. +            thread_dict[post.parent].append(model.CompactPost(post))
  70. +
  71. +        return [thread_dict[num] for num in thread_nums]
  72. +
  73.      def build_cache(self):
  74.          threads = self._get_all_threads()
  75.          
  76. @@ -124,10 +166,7 @@ class Board(object):
  77.              os.unlink(self.make_path(page=page))
  78.              page += 1
  79.  
  80. -    def build_cache_page(self, page, total, pagethreads):
  81. -        '''Build $rootpath/$board/$page.html'''
  82. -        filename = self.make_path(page=page)
  83. -        
  84. +    def parse_page_threads(self, pagethreads):
  85.          threads = []
  86.          for postlist in pagethreads:
  87.              if len(postlist) == 0:
  88. @@ -168,7 +207,10 @@ class Board(object):
  89.                      post.comment = abbreviation
  90.  
  91.              threads.append(thread)
  92. -        
  93. +      
  94. +        return threads
  95. +
  96. +    def get_board_page_data(self, page, total):
  97.          pages = []
  98.          for i in xrange(total):
  99.              p = {}
  100. @@ -176,13 +218,27 @@ class Board(object):
  101.              p['filename'] = self.make_url(page=i)
  102.              p['current'] = page == i
  103.              pages.append(p)
  104. -        
  105.          prevpage = nextpage = None
  106. +
  107.          if page != 0:
  108.              prevpage = pages[page - 1]['filename']
  109.          if page != total - 1:
  110.              nextpage = pages[page + 1]['filename']
  111.  
  112. +        return (pages, prevpage, nextpage)
  113. +
  114. +    def build_cache_page(self, page, total, pagethreads):
  115. +        '''Build $rootpath/$board/$page.html'''
  116. +
  117. +        # Receive contents.
  118. +        threads = self.parse_page_threads(pagethreads)
  119. +
  120. +        # Calculate page link data.
  121. +        (pages, prevpage, nextpage) = self.get_board_page_data(page, total)
  122. +
  123. +        # Generate filename and links to other pages.
  124. +        filename = self.make_path(page=page)
  125. +
  126.          Template('page_template',
  127.              pages=pages,
  128.              postform=self.options['ALLOW_TEXTONLY'] \
  129. @@ -195,9 +251,7 @@ class Board(object):
  130.              threads=threads,
  131.          ).render_to_file(filename)
  132.  
  133. -    def build_thread_cache(self, threadid):
  134. -        '''Build $rootpath/$board/$res/$threadid.html'''
  135. -
  136. +    def get_thread_posts(self, threadid):
  137.          session = model.Session()
  138.          sql = self.table.select(
  139.              or_(
  140. @@ -214,6 +268,13 @@ class Board(object):
  141.          if thread[0].parent:
  142.              raise WakaError(strings.NOTHREADERR)
  143.  
  144. +        return thread
  145. +
  146. +    def build_thread_cache(self, threadid):
  147. +        '''Build $rootpath/$board/$res/$threadid.html'''
  148. +
  149. +        thread = self.get_thread_posts(threadid)
  150. +
  151.          filename = os.path.join(self.path, self.options['RES_DIR'],
  152.              "%s%s" % (threadid, config.PAGE_EXT))
  153.  
  154. @@ -252,10 +313,42 @@ class Board(object):
  155.              if os.path.exists(abbreviated_filename):
  156.                  os.unlink(abbreviated_filename)
  157.  
  158. -    def delete_thread_cache(self, parent):
  159. +    def delete_thread_cache(self, parent, archiving):
  160. +        archive_dir = self.options['ARCHIVE_DIR']
  161. +
  162.          base = os.path.join(self.path, self.options['RES_DIR'], '')
  163. -        full_thread_page = base + "%s%s" % (parent, config.PAGE_EXT)
  164. +        full_filename = "%s%s" % (parent, config.PAGE_EXT)
  165. +        full_thread_page = base + full_filename
  166.          abbrev_thread_page = base + "%s_abbr%s" % (parent, config.PAGE_EXT)
  167. +        if archiving:
  168. +            archive_base = os.path.join(self.path,
  169. +                                        self.options['ARCHIVE_DIR'],
  170. +                                        self.options['RES_DIR'], '')
  171. +            try:
  172. +                os.makedirs(archive_base, 0664)
  173. +            except os.error:
  174. +                pass
  175. +            archive_thread_page = archive_base + full_filename
  176. +
  177. +            with open(full_thread_page, 'r') as res_in:
  178. +                with open(archive_thread_page, 'w') as res_out:
  179. +                    for line in res_in:
  180. +                        # Update image links.
  181. +                        line = re.sub(r'img src="(.*?)'
  182. +                                          + self.options['THUMB_DIR'],
  183. +                                      r'img src="'
  184. +                                          + archive_dir
  185. +                                          + self.options['THUMB_DIR'],
  186. +                                      line)
  187. +                        # Update thread reply links.
  188. +                        line = re.sub(r'a href="(.*?)'
  189. +                                          + self.options['SRC_DIR'],
  190. +                                      r'a href="'
  191. +                                          + archive_dir
  192. +                                          + self.options['SRC_DIR'],
  193. +                                      line)
  194. +                        res_out.write(line)
  195. +                
  196.          if os.path.exists(full_thread_page):
  197.              os.unlink(full_thread_page)
  198.          if os.path.exists(abbrev_thread_page):
  199. @@ -269,7 +362,7 @@ class Board(object):
  200.          for row in query:
  201.              self.build_thread_cache(row[0])
  202.  
  203. -    def __handle_post(self, name, email, subject, comment, file,
  204. +    def _handle_post(self, name, email, subject, comment, file,
  205.                        password, nofile, captcha, admin, no_captcha,
  206.                        no_format, oekaki_post, srcinfo, pch, sticky, lock,
  207.                        admin_post_mode, post_num=None, killtrip=False,
  208. @@ -284,14 +377,14 @@ class Board(object):
  209.  
  210.          # Other automatically determined variables.
  211.          trip = ''
  212. -        date = lastedit = ''
  213. +        date = lastedit = lasthit = ''
  214.          post_ip = lastedit_ip = ''
  215.          filename = thumbnail = md5 = ''
  216.          size = width = height = tn_width = tn_height = 0
  217.  
  218.          # Initialize admin_post variable--tells whether or not this post has
  219.          # fallen under the hand of a mod/admin
  220. -        admin_post = False
  221. +        admin_post = ''
  222.  
  223.          # check that the request came in as a POST, or from the command line
  224.          if local.environ.get('REQUEST_METHOD', '') != 'POST':
  225. @@ -306,7 +399,7 @@ class Board(object):
  226.              if original_row == None:
  227.                  raise WakaError('Post not found') # TODO
  228.                  
  229. -            if password != original_row['password']:
  230. +            if not admin_post_mode and password != original_row['password']:
  231.                  raise WakaError('Wrong password for editing') # TODO
  232.  
  233.              parent = original_row['parent']
  234. @@ -320,6 +413,7 @@ class Board(object):
  235.              timestamp = original_row['timestamp']
  236.              post_ip = original_row['ip']
  237.              size = original_row['size']
  238. +            lasthit = original_row['lasthit']
  239.              if not killtrip:
  240.                  trip = original_row['trip']
  241.  
  242. @@ -341,8 +435,10 @@ class Board(object):
  243.  
  244.          # check admin password - allow both encrypted and non-encrypted
  245.          if admin_post_mode:
  246. -            username, accounttype = misc.check_password(admin, 'mpost')
  247. -            admin_post = True
  248. +            user = self.check_access(admin)
  249. +            username = user.username
  250. +            accounttype = user.account
  251. +            admin_post = 'yes'
  252.          else:
  253.              if no_captcha or no_format or (sticky and not parent) or lock:
  254.                  raise WakaError(strings.WRONGPASS)
  255. @@ -367,10 +463,10 @@ class Board(object):
  256.  
  257.          if lock:
  258.              if parent:
  259. -                threadupdate = threadupdate.values(locked=True)
  260. -            lock = True
  261. +                threadupdate = threadupdate.values(locked='yes')
  262. +            lock = 'yes'
  263.          else:
  264. -            lock = False
  265. +            lock = ''
  266.  
  267.          if (sticky or lock) and parent:
  268.              session.execute(threadupdate)
  269. @@ -397,7 +493,7 @@ class Board(object):
  270.              raise WakaError(strings.TOOLONG)
  271.  
  272.          # check to make sure the user selected a file, or clicked the checkbox
  273. -        if not parent and not file and not nofile:
  274. +        if not post_num and parent and not file and not nofile:
  275.              raise WakaError(strings.NOPIC)
  276.  
  277.          # check for empty reply or empty text-only post
  278. @@ -434,7 +530,7 @@ class Board(object):
  279.  
  280.          if not whitelisted:
  281.              # check for bans
  282. -            misc.ban_check(numip, c_name, subject, comment)
  283. +            interboard.ban_check(numip, c_name, subject, comment)
  284.  
  285.              trap_fields = []
  286.              if self.options['SPAM_TRAP']:
  287. @@ -450,14 +546,15 @@ class Board(object):
  288.              misc.proxy_check(ip)
  289.  
  290.          # check if thread exists, and get lasthit value
  291. -        parent_res = lasthit = ''
  292. -        if parent:
  293. -            parent_res = self.get_parent_post(parent)
  294. -            if not parent_res:
  295. -                raise WakaError(strings.NOTHREADERR)
  296. -            lasthit = parent_res.lasthit
  297. -        else:
  298. -            lasthit = timestamp
  299. +        parent_res = ''
  300. +        if not post_num:
  301. +            if parent:
  302. +                parent_res = self.get_parent_post(parent)
  303. +                if not parent_res:
  304. +                    raise WakaError(strings.NOTHREADERR)
  305. +                lasthit = parent_res.lasthit
  306. +            else:
  307. +                lasthit = timestamp
  308.  
  309.          # kill the name if anonymous posting is being enforced
  310.          if self.options['FORCED_ANON']:
  311. @@ -492,17 +589,15 @@ class Board(object):
  312.          comment = comment or self.options['S_ANOTEXT']
  313.  
  314.          # flood protection - must happen after inputs have been cleaned up
  315. -        misc.flood_check(numip, timestamp, comment, file, 1, 0)
  316. +        interboard.flood_check(numip, timestamp, comment, file, True, False)
  317.  
  318.          # Manager and deletion stuff - duuuuuh?
  319.  
  320.          # generate date
  321.          if not post_num:
  322. -            date = misc.make_date(timestamp + config.TIME_OFFSET,
  323. -                                  self.options['DATE_STYLE'])
  324. +            date = misc.make_date(timestamp, self.options['DATE_STYLE'])
  325.          else:
  326. -            lastedit = misc.make_date(timestamp + config.TIME_OFFSET,
  327. -                                  self.options['DATE_STYLE'])
  328. +            lastedit = misc.make_date(timestamp, self.options['DATE_STYLE'])
  329.  
  330.          # generate ID code if enabled
  331.          if self.options['DISPLAY_ID']:
  332. @@ -552,13 +647,13 @@ class Board(object):
  333.  
  334.          # TODO: Make a keyword dictionary for this?...
  335.          db_update = db_update_function().values(parent=parent,
  336. -            timestamp=timestamp, lasthit=lasthit, ip=post_ip, date=date,
  337. +            timestamp=timestamp, ip=post_ip, date=date,
  338.              name=name, trip=trip, email=email, subject=subject,
  339.              password=password, comment=comment, image=filename, size=size,
  340.              md5=md5, width=width, height=height, thumbnail=thumbnail,
  341.              tn_width=tn_width, tn_height=tn_height, admin_post=admin_post,
  342.              stickied=sticky, locked=lock, lastedit_ip=lastedit_ip,
  343. -            lastedit=lastedit)
  344. +            lasthit=lasthit, lastedit=lastedit)
  345.  
  346.          # finally, write to the database
  347.          result = None
  348. @@ -592,17 +687,18 @@ class Board(object):
  349.          else: # new thread, id is in num
  350.              if admin_post_mode:
  351.                  # TODO add_log_entry not implemented
  352. -                add_log_entry(username, 'admin_post',
  353. -                    '%s,%s' % (self.name, post_num),
  354. -                    date, numip, 0, timestamp)
  355. +                # add_log_entry(username, 'admin_post',
  356. +                #    '%s,%s' % (self.name, post_num),
  357. +                #    date, numip, 0, timestamp)
  358. +                pass
  359.              if post_num == 1:
  360.                  # If this is the first post on a board recently cleared
  361.                  # of posts, the post count will reset; so should our
  362.                  # reports, then.
  363. -                # TODO init_report_database not implemented
  364. -                # TODO maybe it shouldn't be implemented
  365. -                #init_report_database()
  366. -                pass
  367. +                report_table = model.report
  368. +                sql = report_table.delete()\
  369. +                    .where(report_table.c.board == self.name)
  370. +                session.execute(sql)
  371.  
  372.              self.build_thread_cache(post_num)
  373.  
  374. @@ -617,7 +713,7 @@ class Board(object):
  375.                     no_format, oekaki_post, srcinfo, pch, sticky, lock,
  376.                     admin_post_mode):
  377.      
  378. -        post_num = self.__handle_post(name, email, subject, comment,
  379. +        post_num = self._handle_post(name, email, subject, comment,
  380.                                        file, password, nofile, captcha, admin,
  381.                                        no_captcha, no_format, oekaki_post,
  382.                                        srcinfo, pch, sticky, lock,
  383. @@ -663,12 +759,12 @@ class Board(object):
  384.          # end of this function. fuck yeah
  385.  
  386.      def edit_gateway_window(self, post_num, admin_post):
  387. -        return self.__gateway_window(post_num, 'edit', admin_post=admin_post)
  388. +        return self._gateway_window(post_num, 'edit', admin=admin_post)
  389.  
  390.      def delete_gateway_window(self, post_num):
  391. -        return self.__gateway_window(post_num, 'delete')
  392. +        return self._gateway_window(post_num, 'delete')
  393.  
  394. -    def __gateway_window(self, post_num, task, admin_post=None):
  395. +    def _gateway_window(self, post_num, task, admin_post=''):
  396.          if not post_num.isdigit():
  397.              raise WakaError('Please enter post number.') # TODO
  398.  
  399. @@ -677,23 +773,46 @@ class Board(object):
  400.          else:
  401.              return Template('delpassword', num=post_num)
  402.  
  403. +    def get_local_reports(self):
  404. +        session = model.Session()
  405. +        table = model.report
  406. +        sql = table.select().where(and_(table.c.board == self.name,
  407. +                                        table.c.resolved == 0))
  408. +        query = session.execute(sql).fetchall()
  409. +        reported_posts = [dict(row.items()) for row in query]
  410. +
  411. +        rowtype = 1
  412. +        for row in reported_posts:
  413. +            rowtype ^= 0x3
  414. +            row['rowtype'] = rowtype
  415. +
  416. +        return reported_posts
  417. +
  418.      def delete_stuff(self, posts, password, file_only, archiving,
  419. -                     from_window):
  420. +                     caller='user', from_window=False, admin=''):
  421. +        if admin:
  422. +            check_access(admin)
  423. +
  424.          for post in posts:
  425.              self.delete_post(post, password, file_only, archiving,
  426. -                             from_window)
  427. +                             from_window=False, admin=admin)
  428.  
  429.          self.build_cache()
  430.  
  431. -        forward = self.make_path(page=0, url=True)
  432. -        return util.make_http_forward(forward, config.ALTERNATE_REDIRECT)
  433. +        if admin:
  434. +            forward = '%s?task=mpanel&board=%s'\
  435. +                      % (misc.get_secure_script_name(), self.name)
  436. +        else:
  437. +            forward = self.make_path(page=0, url=True)
  438. +        if caller == 'user':
  439. +            return util.make_http_forward(forward, config.ALTERNATE_REDIRECT)
  440.  
  441. -    def delete_post(self, post, password, file_only, archiving, from_window):
  442. +    def delete_post(self, post, password, file_only, archiving,
  443. +                    from_window=False, admin=False):
  444.          '''Delete a single post from the board. This method does not rebuild
  445.          index cache automatically.'''
  446. -        # TODO: Add archiving-related stuff.
  447.          thumb = self.options['THUMB_DIR']
  448. -        # archive = self.options['ARCHIVE']
  449. +        archive = self.options['ARCHIVE_DIR']
  450.          src = self.options['IMG_DIR']
  451.  
  452.          table = self.table
  453. @@ -707,10 +826,15 @@ class Board(object):
  454.          if row is None:
  455.              raise WakaError(strings.POSTNOTFOUND % (post, self.board))
  456.  
  457. -        if password and row.admin_post:
  458. -            raise WakaError(strings.MODDELETEONLY)
  459. +        if password:
  460. +            archiving = False
  461.  
  462. -        if password != row.password:
  463. +            if row.admin_post:
  464. +                raise WakaError(strings.MODDELETEONLY)
  465. +
  466. +            if password != row.password:
  467. +                raise WakaError(post + strings.BADDELPASS)
  468. +        elif not admin:
  469.              raise WakaError(post + strings.BADDELPASS)
  470.  
  471.          if file_only:
  472. @@ -728,7 +852,8 @@ class Board(object):
  473.              
  474.              for i in images_to_baleet:
  475.                  if i.image and i.thumbnail:
  476. -                    self.delete_file(i.image, i.thumbnail)
  477. +                    self.delete_file(i.image, i.thumbnail,
  478. +                                     archiving=archiving)
  479.  
  480.              delete_query = table.delete(or_(
  481.                  table.c.num == post,
  482. @@ -736,28 +861,129 @@ class Board(object):
  483.              session.execute(delete_query)
  484.  
  485.          if not row.parent:
  486. -            if not file_only:
  487. -                # removing an entire thread
  488. -                self.delete_thread_cache(post)
  489. -            else:
  490. +            if file_only:
  491.                  # removing parent (OP) image
  492.                  self.build_thread_cache(post)
  493. +            else:
  494. +                # removing an entire thread
  495. +                self.delete_thread_cache(post, archiving)
  496.          else:
  497.              # removing a reply, or a reply's image
  498.              self.build_thread_cache(row.parent)
  499.  
  500. -    def delete_file(self, relative_file_path, relative_thumb_path):
  501. -        # TODO: Add archiving-related stuff.
  502. +    def delete_file(self, relative_file_path, relative_thumb_path,
  503. +                    archiving=False):
  504.          # pch = oekaki.find_pch(row.image)
  505.          full_file_path = os.path.join(self.path, relative_file_path)
  506.          full_thumb_path = os.path.join(self.path, relative_thumb_path)
  507.          if os.path.exists(full_file_path):
  508. -            os.unlink(full_file_path)
  509. +            if archiving:
  510. +                os.renames(full_file_path, '')
  511. +            else:
  512. +                os.unlink(full_file_path)
  513.          if os.path.exists(full_thumb_path) and \
  514.             re.match(self.options['THUMB_DIR'], full_thumb_path):
  515. -            os.unlink(full_thumb_path)
  516. +            if archiving:
  517. +                os.renames(full_thumb_path)
  518. +            else:
  519. +                os.unlink(full_thumb_path)
  520. +
  521. +    def make_report_post_window(posts, from_window=False):
  522. +        if len(posts) == 0:
  523. +            raise WakaError('No posts selected.')
  524. +        if len(num) > 10:
  525. +            raise WakaError('Too many posts. Try reporting the thread ' \
  526. +                            + 'or a single post in the case of floods.')
  527. +
  528. +        num_parsed = ', '.posts
  529. +        referer = ''
  530. +        if not from_window:
  531. +            referer = environ['HTTP_REFERER']
  532. +
  533. +        return Template('post_report_window', num=num_parsed, referer=referer)
  534. +
  535. +    def report_posts(self, comment, referer, posts):
  536. +        numip = misc.dot_to_dec(environ['REMOTE_ADDR'])
  537. +
  538. +        # Sanity checks.
  539. +        if not comment:
  540. +            raise WakaError('Please input a comment.')
  541. +        if len(comment) > config.REPORT_COMMENT_MAX_LENGTH:
  542. +            raise WakaError('Comment is too long.')
  543. +        if len(comment) < 3:
  544. +            raise WakaError('Comment is too short.')
  545. +        if len(posts) > 10:
  546. +            raise WakaError('Too many posts. Try reporting the thread or a '\
  547. +                            + 'single post in the case of floods.')
  548. +
  549. +        # Access checks.
  550. +        whitelisted = misc.is_whitelisted(numip)
  551. +        if not whitelisted:
  552. +            interboard.ban_check(numip, '', '', '')
  553. +        interboard.flood_check(numip, time.time(), comment, '', False, True);
  554. +
  555. +        # Clear up the backlog.
  556. +        interboard.trim_reported_posts()
  557. +
  558. +        comment = str_format.format_comment(str_format.clean_string(
  559. +                str_format.decode_string(comment)))
  560. +
  561. +        session = model.Session()
  562. +        reports_table = model.report
  563. +
  564. +        # Handle errors individually rather than cancelling operation.
  565. +        errors = []
  566. +
  567. +        for post in posts:
  568. +            if not post.isdigit():
  569. +                errors.append({'error' : '%s: Invalid post number.' % (post)})
  570. +                continue
  571. +
  572. +            sql = select([self.table.c.ip], self.table.c.num == post,
  573. +                         self.table)
  574. +            post_row = session.execute(sql).fetchone()
  575. +        
  576. +            if not post_row:
  577. +                errors.append({'error' \
  578. +                    : '%s: Post not found (likely deleted).' % (post) })
  579. +                continue
  580. +
  581. +            # Store offender IP in case this post is deleted later.
  582. +            offender_ip = post_row.ip
  583. +
  584. +            sql = reports_table.select()\
  585. +                .where(and_(reports_table.c.postnum == post,
  586. +                            reports_table.c.board == self.name))
  587. +            report_row = session.execute
  588. +
  589. +            if report_row:
  590. +                if report_row.resolved:
  591. +                    errors.append({'error' : '%s: Already resolved.' \
  592. +                                             % (post)})
  593. +                else:
  594. +                    errors.append({'error' : '%s: Already reported.' \
  595. +                                             % (post)})
  596. +                continue
  597.  
  598. -    def edit_window(self, post_num, admin, password):
  599. +            timestamp = time.time()
  600. +            date = misc.make_date(timestamp, self.options['DATE_STYLE'])
  601. +
  602. +            # File report.
  603. +            sql = reports_table.insert().values(reporter=numip,
  604. +                                                offender=offender_ip,
  605. +                                                postnum=post,
  606. +                                                comment=comment,
  607. +                                                timestamp=timestamp,
  608. +                                                date=date,
  609. +                                                resolved=0)
  610. +
  611. +            # TODO: Trim database.
  612. +
  613. +            return Template('report_submitted', errors=errors,
  614. +                            error_occurred=len(errors)>0,
  615. +                            referer=referer)
  616. +
  617. +    def edit_window(self, post_num, admin, password, admin_edit_mode=False):
  618.  
  619.          session = model.Session()
  620.          table = self.table
  621. @@ -766,23 +992,25 @@ class Board(object):
  622.  
  623.          if row is None:
  624.              raise WakaError('Post not found') # TODO
  625. -
  626. -        # Wrong password?
  627. -        if password != row['password']:
  628. +        
  629. +        if admin_edit_mode:
  630. +            self.check_access(admin)
  631. +        elif password != row['password']:
  632.              raise WakaError('Wrong pass for editing') # TODO
  633.  
  634. -        return Template('post_edit_template', loop=[row])
  635. +        return Template('post_edit_template', loop=[row],
  636. +                                              admin=admin_edit_mode)
  637.  
  638.      def edit_stuff(self, post_num, name, email, subject, comment, file,
  639.                     password, nofile, captcha, admin, no_captcha,
  640.                     no_format, oekaki_post, srcinfo, pch, sticky, lock,
  641. -                   admin_post_mode, killtrip, postfix):
  642. +                   admin_edit_mode, killtrip, postfix):
  643.  
  644. -        self.__handle_post(name, email, subject, comment, file,
  645. -                           password, nofile, captcha, admin, no_captcha,
  646. -                           no_format, oekaki_post, srcinfo, pch, sticky, lock,
  647. -                           admin_post_mode, post_num=post_num,
  648. -                           killtrip=killtrip)
  649. +        self._handle_post(name, email, subject, comment, file,
  650. +                          password, nofile, captcha, admin, no_captcha,
  651. +                          no_format, oekaki_post, srcinfo, pch, sticky, lock,
  652. +                          admin_edit_mode, post_num=post_num,
  653. +                          killtrip=killtrip)
  654.  
  655.          return Template('edit_successful')
  656.  
  657. @@ -995,7 +1223,58 @@ class Board(object):
  658.          return row[0]
  659.  
  660.      def trim_database(self):
  661. -        pass
  662. +        session = model.Session()
  663. +        table = self.table
  664. +        max_age = self.options['MAX_AGE']
  665. +
  666. +        # Clear expired posts due to age.
  667. +        if max_age:
  668. +            mintime = time.time() - max_age * 3600
  669. +
  670. +            sql = table.select().where(and_(table.c.parent == 0,
  671. +                                            table.c.timestamp <= mintime,
  672. +                                            table.c.stickied == 0))
  673. +            query = session.execute(sql)
  674. +
  675. +            for row in query:
  676. +                self.delete_post(row.num, '', False,
  677. +                                 self.options['ARCHIVE_MODE'], admin=True)
  678. +
  679. +        # TODO: Implement other maxes (even though no one freakin' uses
  680. +        #       them). :3c
  681. +
  682. +    def toggle_thread_state(self, admin, num, operation, enable_state=True):
  683. +        self.check_access(admin)
  684. +
  685. +        # Check  thread
  686. +        session = model.Session()
  687. +        table = self.table
  688. +        sql = select([table.c.parent], table.c.num == num, table)
  689. +        row = session.execute(sql).fetchone()
  690. +        
  691. +        if not row:
  692. +            raise WakaError('Thread /%s/%d not found.' % (self.name, num))
  693. +        if row['parent']:
  694. +            raise WakaError(strings.S_NOTATHREAD)
  695. +
  696. +        update = {}
  697. +        if operation == 'sticky':
  698. +            update = {'stickied' : 1 if enable_state else 0}
  699. +        else:
  700. +            update = {'locked' : 'yes' if enable_state else ''}
  701. +
  702. +        sql = table.update().where(or_(table.c.num == num,
  703. +                                       table.c.parent == num))\
  704. +                            .values(**update)
  705. +
  706. +        self.build_cache()
  707. +
  708. +        # TODO: Log this.
  709. +
  710. +        forward_url = '%s?task=mpanel&board=%s' %\
  711. +            (misc.get_secure_script_name(), self.name)
  712. +
  713. +        return util.make_http_forward(forward_url, config.ALTERNATE_REDIRECT)
  714.  
  715.  # utility functions
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement