def put_file_with_creds(bucket, key, content, access_key, secret_key): """ Get a file from S3 using Specific Credentials :param bucket: name of bucket :param key: key id in bucket :param content: file body content :param access_key: user's access_key :param secret_key: user's secret_key :raise: AWSError: couldn't fetch file contents from S3 """ if key is None or len(key) <= 0: raise ValidationError("Key name cannot be empty.") if bucket is None or len(bucket) <= 0: raise ValidationError("Bucket name cannot be empty.") s3 = boto3.client("s3", aws_access_key_id=access_key, aws_secret_access_key=secret_key) try: s3.put_object( Bucket=bucket, Key=key, Body=content) except ClientError as error: raise AWSError("Problem putting {} from {} bucket ({})" .format(key, bucket, str(error))) return
def send_feedback(table_name, user_name, subject, message): """ Log feedback to website_feedback table Args: table_name: name of dynamodb table to pull feedback from user_name: unique id of user, username/email/uuid subject: string subject of user feedback message: string containing user feedback Returns: None Raises: AWSError: Could not write to database """ dynamodb = boto3.client('dynamodb') try: dynamodb.put_item(TableName=table_name, Item={ 'feedback_time': { 'N': str(systime.time()) }, 'user_name': { 'S': user_name }, 'subject': { 'S': subject }, 'message': { 'S': message }, }) except ClientError as error: raise AWSError('DynamoDB Error: {}'.format(str(error)))
def get_file_with_creds(bucket, key, access_key, secret_key): """ Get a file from S3 using Specific Credentials :param bucket: name of bucket :param key: key id in bucket :param access_key: user's access_key :param secret_key: user's secret_key :return: Stream object with contents :raise: AWSError: couldn't fetch file contents from S3 """ if key is None or len(key) <= 0: raise ValidationError("Key name cannot be empty.") if bucket is None or len(bucket) <= 0: raise ValidationError("Bucket name cannot be empty.") s3 = boto3.client("s3", aws_access_key_id=access_key, aws_secret_access_key=secret_key) try: response = s3.get_object(Bucket=bucket, Key=key) except ClientError as error: raise AWSError("Error loading file from S3: {}".format(str(error))) return response
def get_temp_link(bucket, key, key_id, secret_key, expiry=300): """ Get expiring S3 url with temp token NB: bucket must be in us-east-1 to use path addressing! :param bucket: name of bucket :param key: key id in bucket :param key_id: Amazon AWS API key id :param secret_key: Amazon AWS Secret API key :param expiry: number of seconds token is valid for (default=600) :return: Temporary S3 link to file using temp credentials :raise: AWSError: error getting presigned link from S3 """ session = Session( aws_access_key_id=key_id, aws_secret_access_key=secret_key ) s3_client = session.client("s3", config=Config(s3={'addressing_style': 'path'})) try: link = s3_client.generate_presigned_url( ExpiresIn=expiry, ClientMethod="get_object", Params={ "Bucket": bucket, "Key": key, } ) except ClientError as error: raise AWSError("Error generating temp link: {}".format(str(error))) return link
def put_object_metadata(bucket, key, meta_key, meta_value): """ Get file metadata from S3 :param bucket: name of bucket :param key: key id in bucket :param meta_key: key for updated metadata :param meta_value: value for updated metadata :return: S3 metadata object :raise: AWSError: couldn't load metadata from S3 """ # Get downloads file metadata from S3 bucket s3_client = boto3.client("s3") try: metadata = s3_client.head_object(Bucket=bucket, Key=key)["Metadata"] metadata[meta_key] = meta_value s3_client.copy_object( Bucket=bucket, Key=key, CopySource={ 'Bucket': bucket, 'Key': key, }, Metadata=metadata, MetadataDirective='REPLACE' ) except ClientError as error: raise AWSError("Error loading metadata from S3: {}".format(str(error)))
def get_binary_contents(bucket, key, config=None): """ Get file contents from S3 :param bucket: name of bucket :param key: key id in bucket :return: Stream object with contents :raise: AWSError: couldn't fetch file contents from S3 """ s3_resource = boto3.resource("s3") if config is None else boto3.resource("s3", config=config) try: response = s3_resource.Object(bucket, key).get() except ClientError as error: raise AWSError("Error loading file from S3: {}".format(str(error))) return response
def get_json_contents(bucket, key): """ Get json file from S3 :param bucket: name of bucket :param key: key id in bucket :return: JSON from S3 bucket :raise: AWSError: couldn't fetch file contents from S3 """ s3_resource = boto3.resource("s3") try: response = s3_resource.Object(bucket, key).get() except ClientError as error: raise AWSError("Error loading file from S3: {}".format(str(error))) return json.load(response["Body"])
def get_object_metadata(bucket, key): """ Get file metadata from S3 :param bucket: name of bucket :param key: key id in bucket :return: S3 metadata object :raise: AWSError: couldn't load metadata from S3 """ # Get downloads file metadata from S3 bucket s3_resource = boto3.resource("s3") obj = s3_resource.Object(bucket, key) try: obj.load() except ClientError as error: raise AWSError("Error loading metadata from S3: {}".format(str(error))) return obj
def get_feedback_digest(table_name, days=1): """ Get website feedback and return records timezones are shifted to account for EST Args: table_name: name of dynamodb table to pull feedback from days: optional number of days (starting from yesterday) to return feedback for (default 1) Returns: set of feedback objects or false if empty Raises: AWSError: dynamodb scan failed """ utc_timezone = UTC() eastern_timezone = USTimeZone(-5, "Eastern", "EST", "EDT") epoch = datetime(1970, 1, 1, tzinfo=utc_timezone) zero_time = time(0, 0, 0, 0, eastern_timezone) today = datetime.now(eastern_timezone) yesterday = today - timedelta(days) today = (datetime.combine(today, zero_time) - epoch).total_seconds() yesterday = (datetime.combine(yesterday, zero_time) - epoch).total_seconds() dynamodb = boto3.client('dynamodb') try: feedback = dynamodb.scan( TableName=table_name, FilterExpression='feedback_time BETWEEN :yesterday AND :today', ExpressionAttributeValues={ ':yesterday': { 'N': str(yesterday) }, ':today': { 'N': str(today) }, }) except ClientError as error: raise AWSError('DynamoDB Error: {}'.format(str(error))) if feedback['Count'] > 0: return feedback['Items'] else: return False
def put_doc_file(bucket, key, filename, url, caption=None, thumb=None): """ Appends to a file in S3 :param bucket: file bucket name :param key: key prefix :param filename: filename to be written :param url: location of filename :param caption: caption file contents :param thumb: thumbnail file contents :raise: AWSError: Error adding file to S3 bucket """ if key is None or len(key) <= 0: raise ValidationError("Key name cannot be empty.") s3_resource = boto3.resource("s3") timestr = datetime.now().strftime("%Y%m%d-%H:%M:%S.%f-") docobj = s3_resource.Object(bucket, key + "/" + timestr + filename) if caption is not None: capobj = s3_resource.Object(bucket, key + "/" + timestr + filename + ".cap") else: pass if thumb is not None: thumbobj = s3_resource.Object(bucket, key + "/" + timestr + filename) try: file_content = requests.get(url).content docobj.put(Body=file_content) if caption is not None: capobj.put(Body=caption) if thumb is not None: thumbobj.put(Body=str(thumb)) except ClientError as error: raise AWSError("Problem getting {} from {} bucket ({})" .format(key, bucket, str(error))) return
def save_request(chat_id, msg_id, user_name, event, table_name="MajlisMonitorBot"): """ Save a telegram request to dynamodb :param chat_id: telegram chat id from api :param msg_id: telegram msg id from api :param user_name: name of telegram user :param event: event that triggered lambda call :param table_name: optional table name (default="MajlisMonitorBot") :return: response object from put_item call :raise: AWSError: db call failed """ timestr = datetime.now().strftime("%Y%m%d-%H:%M:%S.%f.msg") message = str(chat_id) + str(msg_id) + "-" + str(user_name) record = { "datetime": { "S": timestr }, "message_id": { "S": message }, "request": { "S": str(event) }, } dynamodb = boto3.client("dynamodb") try: response = dynamodb.put_item(TableName=table_name, Item=record) except ClientError as error: raise AWSError("Problem writing to DB {} ({})".format( table_name, str(error))) return response
def put_text_file(bucket, key, text): """ Appends to a file in S3 :param bucket: file bucket name :param key: file key name :param text: text to be written :raise: AWSError: Error adding file to S3 bucket """ if key is None or len(key) <= 0: raise ValidationError("Key name cannot be empty.") s3_resource = boto3.resource("s3") timestr = datetime.now().strftime("%Y%m%d-%H:%M:%S.%f.msg") key = key + "/" + timestr s3_new_file = s3_resource.Object(bucket, key) try: s3_new_file.put(Body=text) except ClientError as error: raise AWSError("Problem getting object {} from {} ({})" .format(key, bucket, str(error))) return
def send_email(email_from, email_to, subject, text_body, html_body, file_name, file_data, src_email=None): """ Send email with text, html and attachment sections Args: email_from: address to send from email_to: address to send to subject: email subject line text_body: text/plain body of email html_body: text/html body of email, preferred display file_name: name of attachment file file_data: raw binary file data Returns: SES response object from AWS API Raises: FeedbackError: no body text provided or SES response is empty """ # Compose email with link or binary sesclient = boto3.client('ses', region_name='us-east-1') msg = MIMEMultipart() msg['Subject'] = str(subject) msg['From'] = email_from msg['To'] = email_to if html_body and text_body: email_content = MIMEMultipart('alternative') email_content.attach(MIMEText(text_body, 'plain', 'UTF-8')) email_content.attach(MIMEText(html_body, 'html', 'UTF-8')) msg.attach(email_content) elif text_body: msg.attach(MIMEText(text_body, 'plain', 'UTF-8')) else: raise ValidationError('No body text found') # attachment must be last part or clients won't show it if file_data: part = MIMEApplication(file_data) part.add_header('Content-Disposition', 'attachment', filename=file_name) msg.attach(part) try: if src_email == None: response = sesclient.send_raw_email( RawMessage={'Data': msg.as_string()}) else: response = sesclient.send_raw_email( Source=src_email, RawMessage={'Data': msg.as_string()}) except ClientError as error: raise AWSError('SendMail UnknownError: {}'.format(str(error))) if response is None: raise FeedbackError('Unknown Error: Return Value is None') return response