Beispiel #1
0
 def login(self,
           *,
           get_credentials: onlinejudge.type.CredentialsProvider,
           session: Optional[requests.Session] = None) -> None:
     """
     :raises LoginError:
     """
     session = session or utils.get_default_session()
     url = 'https://codeforces.com/enter'
     # get
     resp = utils.request('GET', url, session=session)
     if resp.url != url:  # redirected
         log.info('You have already signed in.')
         return
     # parse
     soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                              utils.html_parser)
     form = soup.find('form', id='enterForm')
     log.debug('form: %s', str(form))
     username, password = get_credentials()
     form = utils.FormSender(form, url=resp.url)
     form.set('handleOrEmail', username)
     form.set('password', password)
     form.set('remember', 'on')
     # post
     resp = form.request(session)
     resp.raise_for_status()
     if resp.url != url:  # redirected
         log.success('Welcome, %s.', username)
     else:
         log.failure('Invalid handle or password.')
         raise LoginError('Invalid handle or password.')
Beispiel #2
0
    def login(self, *, get_credentials: onlinejudge.type.CredentialsProvider, session: Optional[requests.Session] = None) -> None:
        """
        :raises LoginError:
        """

        session = session or utils.get_default_session()
        if self.is_logged_in(session=session):
            return

        # get
        url = 'https://atcoder.jp/login'
        resp = _request('GET', url, session=session, allow_redirects=False)

        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding), utils.html_parser)
        form = soup.find('form', action='')
        if not form:
            raise LoginError('something wrong')

        # post
        username, password = get_credentials()
        form = utils.FormSender(form, url=resp.url)
        form.set('username', username)
        form.set('password', password)
        resp = form.request(session)
        _list_alert(resp, print_=True)

        # result
        if 'login' not in resp.url:
            log.success('Welcome,')  # AtCoder redirects to the top page if success
        else:
            log.failure('Username or Password is incorrect.')
            raise LoginError
Beispiel #3
0
    def submit_code(self, code: bytes, language_id: LanguageId, *, filename: Optional[str] = None, session: Optional[requests.Session] = None) -> onlinejudge.type.Submission:
        """
        :raises NotLoggedInError:
        """

        # NOTE: An implementation with the official API exists at 492d8d7. This is reverted at 2b7e6f5 because the API ignores cookies and says "提出するにはログインが必要です" at least at that time.

        session = session or utils.get_default_session()
        # get
        url = self.get_url() + '/submit'
        resp = utils.request('GET', url, session=session)
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding), utils.HTML_PARSER)
        form = soup.find('form', id='submit_form')
        if not form:
            logger.error('form not found')
            raise NotLoggedInError
        # post
        form = utils.FormSender(form, url=resp.url)
        form.set('lang', language_id)
        form.set_file('file', filename or 'code', code)
        form.unset('custom_test')
        resp = form.request(session=session)
        resp.raise_for_status()
        # result
        if 'submissions' in resp.url:
            # example: https://yukicoder.me/submissions/314087
            logger.info('success: result: %s', resp.url)
            return utils.DummySubmission(resp.url, problem=self)
        else:
            logger.error('failure')
            soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding), utils.HTML_PARSER)
            for div in soup.findAll('div', attrs={'role': 'alert'}):
                logger.warning('yukicoder says: "%s"', div.string)
            raise SubmissionError
 def submit_code(self,
                 code: bytes,
                 language_id: LanguageId,
                 filename: Optional[str] = None,
                 session: Optional[requests.Session] = None) -> Submission:
     """
     :raises NotLoggedInError:
     :raises SubmissionError:
     """
     assert language_id in [
         language.id
         for language in self.get_available_languages(session=session)
     ]
     session = session or utils.new_default_session()
     # get
     url = 'http://{}.contest.atcoder.jp/submit'.format(
         self.contest_id)  # TODO: use beta.atcoder.jp
     resp = _request('GET', url, session=session)
     msgs = AtCoderService._get_messages_from_cookie(resp.cookies)
     if AtCoderService._report_messages(msgs, unexpected=True):
         raise SubmissionError
     # check whether logged in
     path = utils.normpath(urllib.parse.urlparse(resp.url).path)
     if path.startswith('/login'):
         log.error('not logged in')
         raise NotLoggedInError
     # parse
     soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                              utils.html_parser)
     form = soup.find('form', action=re.compile(r'^/submit\?task_id='))
     if not form:
         log.error('form not found')
         raise SubmissionError
     log.debug('form: %s', str(form))
     # post
     task_id = self._get_task_id(session=session)
     form = utils.FormSender(form, url=resp.url)
     form.set('task_id', str(task_id))
     form.set('source_code', code)
     form.set('language_id_{}'.format(task_id), str(language_id))
     resp = form.request(session=session)
     resp.raise_for_status()
     # result
     msgs = AtCoderService._get_messages_from_cookie(resp.cookies)
     AtCoderService._report_messages(msgs)
     if '/submissions/me' in resp.url:
         # example: https://practice.contest.atcoder.jp/submissions/me#32174
         # CAUTION: this URL is not a URL of the submission
         log.success('success: result: %s', resp.url)
         # NOTE: ignore the returned legacy URL and use beta.atcoder.jp's one
         url = 'https://beta.atcoder.jp/contests/{}/submissions/me'.format(
             self.contest_id)
         return utils.DummySubmission(url, problem=self)
     else:
         log.failure('failure')
         log.debug('redirected to %s', resp.url)
         raise SubmissionError('it may be a rate limit')
    def submit_code(
            self,
            code: bytes,
            language_id: LanguageId,
            filename: Optional[str] = None,
            session: Optional[requests.Session] = None) -> 'AtCoderSubmission':
        """
        :raises NotLoggedInError:
        :raises SubmissionError:
        """

        session = session or utils.get_default_session()
        assert language_id in [
            language.id
            for language in self.get_available_languages(session=session)
        ]

        # get
        url = 'https://atcoder.jp/contests/{}/submit'.format(self.contest_id)
        resp = _request('GET', url, session=session)

        # check whether logged in
        if 'login' in resp.url:
            raise NotLoggedInError

        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form',
                         action='/contests/{}/submit'.format(self.contest_id))
        if not form:
            raise SubmissionError('something wrong')
        log.debug('form: %s', str(form))

        # post
        form = utils.FormSender(form, url=resp.url)
        form.set('data.TaskScreenName', self.problem_id)
        form.set('data.LanguageId', str(language_id))
        form.set('sourceCode', code)
        resp = form.request(session=session)
        _list_alert(resp, print_=True)

        # result
        if '/submissions/me' in resp.url:
            submission = next(
                AtCoderContest(
                    self.contest_id)._iterate_submissions_from_response(resp))
            log.success('success: result: %s', submission.get_url())
            return submission
        else:
            raise SubmissionError('it may be a rate limit')
    def submit_code(self,
                    code: bytes,
                    language_id: LanguageId,
                    filename: Optional[str] = None,
                    session: Optional[requests.Session] = None) -> Submission:
        """
        :raises NotLoggedInError:
        :raises SubmissionError:
        """

        assert language_id in [
            language.id
            for language in self.get_available_languages(session=session)
        ]
        session = session or utils.new_default_session()

        # get
        url = 'https://atcoder.jp/contests/{}/submit'.format(self.contest_id)
        resp = _request('GET', url, session=session)

        # check whether logged in
        if 'login' in resp.url:
            raise NotLoggedInError

        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form',
                         action='/contests/{}/submit'.format(self.contest_id))
        if not form:
            raise SubmissionError('something wrong')
        log.debug('form: %s', str(form))

        # post
        form = utils.FormSender(form, url=resp.url)
        form.set('data.TaskScreenName', self.problem_id)
        form.set('data.LanguageId', str(language_id))
        form.set('sourceCode', code)
        resp = form.request(session=session)
        _list_alert(resp, print_=True)

        # result
        if '/submissions/me' in resp.url:
            # example: https://practice.contest.atcoder.jp/submissions/me#32174
            # CAUTION: this URL is not a URL of the submission
            log.success('success: result: %s', resp.url)
            return utils.DummySubmission(resp.url, problem=self)
        else:
            raise SubmissionError('it may be a rate limit')
Beispiel #7
0
    def submit_code(
        self,
        code: bytes,
        language_id: LanguageId,
        *,
        filename: Optional[str] = None,
        session: Optional[requests.Session] = None
    ) -> onlinejudge.type.Submission:
        """
        :raises NotLoggedInError:
        :raises SubmissionError:
        """

        session = session or utils.get_default_session()
        # get
        resp = utils.request('GET', self.get_url(), session=session)
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form', class_='submitForm')
        if form is None:
            log.error('not logged in')
            raise NotLoggedInError
        log.debug('form: %s', str(form))
        # make data
        form = utils.FormSender(form, url=resp.url)
        form.set('programTypeId', language_id)
        form.set_file('sourceFile', filename or 'code', code)
        resp = form.request(session=session)
        resp.raise_for_status()
        # result
        if resp.url.endswith('/my'):
            # example: https://codeforces.com/contest/598/my
            log.success('success: result: %s', resp.url)
            return utils.DummySubmission(resp.url, problem=self)
        else:
            log.failure('failure')
            # parse error messages
            soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                     utils.html_parser)
            msgs = []  # type: List[str]
            for span in soup.findAll('span', class_='error'):
                msgs += [span.string]
                log.warning('Codeforces says: "%s"', span.string)
            raise SubmissionError(
                'it may be the "You have submitted exactly the same code before" error: '
                + str(msgs))
Beispiel #8
0
    def login(self,
              get_credentials: onlinejudge.type.CredentialsProvider,
              session: Optional[requests.Session] = None) -> None:
        """
        :raises LoginError:
        """

        session = session or utils.new_default_session()
        url = 'https://www.hackerrank.com/auth/login'
        # get
        resp = utils.request('GET', url, session=session)
        if resp.url != url:
            log.info('You have already signed in.')
            return
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        csrftoken = soup.find('meta', attrs={
            'name': 'csrf-token'
        }).attrs['content']
        tag = soup.find('input', attrs={'name': 'username'})
        while tag.name != 'form':
            tag = tag.parent
        form = tag
        # post
        username, password = get_credentials()
        form = utils.FormSender(form, url=resp.url)
        form.set('login', username)
        form.set('password', password)
        form.set('remember_me', 'true')
        form.set('fallback', 'true')
        resp = form.request(session,
                            method='POST',
                            action='/rest/auth/login',
                            headers={'X-CSRF-Token': csrftoken})
        resp.raise_for_status()
        # result
        if '/auth' not in resp.url:
            log.success('You signed in.')
        else:
            log.failure('You failed to sign in. Wrong user ID or password.')
            raise LoginError(
                'You failed to sign in. Wrong user ID or password.')
Beispiel #9
0
    def submit_code(
        self,
        code: bytes,
        language_id: LanguageId,
        *,
        filename: Optional[str] = None,
        session: Optional[requests.Session] = None
    ) -> onlinejudge.type.Submission:
        """
        :raises NotLoggedInError:
        """

        session = session or utils.get_default_session()
        # get
        url = self.get_url() + '/submit'
        resp = utils.request('GET', url, session=session)
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form', id='submit_form')
        if not form:
            log.error('form not found')
            raise NotLoggedInError
        # post
        form = utils.FormSender(form, url=resp.url)
        form.set('lang', language_id)
        form.set_file('file', filename or 'code', code)
        form.unset('custom_test')
        resp = form.request(session=session)
        resp.raise_for_status()
        # result
        if 'submissions' in resp.url:
            # example: https://yukicoder.me/submissions/314087
            log.success('success: result: %s', resp.url)
            return utils.DummySubmission(resp.url, problem=self)
        else:
            log.failure('failure')
            soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                     utils.html_parser)
            for div in soup.findAll('div', attrs={'role': 'alert'}):
                log.warning('yukicoder says: "%s"', div.string)
            raise SubmissionError
Beispiel #10
0
    def submit_code(self,
                    code: bytes,
                    language_id: LanguageId,
                    *,
                    filename: Optional[str] = None,
                    session: Optional[requests.Session] = None) -> Submission:
        """
        :raises NotImplementedError:
        :raises SubmissionError:
        """
        session = session or utils.get_default_session()
        # get
        resp = utils.request('GET', self.get_url(), session=session)
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form')
        if form is None:
            log.error('not logged in')
            raise LoginError
        log.debug('form: %s', str(form))
        if form.find('select'
                     ) and form.find('select').attrs['name'] != 'languageId':
            log.error("Wrong submission URL")
            raise SubmissionError

        # make data
        form = utils.FormSender(form, url=resp.url)
        form.set('languageId', language_id)
        form.set_file('source', 'code', code)
        resp = form.request(session=session)
        resp.raise_for_status()
        # result
        if '/s/' in resp.url:
            # example: https://toph.co/s/201410
            log.success('success: result: %s', resp.url)
            return utils.DummySubmission(resp.url, problem=self)
        else:
            log.failure('failure')
            log.debug('redirected to %s', resp.url)
            raise SubmissionError
Beispiel #11
0
    def login_with_github(
            self,
            get_credentials: onlinejudge.type.CredentialsProvider,
            session: Optional[requests.Session] = None) -> None:
        """
        :raise LoginError:
        """

        session = session or utils.get_default_session()
        url = 'https://yukicoder.me/auth/github'
        # get
        resp = utils.request('GET', url, session=session)
        if urllib.parse.urlparse(resp.url).hostname == 'yukicoder.me':
            log.info('You have already signed in.')
            return
        # redirect to github.com
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form')
        if not form:
            log.error('form not found')
            raise LoginError('something wrong')
        log.debug('form: %s', str(form))
        # post
        username, password = get_credentials()
        form = utils.FormSender(form, url=resp.url)
        form.set('login', username)
        form.set('password', password)
        resp = form.request(session)
        resp.raise_for_status()
        if urllib.parse.urlparse(resp.url).hostname == 'yukicoder.me':
            log.success('You signed in.')
        else:
            log.failure('You failed to sign in. Wrong user ID or password.')
            raise LoginError
Beispiel #12
0
    def login(self,
              get_credentials: onlinejudge.type.CredentialsProvider,
              session: Optional[requests.Session] = None) -> None:
        """
        :raises LoginError:
        """
        session = session or utils.new_default_session()
        url = 'https://toph.co/login'
        # get
        resp = utils.request('GET', url, session=session)
        if resp.url != url:  # redirected
            log.info('You are already logged in.')
            return
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form', class_='login-form')
        log.debug('form: %s', str(form))
        username, password = get_credentials()
        form[
            'action'] = '/login'  # to avoid KeyError inside form.request method as Toph does not have any defined action
        form = utils.FormSender(form, url=resp.url)
        form.set('handle', username)
        form.set('password', password)
        # post
        resp = form.request(session)
        resp.raise_for_status()

        resp = utils.request(
            'GET', url, session=session
        )  # Toph's Location header is not getting the expected value
        if resp.url != url:
            log.success('Welcome, %s.', username)
        else:
            log.failure('Invalid handle/email or password.')
            raise LoginError('Invalid handle/email or password.')
Beispiel #13
0
    def submit_code(
        self,
        code: bytes,
        language_id: LanguageId,
        *,
        filename: Optional[str] = None,
        session: Optional[requests.Session] = None
    ) -> onlinejudge.type.Submission:
        """
        :raises NotLoggedInError:
        :raises SubmissionError:
        """

        session = session or utils.get_default_session()
        # get
        resp = utils.request('GET', self.get_url(), session=session)
        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.html_parser)
        form = soup.find('form', class_='submitForm')
        if form is None:
            logger.error('not logged in')
            raise NotLoggedInError
        logger.debug('form: %s', str(form))
        # make data
        form = utils.FormSender(form, url=resp.url)
        form.set('programTypeId', language_id)
        form.set_file('sourceFile', filename or 'code', code)
        # post
        preserved_user_agent = session.headers.get('User-Agent')
        logger.debug(
            'User-Agent is temporarily disabled. The old User-Agent is %s',
            repr(preserved_user_agent))
        try:
            if preserved_user_agent is not None:
                del session.headers['User-Agent']
            resp = form.request(session=session, raise_for_status=False)
        finally:
            if preserved_user_agent is not None:
                session.headers['User-Agent'] = preserved_user_agent
        try:
            resp.raise_for_status()
        except requests.exceptions.HTTPError as e:
            logger.exception(e)
            if resp.status_code == 403:
                logger.warning('You may use wrong User-Agent: %s',
                               repr(session.headers.get('User-Agent')))
                raise SubmissionError(
                    'You may use wrong User-Agent: {}: {}'.format(
                        repr(session.headers.get('User-Agent')), e))
            raise e
        # result
        if resp.url.endswith('/my'):
            # example: https://codeforces.com/contest/598/my
            logger.info('success: result: %s', resp.url)
            return utils.DummySubmission(resp.url, problem=self)
        else:
            logger.error('failure')
            # parse error messages
            soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                     utils.html_parser)
            msgs = []  # type: List[str]
            for span in soup.findAll('span', class_='error'):
                msgs += [span.string]
                logger.warning('Codeforces says: "%s"', span.string)
            raise SubmissionError(
                'it may be the "You have submitted exactly the same code before" error: '
                + str(msgs))
Beispiel #14
0
    def submit_code(
        self,
        code: bytes,
        language_id: LanguageId,
        *,
        filename: Optional[str] = None,
        session: Optional[requests.Session] = None
    ) -> onlinejudge.type.Submission:
        """
        :raises NotLoggedInError:
        :raises SubmissionError:
        """

        session = session or utils.get_default_session()

        # get
        url = 'https://kcs.miz-miz.biz/contest/{}/submit/{}'.format(
            self.contest_id, self.problem_id)
        resp = utils.request('GET', url, session=session)

        # parse
        soup = bs4.BeautifulSoup(resp.content.decode(resp.encoding),
                                 utils.HTML_PARSER)
        form = soup.find('form', id='submission_data')
        if form is None:
            raise NotLoggedInError
        logger.debug('form: %s', str(form))

        # post
        form = utils.FormSender(form, url=resp.url)
        form.set('language', language_id)
        form.set('code', code)
        try:
            resp = form.request(session=session)
        except requests.exceptions.HTTPError as e:
            raise SubmissionError from e

        # result
        if '/submissions' in resp.url:
            # parse the individual submission page
            submission_url = resp.url
            try:
                url = 'https://kcs.miz-miz.biz/contest/{}/submissions?json=True'.format(
                    self.contest_id)
                resp = utils.request('GET', url, session=session)
                submissions = json.loads(resp.content.decode(resp.encoding))
                submission_id = max([
                    submission['submission_id'] for submission in submissions
                ])
                submission_url = 'https://kcs.miz-miz.biz/contest/{}/code/{}'.format(
                    self.contest_id, submission_id)
            except:
                logger.exception(
                    'failed to find the individual submission page. use the list page of all submissions instead.'
                )

            # return the url of the submission page
            logger.info('success: result: %s', submission_url)
            return utils.DummySubmission(submission_url, problem=self)
        else:
            logger.error('failure')
            raise SubmissionError