def post_to_mailgun(data): """Send POST HTTP request to mailgun api. This method is adopted from the requests library's post method. Args: - data: dict. The data to be sent in the request's body. Returns: Response from the server. The object is a file-like object. https://docs.python.org/2/library/urllib2.html """ if not feconf.MAILGUN_API_KEY: raise Exception('Mailgun API key is not available.') if not feconf.MAILGUN_DOMAIN_NAME: raise Exception('Mailgun domain name is not set.') encoded = base64.b64encode(b'api:%s' % feconf.MAILGUN_API_KEY).strip() auth_str = 'Basic %s' % encoded header = {'Authorization': auth_str} server = ( 'https://api.mailgun.net/v3/%s/messages' % feconf.MAILGUN_DOMAIN_NAME) data = python_utils.url_encode(data) req = python_utils.url_request(server, data, header) return python_utils.url_open(req)
def download_and_unzip_files( source_url, target_parent_dir, zip_root_name, target_root_name): """Downloads a zip file, unzips it, and saves the result in a given dir. The download occurs only if the target directory that the zip file unzips to does not exist. NB: This function assumes that the root level of the zip file has exactly one folder. Args: source_url: str. The URL from which to download the zip file. target_parent_dir: str. The directory to save the contents of the zip file to. zip_root_name: str. The name of the top-level folder in the zip directory. target_root_name: str. The name that the top-level folder should be renamed to in the local directory. """ if not os.path.exists(os.path.join(target_parent_dir, target_root_name)): python_utils.PRINT('Downloading and unzipping file %s to %s ...' % ( zip_root_name, target_parent_dir)) common.ensure_directory_exists(target_parent_dir) python_utils.url_retrieve(source_url, filename=TMP_UNZIP_PATH) try: with zipfile.ZipFile(TMP_UNZIP_PATH, 'r') as zfile: zfile.extractall(path=target_parent_dir) os.remove(TMP_UNZIP_PATH) except Exception: if os.path.exists(TMP_UNZIP_PATH): os.remove(TMP_UNZIP_PATH) # Some downloads (like jqueryui-themes) may require a user-agent. req = python_utils.url_request(source_url, None, {}) req.add_header('User-agent', 'python') # This is needed to get a seekable filestream that can be used # by zipfile.ZipFile. file_stream = python_utils.string_io( buffer_value=python_utils.url_open(req).read()) with zipfile.ZipFile(file_stream, 'r') as zfile: zfile.extractall(path=target_parent_dir) # Rename the target directory. os.rename( os.path.join(target_parent_dir, zip_root_name), os.path.join(target_parent_dir, target_root_name)) python_utils.PRINT('Download of %s succeeded.' % zip_root_name)
def lookup_pr(owner, repo, pull_number): """Lookup a PR using the GitHub API. Args: owner: str. Owner of the repository the PR is in. repo: str. Repository the PR is in. pull_number: str. PR number. Returns: dict. JSON object returned by the GitHub API v3. This is an empty dictionary if the response code from the GitHub API is not 200. """ request = python_utils.url_request( GITHUB_API_PR_ENDPOINT % (owner, repo, pull_number), None, {'Accept': 'application/vnd.github.v3+json'}) response = python_utils.url_open(request) if response.getcode() != 200: return {} pr = json.load(response) response.close() return pr
def send_email_to_recipients(sender_email, recipient_emails, subject, plaintext_body, html_body, bcc=None, reply_to=None, recipient_variables=None): """Send POST HTTP request to mailgun api. This method is adopted from the requests library's post method. Args: sender_email: str. The email address of the sender. This should be in the form 'SENDER_NAME <SENDER_EMAIL_ADDRESS>' or 'SENDER_EMAIL_ADDRESS'. Must be utf-8. recipient_emails: list(str). The email addresses of the recipients. Must be utf-8. subject: str. The subject line of the email, Must be utf-8. plaintext_body: str. The plaintext body of the email. Must be utf-8. html_body: str. The HTML body of the email. Must fit in a datastore entity. Must be utf-8. bcc: list(str)|None. Optional argument. List of bcc emails. reply_to: str|None. Optional argument. Reply address formatted like “reply+<reply_id>@<incoming_email_domain_name> reply_id is the unique id of the sender. recipient_variables: dict|None. Optional argument. If batch sending requires differentiating each email based on the recipient, we assign a unique id to each recipient, including info relevant to that recipient so that we can reference it when composing the email like so: recipient_variables = {"*****@*****.**": {"first":"Bob", "id":1}, "*****@*****.**": {"first":"Alice", "id":2}} subject = 'Hey, %recipient.first%’ More info about this format at: https://documentation.mailgun.com/en/ latest/user_manual.html#batch-sending. Raises: Exception. The mailgun api key is not stored in feconf.MAILGUN_API_KEY. Exception. The mailgun domain name is not stored in feconf.MAILGUN_DOMAIN_NAME. Returns: bool. Whether the emails are sent successfully. """ if not feconf.MAILGUN_API_KEY: raise Exception('Mailgun API key is not available.') if not feconf.MAILGUN_DOMAIN_NAME: raise Exception('Mailgun domain name is not set.') # To send bulk emails we pass list of recipients in 'to' paarameter of # post data. Maximum limit of recipients per request is 1000. # For more detail check following link: # https://documentation.mailgun.com/user_manual.html#batch-sending recipient_email_lists = [ recipient_emails[i:i + 1000] for i in python_utils.RANGE(0, len(recipient_emails), 1000) ] for email_list in recipient_email_lists: data = { 'from': sender_email, 'subject': subject, 'text': plaintext_body, 'html': html_body } data['to'] = email_list[0] if len(email_list) == 1 else email_list if bcc: data['bcc'] = bcc[0] if len(bcc) == 1 else bcc if reply_to: data['h:Reply-To'] = reply_to # 'recipient-variable' in post data forces mailgun to send individual # email to each recipient (This is intended to be a workaround for # sending individual emails). data['recipient_variables'] = recipient_variables or {} encoded = base64.b64encode(b'api:%s' % feconf.MAILGUN_API_KEY).strip() auth_str = 'Basic %s' % encoded header = {'Authorization': auth_str} server = (('https://api.mailgun.net/v3/%s/messages') % feconf.MAILGUN_DOMAIN_NAME) encoded_url = python_utils.url_encode(data) req = python_utils.url_request(server, encoded_url, header) resp = python_utils.url_open(req) # The function url_open returns a file_like object that can be queried # for the status code of the url query. If it is not 200, the mail query # failed so we return False (this function did not complete # successfully). if resp.getcode() != 200: return False return True
def test_url_request(self): response = python_utils.url_request('http://www.google.com', None, {}) self.assertEqual(response.get_full_url(), 'http://www.google.com')