Esempio n. 1
0
class PhpBB(object):
    """Class to interract with phpBB forum."""

    delete_form_id = 'confirm'
    reply_url = 'posting.php?mode=reply&f={f}&t={t}'
    edit_url = 'posting.php?mode=edit&f={f}&p={p}'
    form_id = 'postform'
    private_mess_url = 'ucp.php?i=pm&mode=compose'

    def __init__(self, host):
        """Init object with forum url (host) and Browser object."""
        self.host = host
        try:
            self.browser = Browser()
        except HTTPError as e:
            print(e)
            sys.exit(1)

    def __del__(self):
        """Close the session and delete object."""
        try:
            self.browser.session.close()
        except HTTPError as e:
            print(e)
            sys.exit(1)

    def is_logged(self):
        """Check if logged in."""
        u = self._get_user_id()
        if u != 1:
            print(f"login OK : {str(u)}")
            return True
        else:
            print(f"login failed : {str(u)}")
            return False

    def is_logged_out(self):
        """Check if logged out."""
        u = self._get_user_id()
        if u != 1:
            print(f"Still logged in : {str(u)}")
            return True
        else:
            print(f"Signed out : {str(u)}")
            return False

    def _get_user_id(self):
        cookies = self.browser.list_cookies()
        for cookie in cookies:
            if re.search(cookie_u_pattern, cookie.name):
                return int(cookie.value)

    def _get_sid(self):
        cookies = self.browser.list_cookies()
        for cookie in cookies:
            if re.search(cookie_sid_pattern, cookie.name):
                sid = cookie.value
                return sid

    def login(self, username, password):
        """Log in phpBB forum."""
        try:
            forum_ucp = urljoin(self.host, ucp_url)
            payload = self.browser.select_tag(forum_ucp, "input")
            # for key, value in payload.items():
            #     print(key, value)
            payload['username'] = username
            payload['password'] = password
            time.sleep(1)
            self.browser.post(forum_ucp, params=login_mode, data=payload)
            return self.is_logged()

        except HTTPError as e:
            print(e)
            return False

    def logout(self):
        """Log out of phpBB forum."""
        try:
            # u_logout = Login(self.browser.session, self.host)
            # u_logout.send_logout()
            forum_ucp = urljoin(self.host, ucp_url)
            params = {'mode': 'logout', 'sid': self._get_sid()}
            self.browser.post(
                forum_ucp,
                # headers=headers,
                params=params)
            return self.is_logged_out()
        except HTTPError as e:
            print(e)
            return False

    def close(self):
        """Close request session (HTTP connection)."""
        try:
            self.browser.session.close()
        except HTTPError as e:
            print(e)
            sys.exit(1)

    def _get_post_text_area(self, url):
        try:
            soup = self.browser.get_html(url)
            return soup.find("textarea", id="message").text
        except HTTPError as e:
            print(e)
        except AttributeError as e:
            print("Error in _get_post_text_area")
            print(e)

    def _make_delete_confirm(self, url):
        form = self.browser.get_form(url, self.delete_form_id)
        form['values']['confirm'] = 'Oui'
        url = urljoin(self.host, form['action'])
        payload = form['values']
        return url, payload

    def _make_reply_payload(self, url, message):
        form = self.browser.get_form(url, self.form_id)
        form['values']['message'] = message
        # form['values']['icon'] = 0
        del form['values']['icon']
        form['values']['post'] = 'Submit'
        url = urljoin(self.host, form['action'])
        payload = form['values']
        return url, payload

    def _make_add_receiver_payload(self, url, receiver):
        form = self.browser.get_form(url, self.form_id)
        form['values']['username_list'] = receiver
        form['values']['add_to'] = "Ajouter"
        form['values']['addbbcode20'] = 100
        del form['values']['icon']
        url = urljoin(self.host, form['action'])
        payload = form['values']
        return url, payload

    def _make_private_message_payload(self, url, subject, message):
        form = self.browser.get_form(url, self.form_id)
        form['values']['subject'] = subject
        form['values']['message'] = message
        form['values']['addbbcode20'] = 100
        form['values']['address_list[u][8435]'] = "to"
        form['values']['icon'] = 0
        # del form['values']['icon']
        form['values']['post'] = 'Envoyer'
        url = urljoin(self.host, form['action'])
        payload = form['values']
        return url, payload

    def get_post_text(self, postid):
        """Get text of a post."""
        post = Post(postid, self)
        post.get_text()
        print(post.text)

    def get_post_editmode_content(self, forum, post):
        """Get text of a post as seen in edit mode."""
        url = urljoin(self.host, self.edit_url.format(f=forum, p=post))
        return self._get_post_text_area(url)

    def edit_post(self, forum, post, new_message):
        """Edit (modify) a message in a forum."""
        url = urljoin(self.host, self.edit_url.format(f=forum, p=post))
        try:
            form = self.browser.get_form(url, self.form_id)
            form['values']['icon'] = 0
            form['values']['message'] = new_message
            form['values']['post'] = 'Submit'
            form['values']['topic_type'] = '0'

            # wait at least 2 seconds so phpBB let us post
            time.sleep(2)

            payload = form['values']

            self.browser.session.post(
                url,
                # headers=headers,
                data=payload)
        except HTTPError as e:
            print(f'\n>>> Error {e.code}: {e.msg}')

    def get_forum_topics(self, f):
        """Retrieve and print all topics in a forum.

        Used in list-forum.py, for example.
        """
        forum = Forum(f, self)
        forum.print_forum_title()
        forum.get_nb_topics()
        topics_list = forum.get_forum_topics()
        forum.print_topics()
        return topics_list

    def get_forum_view_topics(self, f):
        """Test get_forum_viewtopics()."""
        forum = Forum(f, self)
        forum.print_forum_title()
        return forum.get_forum_viewtopics()

    def get_topic_posts(self, viewtopic, max_count):
        start = 0

        # topic executes get html, get nb message and get title on creation
        topic = Topic(self, viewtopic)
        topic.print40()

        pageurl = topic.make_topic_page_url(start)

        if topic.nb_messages < max_count:
            max_count = topic.nb_messages
        while start < max_count:
            # if (start + 10) < max_count:
            #     count = 0
            # else:
            #     count = max_count - start
            page = Page(pageurl, self.browser.get_html(pageurl))
            pagelist = page.get_page_posts()
            if not pagelist:
                break
            topic.postlist.extend(pagelist)
            start += 10
            pageurl = topic.make_topic_page_url(start)

        return topic.postlist

    def get_topic_posts_with_url(self, viewtopic, txt, max_count):
        start = 0

        # topic executes get html, get nb message and get title on creation
        topic = Topic(self, viewtopic)
        topic.print40()

        pageurl = topic.make_topic_page_url(start)

        if topic.nb_messages < max_count:
            max_count = topic.nb_messages
        while start < max_count:
            # if (start + 10) < max_count:
            #     count = 0
            # else:
            #     count = max_count - start
            page = Page(pageurl, self.browser.get_html(pageurl))
            pagelist = page.get_page_posts_with_url(txt)
            if not pagelist:
                break
            topic.postlist.extend(pagelist)
            start += 10
            pageurl = topic.make_topic_page_url(start)

        return topic.postlist

    # Def get_topic_posts(self, f, t, max_count):
    def get_topic_posts_not_done(self, viewtopic, posts_done, max_count):
        """Return list of posts, not already done.

        Args:
            viewtopic (str): viewtopic url
            posts_done (int): number of posts already done
            max_count (int): max number

        Returns:
            PostList: list of posts not processed yet

        """
        # topic executes get html, get nb message and get title on creation
        topic = Topic(self, viewtopic)
        topic.print40()

        if topic.nb_messages > posts_done:
            print(f"{posts_done} sur {topic.nb_messages} "
                  f"messages déjà traités")
            start = posts_done

            pageurl = topic.make_topic_page_url(start)
            if topic.nb_messages < max_count:
                max_count = topic.nb_messages
            while start < max_count:
                # if (start + 10) < max_count:
                #     count = 0
                # else:
                #     count = max_count - start
                page = Page(pageurl, self.browser.get_html(pageurl))
                pagelist = page.get_page_posts()
                if not pagelist:
                    break
                topic.postlist.extend(pagelist)
                start += 10
                pageurl = topic.make_topic_page_url(start)
            return topic.nb_messages, topic.postlist
        else:
            print("already_done")
            return topic.nb_messages, topic.postlist

    # Get User on a topic
    def get_user_topic_posts(self, viewtopic, max_count):
        start = 0

        # topic executes get html, get nb message and get title on creation
        topic = Topic(self, viewtopic)
        topic.print40()

        pageurl = topic.make_topic_page_url(start)

        if topic.nb_messages < max_count:
            max_count = topic.nb_messages
        while start < max_count:
            # if (start + 10) < max_count:
            #     count = 0
            # else:
            #     count = max_count - start
            page = Page(pageurl, self.browser.get_html(pageurl))
            pagelist = page.get_page_posts_with_user()
            if not pagelist:
                break
            topic.postlist.extend(pagelist)
            start += 10
            pageurl = topic.make_topic_page_url(start)

        return topic.postlist

    def delete_post(self, post):
        """Delete one message. Send proper request."""
        try:
            url_get = post.make_delete_req_url(self.host)
            print("delete : " + url_get)

            url_post, payload = self._make_delete_confirm(url_get)
            time.sleep(1)

            self.browser.session.post(
                url_post,
                # headers=headers,
                data=payload)
        except HTTPError as e:
            print(e)
            print("HTTPError with post : " + post.id)
        except TypeError as e2:
            print(e2)

    def delete_post_list(self, post_list):
        """Delete multiple messages (in a list)."""
        for post in post_list:
            self.delete_post(post)

    def get_topic_posts_with_user(self, viewtopic, max_count):
        start = 0
        # topic executes get html, get nb message and get title on creation
        topic = Topic(self, viewtopic)
        topic.print40()

        if topic.nb_messages < max_count:
            max_count = topic.nb_messages
        while start < max_count:
            # print(urltopic)
            # if (start + 10) < max_count:
            #     count = 0
            # else:
            #     count = max_count - start
            pageurl = topic.make_topic_page_url(start)
            page = Page(pageurl, self.browser.get_html(pageurl))
            pagelist = page.get_page_posts_with_user()
            if not pagelist:
                break
            topic.postlist.extend(pagelist)
            start += 10

        return topic.postlist

    def post_reply(self, forum, topic, message):
        """Send a reply."""
        url = urljoin(self.host, self.reply_url.format(f=forum, t=topic))

        urlrep, payload = self._make_reply_payload(url, message)
        print(urlrep)
        print(payload)
        time.sleep(2)
        self.browser.session.post(
            urlrep,
            # headers=headers,
            # params=self.login_mode,
            data=payload)

    def send_private_message(self, receiver, subject, message):
        """Send private message."""
        url = urljoin(self.host, self.private_mess_url)
        urlrep1, payload1 = self._make_add_receiver_payload(url, receiver)
        urlrep2, payload2 = self._make_private_message_payload(
            url, subject, message)  # noqa: E501
        time.sleep(2)
        # Add receiver
        self.browser.session.post(
            urlrep1,
            # headers=headers,
            # params=self.login_mode,
            data=payload1)

        # Send message
        self.browser.session.post(
            urlrep2,
            # headers=headers,
            # params=self.login_mode,
            data=payload2)