示例#1
0
def new_thread(request, forum, user):
    """
    Given a POST dict, create a new thread, then pass whats left to the 
    new_post function and then create the op. This function returns any
    errors, it returns None if there are no errors.
    """
    
    threadform = ThreadForm(request.POST)
    result = Result()
    result.threadform = threadform
    
    captcha_error = get_captcha_error(request)
    
    if captcha_error:
        result.captcha_error = captcha_error
        result.postform = PostForm(request.POST)
        return result
    else:
        result.captcha_success = True
    
    if threadform.is_valid():
        data = threadform.cleaned_data
        thread = Thread(title=data['title'], forum=forum)
        thread.save()
        result.thread = thread
    else:
        # error occured, return the form and the captcha error
        # (already set to result object) don't bother to try to add the post
        return result
    
    # all is valid, now make the op, skip captcha part 
    # because we already checked it
    return new_post(request, thread, user, result=result)
示例#2
0
    def search(self):
        matched_threads = self.get_matched_threads()

        models.cleanup(self.board, matched_threads)

        for thread_num in matched_threads:
            ThreadModel.get_or_create(num=thread_num, board=self.board)

        return matched_threads
示例#3
0
def test_setup(**kwargs):
    from django.contrib.auth.models import User
    from models import Thread, Post, Category
    from random import choice
    import chomsky

    if not settings.DEBUG:
        return

    if Thread.objects.all().count() > 0:
        # return, since there seem to already be threads in the database.
        return

    # ask for permission to create the test
    msg = """
    You've installed SNAPboard with DEBUG=True, do you want to populate
    the board with random users/threads/posts to test-drive the application?
    (yes/no):
    """
    populate = raw_input(msg).strip()
    while not (populate == "yes" or populate == "no"):
        populate = raw_input("\nPlease type 'yes' or 'no': ").strip()
    if populate == "no":
        return

    # create 10 random users

    users = ("john", "sally", "susan", "amanda", "bob", "tully", "fran")
    for u in users:
        user = User.objects.get_or_create(username=u)
        # user.is_staff = True

    cats = ("Random Topics", "Good Deals", "Skiing in the Vermont Area", "The Best Restaurants")
    for c in cats:
        cat = Category.objects.get_or_create(label=c)

    # create up to 30 posts
    tc = range(1, 50)
    for i in range(0, 35):
        print "thread ", i, "created"
        cat = choice(Category.objects.all())
        subj = choice(chomsky.objects.split("\n"))
        thread = Thread(subject=subj, category=cat)
        thread.save()

        for j in range(0, choice(tc)):
            text = "\n\n".join([chomsky.chomsky() for x in range(0, choice(range(2, 5)))])
            # create a post
            post = Post(
                user=choice(User.objects.all()),
                thread=thread,
                text=text,
                ip=".".join([str(choice(range(1, 255))) for x in (1, 2, 3, 4)]),
            )
            # allows setting of arbitrary ip
            post.management_save()
示例#4
0
    def save(self, request):
        event = Event()
        start_date = self.cleaned_data['start_date']
        start_time = self.cleaned_data['start_time']
        end_time = self.cleaned_data['end_time']
        event.start_time = datetime.combine(start_date, start_time)
        event.end_time = datetime.combine(start_date, end_time)
        event.event_name = self.cleaned_data['event_name']
        event.event_location = self.cleaned_data['event_location']
        event.event_organizer = self.cleaned_data['event_organizer']
        event.event_description = self.cleaned_data['event_description']
        event.event_website = self.cleaned_data['event_website']
        event.save()

        acl = ACLUserEvent()
        acl.user = request.user
        acl.event = event
        acl.save()

        discussiondefs = (
                            ('PR', _(u'Discussion of the upcoming %s'), _(u'Discuss the upcoming event %s before it actually happens.')), 
                            ('LI', _(u'Live discussion of %s'), _(u'Discuss the ongoing event %s live.')),
                            ('PO', _(u'Post-hoc discussion of %s'), _(u'Discuss %s after the facts.'))
                         )

        for s in discussiondefs:
            thread = Thread()
            thread.time = datetime.now()
            thread.user = request.user
            thread.event = event
            thread.thread_type = s[0];
            thread.title = s[1] % (event.event_name)
            thread.description = s[2] % (event.event_name)
            thread.save()
示例#5
0
    def save(self, author):
        self.thread = Thread(title=self.cleaned_data['title'],
                             forum=self.cleaned_data['forum'])

        self.thread.save()

        self.post = Post(thread=self.thread,
                         content=self.cleaned_data['content'],
                         author=author)

        self.post.save()

        return self.thread
示例#6
0
文件: views.py 项目: abdelhai/dyform
def data_view(fid, tid):
    formlinks = FormLink.objects(creator=current_user.to_dbref())
    formlink = FormLink.objects(fid=fid).first()
    # print 'formlink:', formlink
    threads = Thread.objects(formlink=formlink)
    thread = Thread.objects(tid=tid).first()
    datas = FormData.objects(thread=thread).order_by('id')
    main = FormData.objects(thread=thread).order_by('id').first()
    # for x in mains:
    #     print 'hhhhhh', x.load
    # main =  None
    return render_template('forms/dashboard.html', fid=fid, datas=datas,
                           threads=threads, formlinks=formlinks, tid=tid, main=main)
示例#7
0
文件: views.py 项目: DrewDos/forum
def new_thread(request, directory_id):



    form = NewThreadForm(request.POST)


    if request.method == 'POST':

        if form.is_valid():

           title = form.cleaned_data['title']
           body = form.cleaned_data['body']


           directory = Directory.objects.get(pk=directory_id)

           new_thread = Thread(name=title, creator=request.user, directory=directory)
           new_thread.save()

           new_post = Post(body=body, creator=request.user, index=1, thread=new_thread)

           #new_thread.latest_post_ref = new_post

           new_post.save()

           new_thread.directory = directory
           new_thread.latest_post = new_post
           new_thread.post_count = 1
           new_thread.save()

           return HttpResponseRedirect(reverse('main:view_thread', args=[new_thread.pk]))


    return render(request, 'main/new_thread.html', {'form': form, 'directory_id': directory_id})
示例#8
0
文件: rerender.py 项目: cklzqw/gaeaib
def do_render_cache(cursor=None):
  thq = Thread.all()

  if cursor:
    thq.with_cursor(cursor)

  thread = thq.get()

  if not thread:
    logging.info("stop thread clean")
    return

  board = thread.parent_key().name()
  render = Render(board=board, thread = thread.key().id())

  for idx,post in enumerate(thread.posts):
    post['text_html'] = markup(
          board=board, postid=post.get("post"),
          data=escape(post.get('text', '')),
    )

    if idx == 0:
      render.create(post)
    else:
      render.append(post)

  if len(thread.posts) > 1:
    thread.put()
  else:
    thread.delete()

  render.save()

  deferred.defer(do_render_cache, thq.cursor())
示例#9
0
文件: views.py 项目: mgoh/arkestrator
def new_thread(request):
    """ create a new thead """
    if request.method == 'POST':
        thread = Thread(
            creator=request.user,
            site=Site.objects.get_current(),
        )
        post = Post(thread=thread,
                    creator=request.user,
                    posted_from=get_client_ip(request))
        thread_form = forms.ThreadForm(request.POST, instance=thread)
        post_form = forms.PostForm(request.POST, instance=post)
        if thread_form.is_valid() and post_form.is_valid():
            thread = thread_form.save()
            post.thread = thread
            post_form = forms.PostForm(request.POST, instance=post)
            post_form.save()
            request.posting_users.add_to_set(request.user.id)
            return HttpResponseRedirect(reverse('list-threads'))
    else:
        thread_form = forms.ThreadForm()
        post_form = forms.PostForm()
    return render_to_response("board/new_thread.html", {
        'thread_form': thread_form,
        'post_form': post_form,
    },
                              context_instance=RequestContext(request))
示例#10
0
    def newThread(self, topic):
        # create new thread object and add it to the list
        thread = Thread(len(self.threads), topic, 0)
        self.threads.append(thread)
        # create generic RankNode to represent thread in the linked list, and
        # add it to the mapping dict
        node = RankNode(thread.id, None, None)
        self.nodes[thread.id] = node

        # if there is no head, then list is empty. insert node as first element
        if self.head is None:
            self.head = node
            self.tail = node
            self.insertion = node
        # if inesrtion is none, all other nodes have negative score.
        # insert node as first element and update insertion point to node
        elif self.insertion is None:
            node.next = self.head
            self.head = node
            self.insertion = node
        # other positive nodes exist. insert node behind insertion point and
        # update insertion point to node
        else:
            self.insertion.insertAfter(node)
            # if inserting after the last element, update tail to node
            if (self.insertion == self.tail):
                self.tail = node
            self.insertion = node
示例#11
0
def create_thread_view():
    forum = request.form['forum']
    section = request.form['section']
    title = request.form['title']
    text = request.form['text']

    new_thread = Thread.create(
        author=current_user.id,
        forum=forum,
        section=section,
        title=title,
        text=text,
    )

    labels = [
        label.strip()
        for label in request.form['labels'].split(',')
        if label.strip()
    ]
    if labels:
        for label in labels:
            thread_label = ThreadLabel.filter(text=label)
            if thread_label:
                thread_label = thread_label[0]
            else:
                thread_label = ThreadLabel.create(text=label)

            ThreadsLabels.create(
                thread=new_thread.id,
                label=thread_label.id,
            )

    return redirect(f'/thread/{new_thread.id}')
示例#12
0
文件: api.py 项目: strogo/gaeaib
    def get(self, board, num):
        thread_db = Thread.load(num, board)

        if not thread_db:
            raise NotFound()

        return json_response({"posts": thread_db.posts, "skip": 0, "subject": thread_db.subject})
示例#13
0
def index():
    chatwith_form = ChatWithForm()
    if chatwith_form.validate_on_submit():
        user = User.query.filter_by(
            username=chatwith_form.username.data).first()

        if user is None:
            flash("User does not exist")
        else:
            # minor bug: chatting with yourself shows messages of 1st thread created
            threads_user = db.session.query(users).filter_by(
                user_id=user.id).all()
            threads_current_user = db.session.query(users).filter_by(
                user_id=current_user.id).all()
            for thread_user in threads_user:
                for thread_current_user in threads_current_user:
                    if thread_user.thread_id == thread_current_user.thread_id:
                        return redirect(
                            url_for('chat', thread_id=thread_user.thread_id))

            thread = Thread(name=user.username)
            thread.users.append(user)
            thread.users.append(current_user)
            db.session.add(thread)
            db.session.commit()
            return redirect(url_for('chat', thread_id=thread.id))
    return render_template('index.html',
                           title='Chat',
                           chatwith_form=chatwith_form,
                           thread=None)
示例#14
0
def archive(thread_url):
    """
    Get values from the url to create a Thread object.
    Passes the thread to parse_html to be download.
    """
    match = None
    # check for valid urls in extractors
    for cls in Extractor.__subclasses__():
        extractor = None
        if re.match(cls.VALID_URL, thread_url):
            match = re.match(cls.VALID_URL, thread_url)
            extractor = cls()

    if not (match):
        print("Improper URL:", thread_url)
        return 1

    board = match.group('board')
    thread_id = match.group('thread')
    thread = Thread(thread_id, board, thread_url)

    params.path_to_download = 'threads/{}/{}'.format(thread.board, thread.tid)
    if not os.path.exists(params.path_to_download):
        os.makedirs(params.path_to_download)

    if params.verbose:
        print("Downloading thread:", thread.tid)
    extractor.extract(thread, params)
示例#15
0
文件: util.py 项目: a37912/gaeaib
def get_threads(board, page=0, fmt_name="page"):

  _fmt = "thread_" + fmt_name
  if _fmt in globals():
    fmt = globals()[_fmt]
  else:
    fmt = thread_plain


  threads = []

  board_db = Board.get_by_key_name(board)
  if board_db:
    threads = board_db.linked

    if not threads:
      threads = [ (board, th) for th in board_db.thread]

  per_page = get_config('aib.ib', 'thread_per_page')
  threads = threads[per_page*page:per_page*(page+1)]
  logging.info("threadlist in %r : %r" % (board, threads))

  # grab data from cache
  data =  Thread.load_list(threads)

  return [ fmt(th) for th in data if th ]
示例#16
0
    def onMessage(self, author_id, message_object, thread_id, thread_type,
                  **kwargs):
        if author_id != self.uid:
            self.markAsDelivered(author_id, thread_id)
            self.markAsRead(author_id)

            thread: Thread = Thread(thread_id, thread_type,
                                    self.lookupThread(thread_id).name)
            message: Message = Message(message_object.text, author_id,
                                       self.lookupUser(author_id).first_name,
                                       thread)
            client: Client = Client(self)

            try:
                log.info(
                    f'\n{message.author_name} in thread {thread.thread_name} said:\n{indent(message.text)}'
                )
                for handler in self.handlers:
                    if (handler.couldHandle(message)):
                        try:
                            log.info(f'Using: {handler.name()}')
                            handler.handle(message, client)
                        except RuntimeError as e:
                            client.sendText(thread, f'Error: {e}')
                        break
            except:
                client.sendText(thread, 'X_X')
                raise
示例#17
0
文件: views.py 项目: abdelhai/dyform
def data(fid):
    formlinks = FormLink.objects(creator=current_user.to_dbref())
    formlink = FormLink.objects(fid=fid).first()
    # print 'formlink:', formlink
    threads = Thread.objects(formlink=formlink)
    return render_template('forms/dashboard.html', fid=fid,
                           threads=threads, formlinks=formlinks)
示例#18
0
 def post(self):
     user = users.get_current_user()
     if not user:
         self.redirect("/welcome")
     else:
         teleUser = TeleUser.get_by_id(user.user_id())
         if not teleUser:
             teleUser = TeleUser.fromGSI(user=user)
             teleUser.put()
         thread_id = random.randint(1000000000, 9999999999)
         thread = Thread(thread_id=thread_id)
         drawingDataUrl = self.request.get("drawing")
         img_data = drawingDataUrl.split('data:image/png;base64,')[1]
         img = Image.open(BytesIO(base64.b64decode(img_data)))
         output = StringIO()
         img.save(output, format=img.format)
         drawing = output.getvalue()
         new_drawing = Drawing(content=drawing)
         allDrawings = Drawing.query().fetch()
         drawings = []
         for drawin in allDrawings:
             if drawin.content == new_drawing.content:
                 drawings.append(drawin)
         if drawings:
             new_drawing = drawings[0]
             threads = Thread.query().fetch()
             for threadD in threads:
                 if new_drawing.key in threadD.drawings:
                     thread = threads[0]
             new_edit = Edit.query().filter(
                 Edit.addition == new_drawing.key).fetch()[0]
         else:
             content_key = new_drawing.put()
             thread.drawings.append(content_key)
             thread_key = thread.put()
             new_edit = Edit(user=teleUser.key,
                             thread=thread_key,
                             addition=content_key)
             new_edit.put()
         confirmation_newThread_template = the_jinja_env.get_template(
             "confirmation-newthread.html")
         self.response.write(
             confirmation_newThread_template.render({
                 "user_info": user,
                 "thread": thread,
                 "new_edit": new_edit
             }))
示例#19
0
文件: util.py 项目: a37912/gaeaib
def save_post_defer(boards, thread, html, text_html, postid, count, sage):

  index_regen(Thread.gen_key(thread, boards[0]))

  rss.add(boards[0], thread, postid, text_html)

  if not sage:
    bump(boards, thread)
示例#20
0
 def create(cls, forum_id, section_id, author_id):
     return Thread.create(**{
         'title': fake.text(max_nb_chars=cls.MAX_TITLE_SIZE),
         'text': fake.text(max_nb_chars=cls.MAX_TEXT_SIZE),
         'forum': forum_id,
         'section': section_id,
         'author': author_id,
         'created_at': fake.date_time_this_century(before_now=True, after_now=False),
     })
示例#21
0
 def find_thread(self,threads,key):
     rec_cnt = 0
     t_ret = Thread()
     for t in threads:
         rec_cnt += 1
         if t.key == key:
             t_ret = t.thread
             break
     return t_ret,rec_cnt
示例#22
0
  def get(self):
    list, list_url = get_list_from_url(self.request.get('list'))
    msg = None
    if list is None:
      render(self, 'error.html', msg = 'The specified list does not exist.')
      return
    # If the last time the list was updated was over 12 hours ago, schedule an
    # update
    if list.last_fetched_time < datetime.now() - timedelta(hours=12):
      schedule_list_update(list)
      msg = 'Fetching new messages...'

    threads = Thread.all().filter('list_url =', list_url).\
                     order('-last_message_time')
    formatted_threads = []
    for t in threads:
      if len(t.participants) > 3:
        t.participants = [t.participants[0], '...'] + t.participants[-2:]
      t.participants = [', '.join(p.split()[0] for p in  t.participants)]
      t.subject = strip_tags(t.subject)
      t.last_message_body = strip_tags(t.last_message_body)[:100]
      one_day = timedelta(days=1)
      if t.last_message_time > datetime.now() - timedelta(days=1):
        t.short_date = datetime.strftime(t.last_message_time, '%H:%M%p')
      elif t.last_message_time > datetime.now() - timedelta(days=365):
        t.short_date = datetime.strftime(t.last_message_time, '%b %d')
      else:
        t.short_date = datetime.strftime(t.last_message_time, '%D')
      t.read = False
      formatted_threads.append(t)

    user = users.get_current_user()
    if user:
      def lookup():
        if len(lookup_pool) == 0:
          return
        for ut in UserThread.all().filter('thread_id IN', lookup_pool):
          last_viewed[ut.thread_id] = ut.last_viewed
        del lookup_pool[:]

      last_viewed = {} # maps from thread_ids to last viewed
      lookup_pool = []
      for t in formatted_threads:
        lookup_pool.append(t.thread_id)
        if len(lookup_pool) == 30:
          lookup()
      lookup()

      for t in formatted_threads:
        if t.thread_id in last_viewed:
          if t.last_message_time <= last_viewed[t.thread_id]:
            t.read = True

    render(self, 'view.html', list = list, threads = formatted_threads,
                              msg = msg)
示例#23
0
def thread(request, threadid):
	thread = Thread.get_by_id(int(threadid))
	posts = ThreadPostsViewModel(thread)
	
	return render_to_response('home/thread.html',
	{
		'forum' : thread.forum,
		'thread' : ThreadViewModel(thread),
		'posts' : posts,
		'post_form' : PostForm()
	})
示例#24
0
def thread(request, threadid):
    thread = Thread.get_by_id(int(threadid))
    posts = ThreadPostsViewModel(thread)

    return render_to_response(
        'home/thread.html', {
            'forum': thread.forum,
            'thread': ThreadViewModel(thread),
            'posts': posts,
            'post_form': PostForm()
        })
示例#25
0
def thread_label_view(thread_id):
    thread = Thread.get(thread_id)

    if not thread:
        abort(HTTPStatus.BAD_REQUEST)

    labels = ThreadLabel.filter(thread=thread.id)

    return jsonify({
        'thread': thread_id,
        'labels': [label.text for label in labels],
    })
示例#26
0
    def build_thread(self,form,user):
        print 'after validate'
#        print 'Logged in as %s' % user
        u = UserDT()
        u.first_name = user
        u.last_name = "b"
        u.email =  user + "@here.com"
        p = Post()
        p.title = "thread description"
        p.body = form.content.data
        p.creator = u
        print ' post - post build '
        pe = PostArrayEl()
        pe.key="1"
        pe.post=p
        t = Thread()
        t.title = form.name.data
        t.creator = u
        t.posts.append(pe)
        print ' thread - post build '
        t.postcnt=1
        return t
示例#27
0
文件: rerender.py 项目: a37912/gaeaib
def do_render_cache(cursor=None):
  thq = Thread.all(keys_only=True)

  if cursor:
    thq.with_cursor(cursor)

  if not thq.count(1):
    return

  for thread in thq.fetch(100):
    deferred.defer(process, thread, _queue='render')


  deferred.defer(do_render_cache, thq.cursor() )
示例#28
0
def add_thread(user_id):
    """Page to add a thread. """
    # if this user id combo exists
    thread = Thread.query.filter(Thread.user1_id == user_id,
                                 Thread.user2_id == g.user.id).all()

    thread2 = Thread.query.filter(Thread.user2_id == user_id,
                                  Thread.user1_id == g.user.id).all()

    if thread:
        return redirect(f'threads/{thread[0].id}')

    if thread2:
        return redirect(f'threads/{thread2[0].id}')

    # else:
    if (user_id < g.user.id):
        new_thread = Thread(user1_id=user_id, user2_id=g.user.id)
    else:
        new_thread = Thread(user1_id=g.user.id, user2_id=user_id)
    db.session.add(new_thread)
    db.session.commit()
    return redirect(f'threads/{new_thread.id}')
示例#29
0
文件: util.py 项目: cklzqw/gaeaib
def delete_post(board, thread_num, post_num, rape_msg):

  last_deletion = False
  th = Thread.get(db.Key.from_path(
      "Board", board, 
      "Thread", thread_num
      ))

  [post] = [p for p in th.posts if p.get('post') == post_num]
  logging.info("found: %r" % post)

  key = post.get("key")
  if key:
    post.pop("key", None)
    post.pop("image", None)
    info = blobstore.BlobInfo.get(
      blobstore.BlobKey(key))
    info.delete()
    
    try:
      th.images.remove(post.get("key"))
    except:
      pass
    
    logging.info("removed image %r" % post)
    
  else:
    last_deletion = True
    post['text'] = 'Fuuuuuu'       
    post['text_html'] = 'Fuuuuuu'       
    post['rainbow_html'] = u'<b>' + rape_msg + '</b>'

  th.put()
  Cache.delete(
    (
      dict(Board=board),
    )
  )

  r = Render(board, thread_num)
  #kind of shit:
  r.create(th.posts[0])
  for a_post in th.posts[1:]:
    r.append(a_post)
  r.save()
  
  #FIXME: update records in memcache 

  return last_deletion
示例#30
0
class NewThreadForm(forms.Form):
    error_css_class = 'in-error'
    thread_min_len = utils.get_config('min_thread_title_chars')
    post_min_len = utils.get_config('min_post_chars')

    title = forms.CharField(label='Title',
                            max_length=1000,
                            min_length=thread_min_len)

    content = forms.CharField(label='Post Body',
                              min_length=post_min_len,
                              widget=forms.Textarea())

    forum = forms.ModelChoiceField(queryset=Forum.objects.all(),
                                   widget=forms.HiddenInput())

    def __init__(self, *args, **kwargs):
        super(NewThreadForm, self).__init__(*args, **kwargs)

        self.thread = None
        self.post = None

    @transaction.atomic
    def save(self, author):
        self.thread = Thread(title=self.cleaned_data['title'],
                             forum=self.cleaned_data['forum'])

        self.thread.save()

        self.post = Post(thread=self.thread,
                         content=self.cleaned_data['content'],
                         author=author)

        self.post.save()

        return self.thread
示例#31
0
def create_thread_submit(request, forumid):
    forum = Forum.get_by_id(int(forumid))
    thread = Thread(forum=forum,
                    user=request._user,
                    content="Default",
                    title="Default")
    data = ThreadForm(request.POST, instance=thread)
    if data.is_valid():
        entity = data.save(commit=False)
        entity.put()
        forum.increment_thread_count()
        forum.set_last_thread(entity)
        return HttpResponseRedirect('/forum/{0}'.format(forum.key().id()))

    return render_to_response('home/create_thread.html', {'thread_form': data})
示例#32
0
    def save(self, request):
        event = Event()
        start_date = self.cleaned_data['start_date']
        start_time = self.cleaned_data['start_time']
        end_time = self.cleaned_data['end_time']
        event.start_time = datetime.combine(start_date, start_time)
        event.end_time = datetime.combine(start_date, end_time)
        event.event_name = self.cleaned_data['event_name']
        event.event_location = self.cleaned_data['event_location']
        event.event_organizer = self.cleaned_data['event_organizer']
        event.event_description = self.cleaned_data['event_description']
        event.event_website = self.cleaned_data['event_website']
        event.save()

        acl = ACLUserEvent()
        acl.user = request.user
        acl.event = event
        acl.save()

        discussiondefs = ((
            'PR', _(u'Discussion of the upcoming %s'),
            _(u'Discuss the upcoming event %s before it actually happens.')),
                          ('LI', _(u'Live discussion of %s'),
                           _(u'Discuss the ongoing event %s live.')),
                          ('PO', _(u'Post-hoc discussion of %s'),
                           _(u'Discuss %s after the facts.')))

        for s in discussiondefs:
            thread = Thread()
            thread.time = datetime.now()
            thread.user = request.user
            thread.event = event
            thread.thread_type = s[0]
            thread.title = s[1] % (event.event_name)
            thread.description = s[2] % (event.event_name)
            thread.save()
示例#33
0
 def onListening(self):
     default_group_id = int(os.environ['FB_DEFAULT_GROUP'])
     default_group = Thread(default_group_id,
                            fbchat.models.ThreadType.GROUP,
                            self.lookupThread(default_group_id))
     self.handlers = [
         WakeWordHandler(HelpHandler()),
         WakeWordHandler(EchoHandler()),
         WakeWordHandler(TellHandler(default_group)),
         WakeWordHandler(ImageHandler()),
         WakeWordHandler(PointsHandler()),
         # Must be last WakeWordHandler.
         WakeWordHandler(SorryDaveHandler()),
         Xkcd37Handler()
     ]
     fbchat.Client.onListening(self)
示例#34
0
文件: views.py 项目: abdelhai/dyform
def form(fid):
    if FormLink.objects(fid=fid):
        if request.method == 'POST':
            form_data = FormData()
            formlink = FormLink.objects(fid=fid).first().to_dbref()
            form_data.thread = Thread(formlink=formlink).save()
            form_data.load = semiflatten(request.form)
            form_data.headers = dict(request.headers.items())
            form_data.ip = request.remote_addr
            form_data.save()
            return redirect(url_for('forms.data', fid=fid))

        return render_template('forms/test_form.html',
                               fid=url_for('forms.form', fid=fid))
    else:
        return 'no form found'
示例#35
0
文件: util.py 项目: cklzqw/gaeaib
def get_threads(board, page=0, fmt_name="page"):

  _fmt = "thread_" + fmt_name
  if _fmt in globals():
    fmt = globals()[_fmt]
  else:
    fmt = thread_plain

  threads = Board.load(board)
  threads = threads[THREAD_PER_PAGE*page:THREAD_PER_PAGE*(page+1)]
  logging.info("threadlist in %r : %r" % (board, threads))

  # grab data from cache
  data =  Thread.load_list(threads, board)

  return [ fmt(num,th) for num,th in data if th ]
示例#36
0
def create_thread(request):

	newThread = Thread();
	newThread.message = request.POST['message']
	newThread.name = request.POST['title']
	newThread.created_by = request.user
	forum_name = decode_name(request.POST['forum_name'])
	
	newThread.forum = Forum.objects.filter(name=forum_name)[0]
	#newThread.topic = Forum.objects.filter(name=str(thread_name).replace ("_", " ").replace (".qm.", "?"))[0]
	newThread.save()
	args = {}
	#return render_to_response('view_thread.html', args, context_instance=RequestContext(request))
	return HttpResponseRedirect(request.POST['current_url'])
示例#37
0
文件: views.py 项目: abdelhai/dyform
def inbound():
    if request.method == 'POST':
        InboundData(raw=request.form).save()
        text = None
        subject = request.form['subject'].decode('utf-8')
        print subject
        reg = re.compile(ur"[\[]DFNR:(\d+)[-](\d+)[\]]".decode('utf-8'))
        fid = int(re.search(reg, subject).group(1))
        tid = int(re.search(reg, subject).group(2))
        if request.form['text']:
            text = request.form['text'].split('\n')[0]

        form_data = FormData()
        form_data.thread = Thread.objects(tid=tid).first().to_dbref()
        form_data.load = {'message': text}
        form_data.save()
    return ''
示例#38
0
文件: util.py 项目: strogo/gaeaib
def get_threads(board, page=0, fmt_name="page"):

  _fmt = "thread_" + fmt_name
  if _fmt in globals():
    fmt = globals()[_fmt]
  else:
    fmt = thread_plain

  per_page = get_config('aib.ib', 'thread_per_page')

  threads = Board.load(board) or []
  threads = threads[per_page*page:per_page*(page+1)]
  logging.info("threadlist in %r : %r" % (board, threads))

  # grab data from cache
  data =  Thread.load_list(threads, board)

  return [ fmt(num,th) for num,th in data if th ]
示例#39
0
    def index(self):
        counts = {
            'forums': Forum.count(),
            'sections': Section.count(),
            'threads': Thread.count(),
            'labels': ThreadLabel.count(),
            'answers': Answer.count(),
            'users': User.count(),
        }
        for item, count in counts.items():
            counts[item] = '{:,}'.format(counts[item])

        date = datetime.now().strftime('%d.%m.%Y %H:%M')

        return self.render(
            'admin/statistics.html',
            date=date,
            counts=counts,
        )
示例#40
0
文件: views.py 项目: abdelhai/dyform
def send_email(fid, tid):
    body = request.form.get('message')
    thread = Thread.objects(tid=tid).first()
    data = FormData.objects(thread=thread).order_by('id').first()
    email = data.load['email']
    email_address = current_user.username + '@mail.dyform.co'

    subject = 'Reply To: ' + '[DFNR:' + str(fid) + '-' + str(tid) + ']'

    message = sendgrid.Mail(to=email, subject=subject,
                            text=body, from_email=email_address)
    status, msg = sg.send(message)
    form_data = FormData()
    form_data.thread = thread.to_dbref()
    form_data.load = {"message": body,
                      "from": current_user.username + '@mail.dyform.co'}
    form_data.save()

    return redirect(url_for('forms.data_view', fid=fid, tid=tid))
示例#41
0
文件: rerender.py 项目: strogo/gaeaib
def do_render_cache(cursor=None):
  thq = Thread.all()

  if cursor:
    thq.with_cursor(cursor)

  thread = thq.get()

  if not thread:
    logging.info("stop thread clean")
    return

  board = thread.board
  render = Render(board=board, thread = thread.id)

  for idx,post in enumerate(thread.posts):
    if 'text' in post:
      post['text_html'] = markup(
            board=board, postid=post.get("post"),
            data=escape(post.get('text', '')),
      )
      if 'rainbow_html' in post:
        post.pop("rainbow_html")
        post['rainbow'] = rainbow.make_rainbow(post['rainbow'])

    if 'image' in post and not post.get("key"):
      post.pop("image")
      post['name'] = 'Kuroneko'

    if idx == 0:
      render.create(post)
    else:
      render.append(post)

  if len(thread.posts) > 1:
    thread.put()
  else:
    thread.delete()

  render.save()

  deferred.defer(do_render_cache, thq.cursor())
示例#42
0
文件: util.py 项目: a37912/gaeaib
def delete_post(board, thread_num, post_num, rape_msg):

  last_deletion = False
  th = Thread.load(thread_num, board)

  [post] = [p for p in th.posts if p.get('post') == post_num]
  logging.info("found: %r" % post)

  key = post.get("key")
  if key:
    post.pop("key", None)
    post.pop("image", None)
    info = blobstore.BlobInfo.get(
      blobstore.BlobKey(key))

    if info:
      info.delete()
    
    try:
      th.images.remove(post.get("key"))
    except:
      pass
    
    logging.info("removed image %r" % post)
    
  else:
    last_deletion = True
    post['text'] = 'Fuuuuuu'       
    post['text_html'] = 'Fuuuuuu'       
    post['rainbow_html'] = u'<b>' + rape_msg + '</b>'

  th.put()
  Cache.remove("board", board)

  r = Render(thread=th)
  #kind of shit:
  r.create(th.posts[0])
  for a_post in th.posts[1:]:
    r.append(a_post)
  r.save()
  
  return last_deletion
示例#43
0
def create_post_submit_process(request):
	try:
		logging.info("User Id {0}".format(request.POST['userid']))
		thread = Thread.get_by_id(int(request.POST['threadid']))
		user = User(request.POST['userid'])
		#I have to add some value that is not null or empty to content
		#to get round what seems to be a bug with either Django forms or Django
		#forms with the google app engine
		post = Post(user=user, thread=thread, content="CONTENT")
		data = PostForm(data=request.POST, instance=post) 

		if data.is_valid():
			entity = data.save(commit=False)
			entity.put()
			thread.forum.increment_post_count()
			thread.set_last_post(entity)
			thread.increment_post_count()
		else:
			logging.info("data not valid")
	except Exception, e:
		logging.info(e.message)
示例#44
0
def create_post_submit_process(request):
    try:
        logging.info("User Id {0}".format(request.POST['userid']))
        thread = Thread.get_by_id(int(request.POST['threadid']))
        user = User(request.POST['userid'])
        #I have to add some value that is not null or empty to content
        #to get round what seems to be a bug with either Django forms or Django
        #forms with the google app engine
        post = Post(user=user, thread=thread, content="CONTENT")
        data = PostForm(data=request.POST, instance=post)

        if data.is_valid():
            entity = data.save(commit=False)
            entity.put()
            thread.forum.increment_post_count()
            thread.set_last_post(entity)
            thread.increment_post_count()
        else:
            logging.info("data not valid")
    except Exception, e:
        logging.info(e.message)
示例#45
0
文件: util.py 项目: cklzqw/gaeaib
def get_post(board, num):
  key = "post-%(board)s-%(num)d" % {"board":board, "num":num}
  post = None #memcache.get(key)

  if post != None:
    logging.info("cache hit")
    return post

  thq = Thread.all()
  thq.ancestor( db.Key.from_path("Board", board))
  thq.filter("post_numbers", num)

  thread = thq.get()

  if not thread:
    return 

  [post] = [p for p in thread.posts if p.get('post') == num]

  memcache.set(key, post)

  return post
示例#46
0
def create_post_submit(request, threadid):
	thread = Thread.get_by_id(int(threadid))
	#I have to add some value that is not null or empty to content
	#to get round what seems to be a bug with either Django forms or Django
	#forms with the google app engine
	post = Post(user=request._user, thread=thread, content="CONTENT")
	data = PostForm(data=request.POST, instance=post) 

	if data.is_valid():
		for n in range(10):
			dataToSend = dict(request.POST)
			dataToSend['userid'] = request._user.user_id()
			dataToSend['threadid'] = thread.key().id()
			taskqueue.add(url='/tasks/insertpost/', params=dataToSend)	
		return HttpResponseRedirect('/thread/{0}/'.format(threadid))
	
	posts = Post.all().filter('thread =', thread).order('datetime')
	return render_to_response('home/thread.html',{
		'forum' : thread.forum,
		'thread' : thread,
		'posts' : posts,
		'post_form' : data
	})
示例#47
0
    def post(self, thread_name):
        '''Add a comment to thread.'''
        args, author_name = parse_and_decode()

        text = bleach.clean(args['text'], strip=True)

        # Get thread (add if needed)
        try:
            thread = (db.session.query(Thread)
                      .filter(Thread.name == thread_name).one())
        except NoResultFound:
            thread = Thread(name=thread_name)
            db.session.add(thread)
            db.session.commit()

        author_id = get_author_add_if_needed(author_name)

        now = arrow.utcnow()
        comment = Comment(author_id=author_id, text=text, thread_id=thread.id,
                          created=now, modified=now)
        db.session.add(comment)
        db.session.commit()
        return get_thread_comments(thread)
示例#48
0
def create_post_submit(request, threadid):
    thread = Thread.get_by_id(int(threadid))
    #I have to add some value that is not null or empty to content
    #to get round what seems to be a bug with either Django forms or Django
    #forms with the google app engine
    post = Post(user=request._user, thread=thread, content="CONTENT")
    data = PostForm(data=request.POST, instance=post)

    if data.is_valid():
        for n in range(10):
            dataToSend = dict(request.POST)
            dataToSend['userid'] = request._user.user_id()
            dataToSend['threadid'] = thread.key().id()
            taskqueue.add(url='/tasks/insertpost/', params=dataToSend)
        return HttpResponseRedirect('/thread/{0}/'.format(threadid))

    posts = Post.all().filter('thread =', thread).order('datetime')
    return render_to_response('home/thread.html', {
        'forum': thread.forum,
        'thread': thread,
        'posts': posts,
        'post_form': data
    })
示例#49
0
def create_answer_view():
    next_page = request.form['next']

    text = request.form['text']
    thread_id = request.form['thread']

    if not (text and thread_id):
        abort(HTTPStatus.BAD_REQUEST)

    answer = Answer.create(
        text=text[:65535],
        thread=thread_id,
        author=current_user.id,
        created_at=datetime.now(),
    )

    current_user.msg_count += 1
    current_user.save()

    thread = Thread.get(thread_id)
    thread.last_answer_time = answer.created_at
    thread.save()

    return redirect(next_page)
示例#50
0
def update_list(list, start_msg, limit = 10):
  import email_loader
  import urllib
  required_fields = ['date', 'message_id', 'subject', 'body', 'sender']
  thread_id_cache = {}
  thread_pool = {}
  message_pool = []
  new = 0
  err = None
  for i in range(start_msg, start_msg + limit):
    url = "%s/msg%05i.html" % (list.list_url, i)
    logging.info("loading an email from url %s" % url)

    # Try three times to fetch the URL
    result = None
    for attempt in range(3):
      try:
        result = urlfetch.fetch(url=url)
        err = None
        break
      except urlfetch.DownloadError, msg:
        err = msg
        continue
    if result is None: break

    if result.status_code == 404:
      # This message does not exist, so return messages collected so far.
      break
    elif result.status_code != 200:
      err = 'Got status code %i while trying to fetch %s' % (result.status_code,
                                                             url)
      break

    logging.info("got content: %s" % result.content)
    result = email_loader.parser(StringIO(result.content))

    logging.info("got result: %s" % result)
    result['source_url'] = url
    result['list_msg_id'] = i
    if not all((field in result) for field in required_fields):
      logging.error(
        "failed to update list %s msg %i with url %s; got bad parse result %s"
        % (list, i, url, result))
      break
    result['date'] = datetime.strptime(' '.join(result['date'].split()[:-1]),
                                       '%a, %d %b %Y %H:%M:%S')
    # Determine thread_id
    if 'references' in result:
      for reference in result['references']:
        if 'thread_id' in result:
          break
        if reference in thread_id_cache:
          result['thread_id'] = thread_id_cache[reference]

      for reference in result['references']:
        if 'thread_id' in result:
          break
        ref = gql_limit1(Message, message_id = reference)
        if ref is not None:
          result['thread_id'] = ref.thread_id
    # If no thread_id was found, start a new thread with this message
    if 'thread_id' not in result:
      result['thread_id'] = result['message_id']
      thread = Thread(thread_id = result['message_id'],
                      list_url = list.list_url,
                      last_message_time = result['date'],
                      subject = result['subject'],
                      last_message_body = result['body'],
                      participants = [result['sender']])
      thread_pool[result['thread_id']] = thread

    # Build the message object
    message = Message(**result)

    # Update the thread
    if result['thread_id'] not in thread_pool:
      thread = gql_limit1(Thread, thread_id = result['thread_id'])
      thread_pool[result['thread_id']] = thread
    thread = thread_pool[result['thread_id']]
    thread.last_message_time = message.date
    thread.last_message_body = message.body
    if message.sender not in thread.participants:
      thread.participants.append(message.sender)
    thread_id_cache[result['message_id']] = result['thread_id']

    # Update the message_pool
    message_pool.append(message)
    new += 1
示例#51
0
def ask(request):
	"""
	Request handler when someone posts a question
	1. Add question content to the database
	2. Select random active answerer
	3. Put the question in the answerer's update stack
	4. Send push notification to the answerer's device to retrieve updates
	"""
	if request.method == 'POST':
		json_data = json.loads(request.body)

		try:
			question_content = json_data['content']
			asker_device_id = json_data['device_id']
			max_new_threads = json_data['max_new_threads']
		except KeyError:
			print "Error: A posted question did not have a JSON object with the required properties"
		else:
			
			# then add question to database
			question = Question(asker_device_id=asker_device_id, content=question_content)
			question.save()

			# We are going to start one or more threads with random devices, put the critical information about the thread in this array
			# and send it back to the device
			new_thread_ids = [];
			responder_ids = [];
			
			# then select a random device to send the question to
			all_devices = Device.objects.all()
			asker_device = all_devices.filter(device_id=asker_device_id)[0];
			print "Found asker device"
			print asker_device
			print max_new_threads
			reasonable_number_of_tries = 0
			while len(new_thread_ids) < max_new_threads:
				random_device = random.choice(all_devices) if len(all_devices) > 1 else None
				print "Chosing random device"
				print random_device
				# ensure that we've a valid answerer device
				if random_device is None:
					return
				while len(all_devices) > 1 and random_device.device_id == asker_device_id or random_device.device_id in responder_ids :
					if reasonable_number_of_tries < 5:
						random_device = random.choice(all_devices)
						reasonable_number_of_tries = reasonable_number_of_tries + 1
					else:
						break
					
				if reasonable_number_of_tries >= 5:
					break
				
				print "Chose another random device"
				print random_device
				responder_ids.append(random_device.device_id)
				
				print "But I am"
				print asker_device_id
				
				# find a unique thread id

					

				
				# Start the thread between the asker device and the random device	
				response_thread = Thread(question_id=question.id, asker_device=asker_device, answerer_device=random_device)
				response_thread.save()
				new_thread_ids.append(response_thread.id)
				print "response thread with id: " + str(response_thread.id)
	
				# add question to answerer_device update stack
				QuestionUpdates.add_update(random_device, question)
				ThreadUpdates.add_update(random_device, response_thread)
			
			new_threads = []
			for i in range(0, len(new_thread_ids)):
				new_threads.append({'thread_id':new_thread_ids[i], 'responder_device_id':responder_ids[i]})

			return HttpResponse(json.dumps({ 'question_id' : question.id, 'threads' : new_threads }), content_type="application/json")
示例#52
0
文件: util.py 项目: cklzqw/gaeaib
def save_post(request, data, board, thread):

  board_db = Board.get_by_key_name(board)

  if not board_db:
    board_db = Board(key_name = board, thread = [])

  board_db.counter += 1

  # create new thread
  new = False
  if thread == 'new':
    new = True
    if data.get("sage"):
      raise NotFound() # FIXME: move to form

    thread = board_db.counter
    posts = []
    thread_db = Thread.create(thread, board)
    thread_db.posts = []
    thread_db.subject = data.get("subject")[:SUBJECT_MAX]
  else:
    thread = int(thread)
    #if thread not in board_db.thread:
    #  raise NotFound()

    if thread in board_db.thread and not data.get("sage"):
      board_db.thread.remove(thread)

    thread_db = Thread.load(thread, board)

    if not thread_db:
      raise NotFound()

  if not data.get("sage"):
    board_db.thread.insert(0, thread)

  board_db.thread = board_db.thread[:THREAD_PER_PAGE*BOARD_PAGES]

  rb = rainbow.make_rainbow(request.remote_addr, board, thread)
  data['rainbow'] = rb
  data['rainbow_html'] = rainbow.rainbow(rb)
  data['text_html'] = markup(
        board=board, postid=board_db.counter,
        data=escape(data.get('text', '')),
  )

  # FIXME: move to field
  data['name'] = data.get("name") or "Anonymous"

  # save thread and post number
  data['post'] = board_db.counter
  data['thread'] = thread
  now = datetime.now()
  data['time'] = now.strftime("%Y-%m-%d, %H:%M")
  data['timestamp'] = int(now.strftime("%s"))

  img_key = data.get("key")

  if img_key:
    blob_key = blobstore.BlobKey(img_key)
    blob_info = blobstore.BlobInfo.get(blob_key)

    data['image'] = {
        "size" : blob_info.size,
        "content_type" : blob_info.content_type,
        "full" : images.get_serving_url(img_key),
        "thumb" : images.get_serving_url(img_key, 200),
    }

  for fname in board_options.get(board, []):
    func = globals().get('option_'+fname)

    if func:
      func(request, data)

  thread_db.posts.append(data)

  db.put( (thread_db, board_db))
  Cache.delete(
    (
      dict(Board=board),
    )
  )
  memcache.set("threadlist-%s" % board, board_db.thread)

  memcache.set("post-%s-%d" %(board, board_db.counter), data)

  r = Render(board, thread)
  r.add(data, new)
  r.save()

  key = "update-thread-%s-%d" % (board, thread)
  if not new:
    send = { 
        "html" : r.post_html, 
        "evt" : "newpost" ,
        "count" : len(thread_db.posts),
        "last" : board_db.counter,
    }
    watchers = memcache.get(key) or []
    for person in watchers:
      logging.info("send data to key %s" % (person+key))
      channel.send_message(person+key, dumps(send))

  return board_db.counter, thread
示例#53
0
	def __init__(self, forum):
		self.threads = []
		threads = Thread.all().filter('forum =',forum).order('-datetime').fetch(10,offset=0)
		for thread in threads:
			self.threads.append(ThreadViewModel(thread))
示例#54
0
文件: util.py 项目: a37912/gaeaib
def save_post(request, data, board, thread, ip):

  def board_increment():
    board_db = BoardCounter.get_by_key_name(board)

    if not board_db:
      board_db = BoardCounter(key_name = board, thread = [])

    board_db.counter += 1
    board_db.put()

    return board_db.counter

  postid = db.run_in_transaction(board_increment,)

  # create new thread
  new = False
  if thread == 'new':
    new = True
    if data.get("sage"):
      raise NotFound() # FIXME: move to form

    thread = postid
    posts = []
    thread_db = Thread.create(thread, board)
    thread_db.posts = []
    thread_db.subject = data.get("subject")[:SUBJECT_MAX]
  else:
    thread = int(thread)

    thread_db = Thread.load(thread, board)

    if not thread_db:
      raise NotFound()

  rb = rainbow.make_rainbow(ip, board, thread)
  data['rainbow'] = rb
  data['overlay'] = board in OVER
  
  data['text_html'] = markup(
        board=board, postid=postid,
        data=escape(data.get('text')),
  )

  # save thread and post number
  data['post'] = postid
  data['thread'] = thread
  now = datetime.now()
  data['time'] = now.strftime("%Y-%m-%d, %H:%M")
  data['timestamp'] = int(now.strftime("%s"))

  img_key = data.get("key")

  if img_key:
    blob_key = blobstore.BlobKey(img_key)
    blob_info = blobstore.BlobInfo.get(blob_key)

    data['image'] = {
        "size" : blob_info.size,
        "content_type" : blob_info.content_type,
        "full" : images.get_serving_url(img_key),
        "thumb" : images.get_serving_url(img_key, 200),
    }

  for fname in OPTIONS.get(board, []):
    func = globals().get('option_'+fname)

    if func:
      func(request, data)

  thread_db.posts.append(data)
  thread_db.put()

  r = Render(thread=thread_db)
  r.post_html = ''
  r.add(data, new) # WARNING: side effect on data
  r.save()

  deferred.defer(save_post_defer,
      thread_db.boards, thread,
      r.post_html, data.get('text_html'),
      postid,
      len(thread_db.posts),
      data.get("sage"),
  )

  # send notify
  thread_flag = 'new' if new else 'sage' if data.get("sage") else 'bump'
  match_msg = Post(board = board, thread = thread, thread_flag = thread_flag)
  match_msg.data = dict(
    board = board,
    thread = thread,
    html = r.post_html,
    text = data.get('text'),
    last = postid,
    count = len(thread_db.posts),
    evt = 'newpost'
  )

  matcher.match(match_msg, topic='post',
      result_task_queue='postnotify')

  return postid, thread
示例#55
0
def section_view(section_id):
    section = Section.get(section_id)
    forum = Forum.get(section.forum)
    parent_section = Section.get(section.parent)
    subsections = Section.filter(parent=section.id)

    # Threads
    try:
        page = int(request.args.get('page'))
    except (TypeError, ValueError):
        page = 1

    if not page or page < 1:
        page = 1

    threads_count = len(Thread.filter(section=section.id))
    # FIXME(a.telishev): Threads per page by search
    pages_count = threads_count // THREADS_PER_PAGE

    if page > pages_count:
        page = pages_count

    prev_page = page - 1
    next_page = page + 1
    if page == 1:
        prev_page = None
    if page == pages_count:
        next_page = None

    offset = (page - 1) * THREADS_PER_PAGE

    search = request.args.get('search', '')
    search_condition = f'AND thread.title LIKE "%{search}%"' if search else ''
    query = f"""
        SELECT
            thread.id thread_id,
            thread.title thread_title,
            thread.created_at thread_created_at,
            thread.last_answer_time thread_last_answer_time,
            user.id user_id,
            user.username username
        FROM thread
        INNER JOIN user ON thread.author = user.id
        WHERE section = %(section_id)s {search_condition}
        ORDER BY thread.last_answer_time DESC
        LIMIT %(limit)s
        OFFSET %(offset)s;
    """
    cursor = get_connector().cursor()
    cursor.execute(query, {
        'section_id': section.id,
        'limit': THREADS_PER_PAGE,
        'offset': offset,
    })
    threads = {
        thread_id: {
            'id':
            thread_id,
            'title':
            thread_title,
            'created_at':
            thread_created_at.strftime('%d %b %Y'),
            'created_at_h':
            thread_created_at.strftime('%d %b %Y\n%H:%M:%S'),
            'last_answer_time':
            (thread_last_answer_time.strftime('%d %b %Y\n%H:%M:%S')
             if thread_last_answer_time else None),
            'user_id':
            user_id,
            'username':
            username,
        }
        for (
            thread_id,
            thread_title,
            thread_created_at,
            thread_last_answer_time,
            user_id,
            username,
        ) in cursor
    }

    if threads:
        answers_count_query = f"""
            SELECT
                thread.id,
                COUNT(*)
            FROM thread INNER JOIN answer on thread.id = answer.thread
            WHERE thread.id IN ({
                ', '.join(str(thread_id) for thread_id in threads)
            })
            GROUP BY thread.id;
        """
        cursor.execute(answers_count_query)
        for thread_id, answers_count in cursor:
            threads[thread_id]['answers_count'] = answers_count

    cursor.close()

    return render_template(
        'section.html',
        section=section,
        forum=forum,
        parent_section=parent_section,
        subsections=subsections,
        threads=threads.values(),
        search=search,
        next_page=next_page,
        curr_page=page,
        prev_page=prev_page,
    )