def send_failure_alert(printer): if not settings.EMAIL_HOST: LOGGER.warn("Email settings are missing. Ignored send requests") return subject = 'Your print {} may be failing on {}'.format( printer.current_print_filename or '', printer.name) from_email = settings.DEFAULT_FROM_EMAIL ctx = { 'printer': printer, 'view_link': site.build_full_url('/printers/'), 'cancel_link': site.build_full_url('/printers/{}/cancel/'.format(printer.id)), 'resume_link': site.build_full_url('/printers/{}/resume/?mute_alert=true'.format( printer.id)), } message = get_template('email/failure_alert.html').render(ctx) msg = EmailMessage(subject, message, to=(printer.user.email, ), from_email=from_email) msg.content_subtype = 'html' msg.send()
def send_failure_alert_email(printer, is_warning, print_paused): if not settings.EMAIL_HOST: LOGGER.warn("Email settings are missing. Ignored send requests") return subject = 'Your print {} on {} {}.'.format( printer.current_print.filename or '', printer.name, 'smells fishy' if is_warning else 'is probably failing') ctx = { 'printer': printer, 'print_paused': print_paused, 'is_warning': is_warning, 'view_link': site.build_full_url('/printers/'), 'cancel_link': site.build_full_url('/printers/{}/cancel/'.format(printer.id)), 'resume_link': site.build_full_url('/printers/{}/resume/'.format(printer.id)), } unsub_url = site.build_full_url( f'/unsubscribe_email/?unsub_token={printer.user.unsub_token}&list=alert' ) send_email( printer.user, subject, unsub_url, 'email/failure_alert.html', ctx, img_url=printer.pic['img_url'], )
def send_print_notification_email(_print, extra_ctx={}, event_type=None): ctx = { 'print': _print, 'timelapse_link': site.build_full_url(f'/prints/{_print.id}/'), 'user_pref_url': site.build_full_url('/user_preferences/'), } if event_type == PrintEvent.FILAMENT_CHANGE: subject = f'{_print.filename} requires filament change.' template_path = 'email/filament_change_req_notification.html' else: subject = f'{_print.filename} is canceled.' if _print.is_canceled( ) else f'🙌 {_print.filename} is ready.' template_path = 'email/print_notification.html' ctx['print_time'] = str(_print.ended_at() - _print.started_at).split('.')[0], ctx.update(extra_ctx) send_email( user=_print.printer.user, subject=subject, mailing_list='print_notification', template_path=template_path, ctx=ctx, img_url=_print.poster_url, )
def send_failure_alert_email(printer, rotated_jpg_url, is_warning, print_paused): if not settings.EMAIL_HOST: LOGGER.warn("Email settings are missing. Ignored send requests") return subject = 'Your print {} on {} {}.'.format( printer.current_print.filename or '', printer.name, 'smells fishy' if is_warning else 'is probably failing') ctx = { 'printer': printer, 'print_paused': print_paused, 'is_warning': is_warning, 'view_link': site.build_full_url('/printers/'), 'cancel_link': site.build_full_url('/prints/{}/cancel/'.format( printer.current_print_id)), 'resume_link': site.build_full_url('/prints/{}/resume/'.format( printer.current_print_id)), } send_email( user=printer.user, subject=subject, mailing_list='alert', template_path='email/failure_alert.html', ctx=ctx, img_url=rotated_jpg_url, )
def inline_markup(printer, buttons=['more_info']): links = { 'cancel': { 'text': 'Yes it failed. Cancel the print!', 'url': site.build_full_url('/printers/{}/cancel/'.format(printer.id)) }, 'resume': { 'text': 'It is a false alarm. Resume the print!', 'url': site.build_full_url('/printers/{}/resume/'.format(printer.id)) }, 'do_not_ask': { 'text': 'Resume the print, and don\'t alert me for the rest of this print.', 'url': site.build_full_url('/printers/{}/resume/?mute_alert=true'.format( printer.id)) }, 'more_info': { 'text': 'Go to The Spaghetti Detective to take a closer look.', 'url': site.build_full_url('/printers/') } } button_list = [ types.InlineKeyboardButton(links[button]['text'], url=links[button]['url']) for button in buttons ] markup = types.InlineKeyboardMarkup(row_width=1) markup.add(*button_list) return markup
def send_failure_alert_email(printer, is_warning, print_paused): if not settings.EMAIL_HOST: LOGGER.warn("Email settings are missing. Ignored send requests") return # https://github.com/TheSpaghettiDetective/TheSpaghettiDetective/issues/43 try: if ipaddress.ip_address(urlparse( printer.pic['img_url']).hostname).is_global: attachments = [] else: attachments = [('Detected Failure.jpg', requests.get(printer.pic['img_url']).content, 'image/jpeg')] except: attachments = [] subject = 'Your print {} on {} {}.'.format( printer.current_print.filename or '', printer.name, 'smells fishy' if is_warning else 'is probably failing') from_email = settings.DEFAULT_FROM_EMAIL ctx = { 'printer': printer, 'print_paused': print_paused, 'is_warning': is_warning, 'view_link': site.build_full_url('/printers/'), 'cancel_link': site.build_full_url('/printers/{}/cancel/'.format(printer.id)), 'resume_link': site.build_full_url('/printers/{}/resume/?mute_alert=true'.format( printer.id)), 'insert_img': len(attachments) == 0, } # By default email verification should be required for notifications but # maybe users will want to disable it on private servers if settings.ACCOUNT_EMAIL_VERIFICATION != 'none': emails = EmailAddress.objects.filter(user=printer.user, verified=True) else: emails = EmailAddress.objects.filter(user=printer.user) message = get_template('email/failure_alert.html').render(ctx) for email in emails: msg = EmailMessage(subject, message, to=(email.email, ), from_email=from_email, attachments=attachments) msg.content_subtype = 'html' msg.send()
def send_print_notification_pushbullet(_print): if not _print.printer.user.has_valid_pushbullet_token(): return pb = Pushbullet(_print.printer.user.pushbullet_access_token) title = 'The Spaghetti Detective - Print job notification' link = site.build_full_url('/') body = f"Your print job {_print.filename} {'has been canceled' if _print.is_canceled() else 'is done'} on printer {_print.printer.name}." file_url = None try: file_url = _print.printer.pic['img_url'] if not ipaddress.ip_address(urlparse(file_url).hostname).is_global: pb.upload_file(requests.get(file_url).content, 'Snapshot.jpg') except: pass try: if file_url: pb.push_file(file_url=file_url, file_name="Snapshot.jpg", file_type="image/jpeg", body=body, title=title) else: pb.push_link(title, link, body) except (PushError, PushbulletError) as e: LOGGER.error(e)
def send_failure_alert_pushover(printer, rotated_jpg_url, is_warning, print_paused): if not printer.user.pushover_user_token: return try: photo = requests.get(rotated_jpg_url).content except: photo = None pausing_msg = '' if print_paused: pausing_msg = 'Printer is paused.' elif printer.action_on_failure == Printer.PAUSE and is_warning: pausing_msg = 'Printer is NOT paused because The Detective is not very sure about it.' title = 'The Spaghetti Detective - Failure alert!' msg = 'Your print {} on {} {}.'.format( printer.current_print.filename or '', printer.name, 'smells fishy' if is_warning else 'is probably failing') link = site.build_full_url('/') body = '{}\n{}\nGo check it at: {}'.format(msg, pausing_msg, link) priority = PushoverPriority.HIGH try: pushover_notification(printer.user.pushover_user_token, body, title, photo, priority) except (PushoverException) as e: LOGGER.error(e)
def send_failure_alert_pushbullet(printer, is_warning, print_paused): if not printer.user.has_valid_pushbullet_token(): return pausing_msg = '' if print_paused: pausing_msg = 'Printer is paused.' elif printer.action_on_failure == Printer.PAUSE and is_warning: pausing_msg = 'Printer is NOT paused because The Detective is not very sure about it.' pb = Pushbullet(printer.user.pushbullet_access_token) title = 'The Spaghetti Detective - Your print {} on {} {}.'.format( printer.current_print.filename or '', printer.name, 'smells fishy' if is_warning else 'is probably failing') link = site.build_full_url('/') body = '{}\nGo check it at: {}'.format(pausing_msg, link) try: file_url = None try: file_url = printer.pic['img_url'] if not ipaddress.ip_address(urlparse(file_url).hostname).is_global: pb.upload_file(requests.get(file_url).content, 'Detected Failure.jpg') except: pass if file_url: pb.push_file(file_url=file_url, file_name="Detected Failure.jpg", file_type="image/jpeg", body=body, title=title) else: pb.push_link(title, link, body) except PushError as e: LOGGER.error(e) except PushbulletError as e: LOGGER.error(e)
def send_timelapse_detection_done_email(_print): if not settings.EMAIL_HOST: LOGGER.warn("Email settings are missing. Ignored send requests") return subject = 'The Detective is done looking at the time-lapse you uploaded.' from_email = settings.DEFAULT_FROM_EMAIL ctx = { 'print': _print, 'unsub_url': 'https://app.thespaghettidetective.com/ent/email_unsubscribe/?list=notification&email={}' .format(_print.user.email), 'prints_link': site.build_full_url('/prints/'), } emails = [ email.email for email in EmailAddress.objects.filter(user=_print.user) ] message = get_template('email/upload_print_processed.html').render(ctx) msg = EmailMessage( subject, message, to=emails, from_email=from_email, headers={ 'List-Unsubscribe': '<{}>, <mailto:[email protected]?subject=Unsubscribe_notification>' .format(ctx['unsub_url']) }, ) msg.content_subtype = 'html' msg.send()
def send_failure_alert(self, context: FailureAlertContext) -> None: chat_id = self.get_chat_id_from_config(context.config) if not chat_id: return link = site.build_full_url('/printers/') text = self.get_failure_alert_text(context=context, link=link) if not text: return buttons = ['more_info'] if context.print_paused: buttons = ['cancel', 'resume', 'do_not_ask', 'more_info'] elif context.printer.pause_on_failure and context.is_warning: buttons = ['cancel', 'more_info'] message = f"Hi {context.user.first_name},\n{text}" try: file_content = requests.get(context.img_url).content except: file_content = None markups = self.inline_buttons( context, buttons) if file_content else self.default_button() self.call_telegram( chat_id=chat_id, message=message, markups=markups, file_content=file_content, )
def send_print_notification_pushbullet(_print, event_type=None): if not _print.printer.user.has_valid_pushbullet_token(): return pb = Pushbullet(_print.printer.user.pushbullet_access_token) title = 'The Spaghetti Detective - Print job notification' link = site.build_full_url('/') body = get_notification_body(_print, event_type=event_type) file_url = None try: file_url = _print.poster_url if not settings.SITE_IS_PUBLIC: pb.upload_file(requests.get(file_url).content, 'Snapshot.jpg') except: pass try: if file_url: pb.push_file(file_url=file_url, file_name="Snapshot.jpg", file_type="image/jpeg", body=body, title=title) else: pb.push_link(title, link, body) except (PushError, PushbulletError) as e: LOGGER.error(e)
def send_failure_alert_sms(printer, is_warning, print_paused): if not settings.TWILIO_ENABLED: LOGGER.warn("Twilio settings are missing. Ignored send requests") return if not printer.user.sms_eligible(): return twilio_client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) from_number = settings.TWILIO_FROM_NUMBER to_number = printer.user.phone_country_code + printer.user.phone_number pausing_msg = '' if print_paused: pausing_msg = 'Printer is paused. ' elif printer.action_on_failure == Printer.PAUSE and is_warning: pausing_msg = 'Printer is NOT paused. ' msg = 'The Spaghetti Detective - Your print {} on {} {}. {}Go check it at: {}'.format( printer.current_print.filename or '', printer.name, 'smells fishy' if is_warning else 'is probably failing', pausing_msg, site.build_full_url('/')) twilio_client.messages.create(body=msg, to=to_number, from_=from_number)
def default_markup(): markup = types.InlineKeyboardMarkup(row_width=1) markup.add( types.InlineKeyboardButton( 'Go to The Spaghetti Detective to take a closer look.', url=site.build_full_url('/printers/'))) return markup
def send_print_notification_email(_print, extra_ctx={}): subject = f'{_print.filename} is canceled.' if _print.is_canceled( ) else f'🙌 {_print.filename} is ready.' ctx = { 'print': _print, 'print_time': str(_print.ended_at() - _print.started_at).split('.')[0], 'timelapse_link': site.build_full_url(f'/prints/{_print.id}/'), 'user_pref_url': site.build_full_url(f'/user_preferences/'), } ctx.update(extra_ctx) send_email( user=_print.printer.user, subject=subject, mailing_list='print_notification', template_path='email/print_notification.html', ctx=ctx, img_url=_print.poster_url, )
def send_test_message(self, context: TestMessageContext) -> None: access_token = self.get_access_token_from_config(context.config) link = site.build_full_url('/') self.call_pushbullet( access_token=access_token, title='Test Notification', body='It works', link=link, file_url='', )
def save_file_obj(dest_path, file_obj, container): fqp = path.join(settings.MEDIA_ROOT, container, dest_path) if not path.exists(path.dirname(fqp)): os.makedirs(path.dirname(fqp)) with open(fqp, 'wb+') as dest_file: copyfileobj(file_obj, dest_file) uri = '{}{}/{}'.format(settings.MEDIA_URL, container, dest_path) return settings.INTERNAL_MEDIA_HOST + uri, site.build_full_url(uri)
def send_print_notification_email(_print): subject = f'{_print.filename} is canceled.' if _print.is_canceled( ) else f'🙌 {_print.filename} is ready.' ctx = { 'print': _print, 'print_time': str(_print.ended_at() - _print.started_at).split('.')[0], 'timelapse_link': site.build_full_url('/prints/'), } unsub_url = site.build_full_url( f'/unsubscribe_email/?unsub_token={_print.printer.user.unsub_token}&list=print_notification' ) send_email( _print.printer.user, subject, unsub_url, 'email/print_notification.html', ctx, img_url=_print.printer.pic['img_url'] if _print.printer.pic else None, )
def send_failure_alert(self, context: FailureAlertContext) -> None: if not settings.TWILIO_ENABLED: LOGGER.warn("Twilio settings are missing. Ignored send requests") return to_number = self.get_number_from_config(context.config) link = site.build_full_url('/printers/') text = self.get_failure_alert_text(context=context, link=link) if not text or not to_number: return return self.send_sms(body=text, to_number=to_number)
def send_email(user, subject, mailing_list, template_path, ctx, img_url=None, verified_only=True, attachment=None): if not settings.EMAIL_HOST: LOGGER.warn("Email settings are missing. Ignored send requests") return attachments = [] if img_url: # https://github.com/TheSpaghettiDetective/TheSpaghettiDetective/issues/43 try: if not ipaddress.ip_address(urlparse(img_url).hostname).is_global: attachments = [('Image.jpg', requests.get(img_url).content, 'image/jpeg')] except: pass ctx['img_url'] = None if attachments else img_url # By default email verification should be required for notifications but # maybe users will want to disable it on private servers if settings.ACCOUNT_EMAIL_VERIFICATION != 'none' and verified_only: emails = EmailAddress.objects.filter(user=user, verified=True) else: emails = EmailAddress.objects.filter(user=user) unsub_url = site.build_full_url( f'/unsubscribe_email/?unsub_token={user.unsub_token}&list={mailing_list}' ) for email in emails: ctx['unsub_url'] = unsub_url message = get_template(template_path).render(ctx) msg = EmailMessage( subject, message, to=(email.email, ), from_email=settings.DEFAULT_FROM_EMAIL, attachments=attachments, headers={ 'List-Unsubscribe': f'<{unsub_url}>, <mailto:[email protected]?subject=Unsubscribe_{mailing_list}>' }, ) msg.content_subtype = 'html' if attachment: msg.attach_file(attachment) msg.send()
def send_failure_alert_sms(printer, pause_print): if not settings.TWILIO_ENABLED: LOGGER.warn("Twilio settings are missing. Ignored send requests") return if not printer.user.sms_eligible(): return twilio_client = Client(settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) from_number = settings.TWILIO_FROM_NUMBER to_number = printer.user.phone_country_code + printer.user.phone_number msg = 'The Spaghetti Detective - Your print {} may be failing on {}. {}Go check it at: {}'.format( printer.current_print_filename or '', printer.name, 'Printer is paused. ' if pause_print else '', site.build_full_url('/')) twilio_client.messages.create(body=msg, to=to_number, from_=from_number)
def send_failure_alert(self, context: FailureAlertContext) -> None: access_token = self.get_access_token_from_config(context.config) if not access_token: return link = site.build_full_url('/') title = self.get_failure_alert_title(context=context, link=link) text = self.get_failure_alert_text(context=context, link=link) if not title or not text: return self.call_pushbullet( access_token=access_token, title=title, body=text, link=link, file_url=context.img_url, )
def send_printer_notification(self, context: PrinterNotificationContext) -> None: access_token = self.get_access_token_from_config(context.config) if not access_token: return title = self.get_printer_notification_title(context=context) text = self.get_printer_notification_text(context=context) if not text or not title: return link = site.build_full_url('/') self.call_pushbullet( access_token=access_token, title=title, body=text, link=link, file_url=context.img_url, )
def send_discord_notification(printer, text, color, webhook_url, image_url=None): webhook = DiscordWebhook(url=webhook_url, username="******") embed = DiscordEmbed(title=printer.name, description=text, color=color) if image_url: embed.set_image(url=image_url) embed.set_author( name="Click Here to Examine.", url=site.build_full_url('/printers/'), icon_url= "https://github.com/TheSpaghettiDetective/TheSpaghettiDetective/raw/master/web/app/static/img/logo-square.png" ) embed.set_timestamp() embed.set_footer(text="The Spaghetti Detective") webhook.add_embed(embed) webhook.execute()
def call_webhook(self, title: str, text: str, color: int, webhook_url: str, image_url: Optional[str] = None): webhook = DiscordWebhook(url=webhook_url, username="******") embed = DiscordEmbed(title=title, description=text, color=color) if image_url: embed.set_image(url=image_url) embed.set_author( name="Printer Notification", url=site.build_full_url('/printers/'), icon_url= "https://github.com/TheSpaghettiDetective/TheSpaghettiDetective/raw/master/frontend/static/img/logo/compact/logo-compact_light-scheme.png" ) embed.set_timestamp() embed.set_footer(text="The Spaghetti Detective") webhook.add_embed(embed) webhook.execute()