Example #1
0
def GetUserStatus(host, cookie, middleware_token, contest_id, problems):
    """Get the current user's status from the server.

  Args:
    host: Domain name of the server where the contest is running.
    cookie: Cookie for the current user.
    middleware_token: Middleware authentication token for the current user.
    contest_id: Id of the contest where the user is participating.
    problems: List with all problems in the contest.

  Returns:
    An UserStatus object with the current user's status.

  Raises:
    error.NetworkError: If a network error occurs while communicating with the
      server.
    error.ServerError: If the server answers code distinct than 200 or the
      response is a malformed JSON.
  """
    # Send an HTTP request to get the user status.
    sys.stdout.write(
        'Getting user status at contest {0} from "{1}"...\n'.format(
            contest_id, host))
    request_referer = 'http://{0}/codejam/contest/dashboard?c={1}'.format(
        host, contest_id)
    request_arguments = {
        'cmd': 'GetUserStatus',
        'contest': contest_id,
        'zx': str(int(time.time())),
        'csrfmiddlewaretoken': str(middleware_token),
    }
    request_headers = {
        'Referer': request_referer,
        'Cookie': cookie,
    }
    try:
        status, reason, response = http_interface.Get(
            host, '/codejam/contest/dashboard/do', request_arguments,
            request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError(
            'HTTP exception while user status from the Google '
            'Code Jam server: {0}.\n'.format(e))

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'get user status. Check that the host, username '
            'and contest id are valid.\n')

    # Parse the JSON response and return an object with the user status.
    try:
        json_response = json.loads(response)
        return UserStatus.FromJsonResponse(json_response, problems)
    except ValueError as e:
        raise error.ServerError(
            'Invalid response received from the server, cannot '
            'get user status. Check that the contest id is '
            'valid: {0}.\n'.format(e))
Example #2
0
def GetContestStatus(host, cookie, get_initial_values_token, contest_id):
    """Get the contest status of the specified contest.

  Args:
    host: Host where the contest is running.
    cookie: Cookie that the user received when authenticating.
    get_initial_values_token: Middleware token used to make the request.
    contest_id: ID of the contest whose problems must be read.

  Returns:
    The contest status.

  Raises:
    error.NetworkError: If a network error occurs while communicating with the
      server.
    error.ServerError: If the server answers code distinct than 200 or the
      response is a malformed JSON.
  """
    # Send an HTTP request to get the problem list from the server.
    sys.stdout.write('Getting status of contest {0} from "{1}"...\n'.format(
        contest_id, host))
    request_referer = 'http://{0}/codejam/contest/dashboard?c={1}'.format(
        host, contest_id)
    request_arguments = {
        'cmd': 'GetInitialValues',
        'contest': contest_id,
        'zx': str(int(time.time())),
        'csrfmiddlewaretoken': str(get_initial_values_token),
    }
    request_headers = {
        'Referer': request_referer,
        'Cookie': cookie,
    }
    try:
        status, reason, response = http_interface.Get(
            host, '/codejam/contest/dashboard/do', request_arguments,
            request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError(
            'HTTP exception while retrieving contest status '
            'from the Google Code Jam server: '
            '{0}.\n'.format(e))

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'get contest status. Check that the host, username '
            'and contest id are valid.\n')

    # Parse the JSON response and extract the contest status from it.
    try:
        json_response = json.loads(response)
        return json_response['cs']
    except (KeyError, ValueError) as e:
        raise error.ServerError(
            'Invalid response received from the server, cannot '
            'get contest status. Check that the contest id is '
            'valid: {0}.\n'.format(e))
Example #3
0
def _GetMiddlewareTokens(host, cookie):
    """Get needed middleware tokens for the specified host.

  Args:
    host: Host where the contest is running.
    cookie: Cookie that the user received when authenticating.

  Returns:
    A tuple two elements: a dictionary containing all the middleware tokens,
    and the tokens expiration date.

  Raises:
    error.NetworkError: If a network error occurs while communicating with the
      server.
    error.ServerError: If the server answers code distinct than 200 or the
      response is a malformed JSON.
  """
    # Send an HTTP request to get the problem list from the server.
    sys.stdout.write('Getting middleware tokens from "{0}"...\n'.format(host))
    request_referer = 'http://{0}/codejam'.format(host)
    request_arguments = {
        'cmd': 'GetMiddlewareTokens',
        'actions': 'GetInitialValues,GetInputFile,GetUserStatus,SubmitAnswer',
    }
    request_headers = {
        'Referer': request_referer,
        'Cookie': cookie,
    }
    try:
        status, reason, response = http_interface.Get(host,
                                                      '/codejam/middleware',
                                                      request_arguments,
                                                      request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError('HTTP exception while retrieving middleware '
                                 'tokens from the Google Code Jam server: '
                                 '{0}\n'.format(e))

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'get middleware tokens. Check that the host, '
            'username and contest id are valid.\n')

    # Extract token information from server response.
    try:
        tokens_info = json.loads(response)
        return tokens_info['tokens'], tokens_info['expire']
    except (KeyError, ValueError) as e:
        raise error.ServerError(
            'Invalid response received from the server, cannot '
            'initialize contest. Check that the contest id is '
            'valid: {0}.\n'.format(e))
Example #4
0
    def _ParseResult(self, response_data, io_set_public):
        """Extract the result from the server response data.

    Args:
      response_data: The response body obtained from the server, which is
        formatted like a python dictionary.
      io_set_public: Boolean indicating whether the answer is public or not.

    Returns:
      The returned message from the server, or the string 'No message found' if
      there was no answer message.

    Raises:
      error.ServerError: If the server response is malformed.
    """
        # Convert the response data to a dictionary and return the message.
        try:
            result = json.loads(response_data)
            msg = result.get('msg', 'No message found')
            if not result.get('hasAnswer', False):
                return 'Rejected: ' + msg
            elif not io_set_public:
                return 'Submitted: ' + msg
            elif result.get('ok', False):
                return 'Correct: ' + msg
            else:
                return 'Incorrect: ' + msg
        except ValueError as e:
            raise error.ServerError(
                'Invalid response received from the server, '
                'cannot submit solution. Check that the host, '
                'user and contest id are valid: {0}.\n'.format(e))
Example #5
0
    def FromJsonResponse(json_response, problems):
        """Convert a JSON response with a submission into a more usable format.

    Args:
      json_response: JSON response recevied from the server that must be parsed.
      problems: Iterable with all problems in the current contest.

    Returns:
      An UserSubmission object with the parsed json_response.

    Raises:
      error.ServerError: An error
    """
        # Extract information needed from the JSON response.
        try:
            submission_key = json_response['k']
            problem_key = json_response['p']
            input_id = json_response['d']
            status = json_response['s']
            timestamp = json_response['t']
        except KeyError as e:
            raise error.ServerError('Cannot find field {0} in user '
                                    'submission.\n'.format(e))

        # Parse information into a more usable format and return an user submission.
        problem_index = utils.GetProblemIndexFromKey(problems, problem_key)
        parsed_timestamp = UserSubmission._ConvertTimestampToSeconds(timestamp)
        return UserSubmission(submission_key, problem_index, input_id, status,
                              parsed_timestamp)
Example #6
0
    def FromJsonResponse(json_response, input_spec):
        """Construct an UserStatus object using a server json_response.

    Args:
      json_response: JSON response returned by the server when asked for the
          current user status.
      input_spec: List of (input_name, time_limit) tuples, each one specifying
          the type of inputs per problem.

    Returns:
      An UserStatus object with the information contained in the json_response,
      or None if the user is not participating/did not participate in this
      contest.

    Raises:
      error.ServerError: If there is a key missing from the server response.
    """
        try:
            # Extract the rank and check if the user is participating or participated
            # in this contest.
            rank = json_response['rank']
            if rank == -1:
                return None

            # Extract problem information from the response and create problem input
            # status objects for each problem.
            json_attempts = json_response['a']
            json_solved_time = json_response['s']
            json_current = json_response['p']
            json_submitted = json_response['submitted']
            plain_problem_inputs = []
            for index, (attempts, solved, current_passed,
                        submitted) in enumerate(
                            zip(json_attempts, json_solved_time, json_current,
                                json_submitted)):
                # Remove the correct submission and the current attempt from the wrong
                # tries, if any.
                wrong_tries = attempts
                if solved != -1: wrong_tries -= 1
                if current_passed != -1: wrong_tries -= 1

                # Get the input type and time left for this input, then create a problem
                # input status object for it.
                input_type, total_time = input_spec[index % len(input_spec)]
                time_left = -1 if current_passed == -1 else total_time - current_passed
                plain_problem_inputs.append(
                    ProblemInputStatus(input_type, solved, wrong_tries,
                                       time_left, bool(submitted)))

            # Extract the user status and clusterize the problem inputs. Then return
            # an user status object with the extracted information.
            points = json_response['pts']
            problem_inputs = _ClusterByGroups(plain_problem_inputs,
                                              len(input_spec))
            return UserStatus(rank, points, problem_inputs)

        except KeyError as e:
            raise error.ServerError('Cannot find needed key in server status '
                                    'response: {0}.\n'.format(e))
Example #7
0
    def FromJsonResponse(json_response, problems):
        """Construct an UserStatus object using a server json_response.

    Args:
      json_response: JSON response returned by the server when asked for the
          current user status.
      problems: List with all problems in the contest.

    Returns:
      An UserStatus object with the information contained in the json_response,
      or None if the user is not participating/did not participate in this
      contest.

    Raises:
      error.ServerError: If there is a key missing from the server response.
    """
        try:
            # Extract the rank and check if the user is participating or participated
            # in this contest.
            rank = json_response['rank']
            if rank == -1:
                return None

            # Extract problem information from the response and create problem input
            # status objects for each problem.
            json_attempts = json_response['a']
            json_solved_time = json_response['s']
            json_current = json_response['p']
            json_submitted = json_response['submitted']
            json_points = json_response['pts']

        except KeyError as e:
            raise error.ServerError('Cannot find needed key in server status '
                                    'response: {0}.\n'.format(e))

        # Get a list of with all I/O sets' status, see _ConstructProblemInputStatus
        # for more details.
        io_set_status = []
        for index, (attempts, solved, current_passed, submitted) in enumerate(
                itertools.izip(json_attempts, json_solved_time, json_current,
                               json_submitted)):
            # Remove the correct submission and the current attempt from the wrong
            # tries, if any.
            wrong_tries = attempts
            if solved != -1: wrong_tries -= 1
            if current_passed != -1: wrong_tries -= 1

            # Store a tuple for this I/O set, which is used when constructing the
            # final UserStatus.
            io_set_status.append(
                (solved, wrong_tries, current_passed, bool(submitted)))

        # Return an user status object with the extracted information.
        problem_inputs = UserStatus._ConstructProblemInputStatus(
            problems, io_set_status)
        return UserStatus(rank, json_points, problem_inputs)
Example #8
0
def GetCurrentContestId(host, cookie, tournament_id):
    # Send an HTTP request to get the problem list from the server.
    sys.stdout.write('Getting current contest of tournament {0} from '
                     '"{1}"...\n'.format(tournament_id, host))
    request_arguments = {
        't': tournament_id,
        'zx': str(int(time.time())),
    }
    request_headers = {
        'Referer': 'http://{0}/codejam',
        'Cookie': cookie,
    }
    try:
        status, reason, response = http_interface.Get(
            host, '/codejam/contest/microsite-info', request_arguments,
            request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError(
            'HTTP exception while retrieving current contest '
            'from the Google Code Jam server: '
            '{0}.\n'.format(e))

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'get current contest. Check that the host and '
            'username are valid.\n')

    # Parse the JSON response and extract the contest status from it.
    try:
        json_response = json.loads(response)
        return json_response.get('contestId', None)
    except ValueError as e:
        raise error.ServerError(
            'Invalid response received from the server, cannot '
            'get current contest. Check that the tournament id '
            'is valid: {0}.\n'.format(e))
Example #9
0
def GetUserStatus(host, cookie, middleware_token, contest_id, input_spec):
    """Get the current user's status from the server.

  Args:
    host: Domain name of the server where the contest is running.
    cookie: Cookie for the current user.
    middleware_token: Middleware authentication token for the current user.
    contest_id: Id of the contest where the user is participating.
    input_spec: Dictionary with the input specification, mapping from input name
        to another dictionary with a 'time_limit' key.

  Returns:
    An UserStatus object with the current user's status.

  Raises:
    error.ConfigurationError: If there is an input specification without time
      limit.
    error.NetworkError: If a network error occurs while communicating with the
      server.
    error.ServerError: If the server answers code distinct than 200 or the
      response is a malformed JSON.
  """
    # Send an HTTP request to get the user status.
    sys.stdout.write(
        'Getting user status at contest {0} from "{1}"...\n'.format(
            contest_id, host))
    request_referer = 'http://{0}/codejam/contest/dashboard?c={1}'.format(
        host, contest_id)
    request_arguments = {
        'cmd': 'GetUserStatus',
        'contest': contest_id,
        'zx': str(int(time.time())),
        'csrfmiddlewaretoken': str(middleware_token),
    }
    request_headers = {
        'Referer': request_referer,
        'Cookie': cookie,
    }
    try:
        status, reason, response = http_interface.Get(
            host, '/codejam/contest/dashboard/do', request_arguments,
            request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError(
            'HTTP exception while user status from the Google '
            'Code Jam server: {0}.\n'.format(e))

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'get user status. Check that the host, username '
            'and contest id are valid.\n')

    # Sort and extract information from the input specification.
    try:
        parsed_input_spec = [
            (input_data['input_id'], input_name, input_data['time_limit'])
            for input_name, input_data in input_spec.iteritems()
        ]
        parsed_input_spec.sort()
        input_spec = [input_data[1:] for input_data in parsed_input_spec]
    except KeyError:
        raise error.ConfigurationError(
            'Wrong input specification, "time_limit" '
            'key not found.\n')

    # Parse the JSON response and return an object with the user status.
    try:
        json_response = json.loads(response)
        return UserStatus.FromJsonResponse(json_response, input_spec)
    except ValueError as e:
        raise error.ServerError(
            'Invalid response received from the server, cannot '
            'get user status. Check that the contest id is '
            'valid: {0}.\n'.format(e))
Example #10
0
    def Submit(self,
               input_id,
               output_name,
               source_patterns,
               io_set_public,
               gzip_body=True,
               zip_sources=False,
               add_ignored_zips=False):
        """Submit the specified output and sources file to the problem.

    Args:
      input_id: Identifier of the output to submit ('0' for the small output,
        '1' for the large output).
      output_name: Name of the file with the output data.
      source_patterns: Name patterns of the source files to be included with the
        output. These patterns will be expanded using Python's glob module.
      io_set_public: Boolean indicating whether the answer is public or not.
      gzip_body: Boolean indicating whether the body has to be gzipped or not.
      zip_sources: Boolean indicating whether all sources should be put inside a
        zip file or not.
      add_ignored_zips: Boolean indicating whether zip files that are not
        included directly but are inside a included directory should be
        submitted or not.

    Raises:
      error.InternalError: If an error occurs while copying ignored zip files
        to the final location.
      error.NetworkError: If a network error occurs while communicating with the
        server.
      error.ServerError: If the server answers code distinct than 200.
    """
        # Prepare the source files (zipping all directories). After this,
        # source_files will only contain text files and zip files specified directly
        # or by compressing a directory.
        source_files, ignored_zips = self._PrepareSourceFiles(
            set(source_patterns))

        # Check if the user requested to zip source files.
        if zip_sources:
            # Extract all files to zip into a list and remove them from the
            # source files list.
            sources_to_zip = [
                filename for filename, file_data in source_files
                if file_data is None
            ]
            source_files = [(filename, file_data)
                            for filename, file_data in source_files
                            if file_data is not None]

            # Generate a zip file with all the flat source files.
            sys.stdout.write('Compressing files "{0}"...\n'.format(
                ', '.join(sources_to_zip)))
            zipped_sources, _ = zip_utils.MakeZipFileInMemory(
                sources_to_zip, ignore_exts=['.zip'])

            # Generate a random name for the zipped source files and add it to the
            # source files to send.
            zip_filename = '__plain_files_{0}.zip'.format(
                random.randrange(0, 2**31 - 1))
            source_files.append((zip_filename, zipped_sources))

        # Check if the user requested to add the ignored zip files inside included
        # directories.
        if add_ignored_zips:
            # Copy and add each ignored file to the source list.
            for ignored_zip in ignored_zips:
                # Read the contents of the ignored zip file.
                try:
                    zip_file = open(ignored_zip, 'rb')
                    zip_file_contents = zip_file.read()
                    zip_file.close()
                except IOError as e:
                    raise error.InternalError(
                        'I/O error happened while read zip file '
                        '"{0}": {1}.\n'.format(ignored_zip, e))

                # Generate the zip flat filename by substituting path with underscores
                # and adding a random number to prevent collisions. Then use it to add
                # the zip file and its contents into the source files to send.
                path, ext = os.path.splitext(ignored_zip)
                zip_flat_filename = '{1}_{0}{2}'.format(
                    random.randrange(0, 2**31 - 1),
                    path.replace('\\', '_').replace('/', '_'), ext)
                source_files.append((zip_flat_filename, zip_file_contents))

        # Print message and check that at least one source file was included.
        if source_files:
            sources_str = ', '.join('"{0}"'.format(filename)
                                    for filename, _ in source_files)
            sys.stdout.write(
                'Sending output file "{0}" and source(s) {1} to "{2}"'
                '...\n'.format(output_name, sources_str, self.host))
        else:
            # Print warning saying that no source file is being included, this might
            # cause disqualification in a real contest.
            sys.stdout.write(
                'Warning, no source files are being sent for output '
                'file "{0}"!\n'.format(output_name))
            sys.stdout.write('Sending output file "{0}" to "{1}"...\n'.format(
                output_name, self.host))

        # Generate a random boundary string to separate multipart data and
        # create a multipart data object with it. Then fill it with the necessary
        # arguments.
        multipart_boundary = '----gcjMultipartBoundary{0}'.format(
            random.randrange(0, 2**31 - 1))
        body_data = multipart_data.MultipartData(multipart_boundary)
        body_data.AddString('csrfmiddlewaretoken', self.middleware_token)
        body_data.AddFile('answer', output_name)
        for i, (filename, file_data) in enumerate(source_files):
            body_data.AddFile('source-file{0}'.format(i), filename, file_data)
            body_data.AddString('source-file-name{0}'.format(i), filename)
        body_data.AddString('cmd', 'SubmitAnswer')
        body_data.AddString('contest', self.contest_id)
        body_data.AddString('problem', self.problem_id)
        body_data.AddString('input_id', input_id)
        body_data.AddString('num_source_files', str(len(source_files)))
        body_data.AddString('agent', constants.CODEJAM_AGENT_NAME)

        # Get the message body and check if compression was requested.
        request_body = str(body_data)
        if gzip_body:
            compressed_body = zip_utils.ZipData(request_body)
            sys.stdout.write('Sending {0} bytes to server ({1} uncompressed)'
                             '...\n'.format(len(compressed_body),
                                            len(request_body)))
            request_body = compressed_body
        else:
            sys.stdout.write('Sending {0} bytes to server...\n'.format(
                len(request_body)))

        # Send an HTTP request with the output file and the source files.
        request_url = '/codejam/contest/dashboard/do'
        request_referer = 'http://{0}/codejam/contest/dashboard?c={1}'.format(
            self.host, self.contest_id)
        request_arguments = {}
        request_headers = {
            'Content-Encoding':
            'gzip' if gzip_body else 'text/plain',
            'Content-Type':
            'multipart/form-data; boundary={0}'.format(multipart_boundary),
            'Referer':
            request_referer,
            'Cookie':
            self.cookie,
        }
        try:
            status, reason, response = http_interface.Post(
                self.host, request_url, request_arguments, request_headers,
                request_body)
        except httplib.HTTPException as e:
            raise error.NetworkError(
                'HTTP exception while sending solution to the '
                'Google Code Jam server: {0}.\n'.format(e))

        # Check if the status is not good.
        if status != 200 or reason != 'OK':
            raise error.ServerError(
                'Error while communicating with the server, '
                'cannot submit solution. Check that the host, '
                'username and contest id are valid.\n')

        # Check if the server accepted the input or just ignored it. If it
        # accepted it, parse the response and print the submission result.
        if response:
            submit_result = self._ParseResult(response, io_set_public)
            sys.stdout.write('{0}\n'.format(submit_result))
        else:
            raise error.ServerError(
                'No response received from the server. This generally happens if '
                'you try to submit the large output before solving the small '
                'input.\n')
Example #11
0
    def Download(self, input_id, filename):
        """Download the specified input and store it in the specified file.

    Args:
      input_id: Identifier of the input to download ('0' for the small input
          and '1' for the large input).
      filename: Name of the file where the input data must be stored.
    """
        # Send an HTTP request to get the input file from the server.
        sys.stdout.write('Getting input file "{0}" from "{1}"...\n'.format(
            filename, self.host))
        request_url = '/codejam/contest/dashboard/do/{0}'.format(filename)
        request_referer = 'http://{0}/codejam/contest/dashboard?c={1}'.format(
            self.host, self.contest_id)
        request_arguments = {
            'cmd': 'GetInputFile',
            'contest': self.contest_id,
            'problem': str(self.problem_id),
            'input_id': input_id,
            'filename': filename,
            'input_file_type': '0',
            'csrfmiddlewaretoken': self.middleware_token,
            'agent': constants.CODEJAM_AGENT_NAME,
        }
        request_headers = {
            'Referer': request_referer,
            'Cookie': self.cookie,
        }
        try:
            status, reason, response = http_interface.Get(
                self.host, request_url, request_arguments, request_headers)
        except httplib.HTTPException as e:
            raise error.NetworkError(
                'HTTP exception while getting input file: '
                '{0}.\n'.format(e))

        # Check if the status is not good.
        if status != 200 or reason != 'OK':
            raise error.ServerError(
                'Error while communicating with the server, '
                'cannot download input. Check that the host, '
                'username and contest id are valid.\n')

        # No response from the server, output warning.
        if not response:
            raise error.ServerError(
                'No response received from the server. This generally happens when:\n'
                '  - You try to download a small input but it is already solved.\n'
                '  - You try to download the large input before solving the small '
                'input.\n'
                '  - You try to redownload the large but its timer already '
                'expired.\n')

        # Write response to the desired file.
        try:
            input_file = open(filename, 'wt')
            input_file.write(response)
            input_file.close()
            sys.stdout.write(
                'File "{0}" downloaded successfully.\n'.format(filename))
        except IOError as e:
            raise error.InternalError('I/O error while writing file "{0}": '
                                      '{1}.\n'.format(filename, e))
Example #12
0
def GetUserSubmissions(host, cookie, contest_id, problems):
    """Get the current user's submissions for the current contest.

  Args:
    host: Domain name of the server where the contest is running.
    cookie: Cookie for the current user.
    contest_id: Id of the contest where the user is participating.
    problems: Iterable with all problems in the current contest.

  Returns:
    A list of UserSubmission objects with the user submissions for the current
    contest.

  Raises:
    error.NetworkError: If a network error occurs while communicating with the
      server.
    error.ServerError: If the server answers code distinct than 200 or the
      response is a malformed JSON.
  """
    # Send an HTTP request to get the contest events.
    sys.stdout.write('Getting events of contest {0} from "{1}"...\n'.format(
        contest_id, host))
    request_referer = 'http://{0}/codejam/contest/dashboard?c={1}'.format(
        host, contest_id)
    request_arguments = {
        'cmd': 'GetEvents',
        'contest': contest_id,
        'zx': str(int(time.time())),
    }
    request_headers = {
        'Referer': request_referer,
        'Cookie': cookie,
    }
    try:
        status, reason, response = http_interface.Get(
            host, '/codejam/contest/dashboard/do', request_arguments,
            request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError(
            'HTTP exception while retrieving user submissions from the Google Code '
            'Jam server: {0}.\n'.format(e))

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'get contest events. Check that the host, username '
            'and contest id are valid.\n')

    # Parse the JSON response and extract the user submissions (or attempts).
    try:
        json_response = json.loads(response)
        submissions = json_response.get('a')
        if submissions is None:
            return None
    except ValueError as e:
        raise error.ServerError('Cannot parse JSON from server response: '
                                '{0}.\n'.format(e))

    # Process each user submission and return them in a list.
    return [
        UserSubmission.FromJsonResponse(submission, problems)
        for submission in submissions
    ]
Example #13
0
def CheckToolVersion(host, tool_version):
    """Check if the specified tool_version is accepted by the host.

  Args:
    host: Host where the contest is running.
    tool_version: String with this tool's version.

  Raises:
    error.InternalError: If the tool's version is not accepted by the host.
    error.NetworkError: If a network error occurs while communicating with the
      server.
    error.ServerError: If the server answers code distinct than 200 or the
      response is a malformed JSON.
  """
    # Send an HTTP request to get the problem list from the server.
    sys.stdout.write('Checking tool version for "{0}"...\n'.format(host))
    request_referer = 'http://{0}/codejam'.format(host)
    request_arguments = {
        'cmd': 'CheckVersion',
        'version': tool_version,
    }
    request_headers = {
        'Referer': request_referer,
    }
    try:
        status, reason, response = http_interface.Get(host, '/codejam/cmdline',
                                                      request_arguments,
                                                      request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError(
            'HTTP exception while checking tool version with '
            'the Google Code Jam server: {0}\n'.format(e))

    # The current server version might not support this yet. Print a warning
    # message and skip validation.
    if status == 404:
        print 'WARNING: Cannot check commandline version with the server.'
        return

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'check tool version. Check that the host is '
            'valid.\n')

    # Extract token information from server response.
    try:
        validation_info = json.loads(response)
        if validation_info['msg']:
            print validation_info['msg']
        if not validation_info['valid']:
            raise error.InternalError(
                'This tool\'s version is not accepted by host '
                '{0}, please update to the latest '
                'version.\n'.format(host, tool_version))
    except (KeyError, ValueError) as e:
        raise error.ServerError(
            'Invalid response received from the server, cannot '
            'initialize contest. Check that the contest id is '
            'valid: {0}.\n'.format(e))
Example #14
0
def _GetProblems(host, cookie, contest_id):
    """Read the problems of the specified contest.

  Args:
    host: Host where the contest is running.
    cookie: Cookie that the user received when authenticating.
    contest_id: ID of the contest whose problems must be read.

  Returns:
    A tuple with two lists, the first with the problem IDs and the second
    with the problem names.

  Raises:
    error.NetworkError: If a network error occurs while communicating with the
      server.
    error.ServerError: If the server answers code distinct than 200 or the
      response is a malformed JSON.
  """
    # Send an HTTP request to get the problem list from the server.
    sys.stdout.write(
        'Getting problem list of contest {0} from "{1}"...\n'.format(
            contest_id, host))
    request_referer = 'http://{0}/codejam/contest/dashboard?c={1}'.format(
        host, contest_id)
    request_arguments = {
        'cmd': 'GetProblems',
        'contest': contest_id,
    }
    request_headers = {
        'Referer': request_referer,
        'Cookie': cookie,
    }
    try:
        status, reason, response = http_interface.Get(
            host, '/codejam/contest/dashboard/do', request_arguments,
            request_headers)
    except httplib.HTTPException as e:
        raise error.NetworkError(
            'HTTP exception while retrieving problem '
            'information from the Google Code Jam server: '
            '{0}.\n'.format(e))

    # Check if the status is not good.
    if status != 200 or reason != 'OK':
        raise error.ServerError(
            'Error while communicating with the server, cannot '
            'get problem information. Check that the host, '
            'username and contest id are valid.\n')

    # Parse the JSON response and extract each problem from it.
    try:
        problems = []
        json_response = json.loads(response)
        for problem in json_response:
            problems.append({
                'key': problem['key'],
                'id': problem['id'],
                'name': problem['name']
            })
        return problems
    except (KeyError, ValueError) as e:
        raise error.ServerError(
            'Invalid response received from the server, cannot '
            'initialize contest. Check that the contest id is '
            'valid: {0}.\n'.format(e))