190 lines
7.3 KiB
Python
Raw Normal View History

import smtplib
from communicator import db, app, executor
2020-09-17 11:16:41 -04:00
from communicator.models import Sample
2020-09-25 11:56:08 -04:00
from communicator.models.invitation import Invitation
from communicator.models.notification import Notification, EMAIL_TYPE, TEXT_TYPE
from communicator.models.sample import SampleSchema
2020-09-17 11:16:41 -04:00
from communicator.services.ivy_service import IvyService
from communicator.services.notification_service import NotificationService
from communicator.services.sample_service import SampleService
from time import sleep
2020-09-17 11:16:41 -04:00
def verify_token(token, required_scopes):
if token == app.config['API_TOKEN']:
return {'scope':['any']}
else:
raise Exception("permission_denied", "API Token information is not correct")
def status():
return {"status": "good"}
2020-09-17 11:16:41 -04:00
def add_sample(body):
sample = Sample(barcode=body['barcode'],
student_id=body['student_id'],
computing_id=body['computing_id'],
date=body['date'])
# Split the 4 digit location code into station and location
loc_code = body['location']
sample.location, sample.station = int(loc_code[:2]), int(loc_code[2:])
SampleService().add_or_update_records([sample])
2020-09-17 11:16:41 -04:00
def get_samples(bar_code=None):
query = db.session.query(Sample)
if bar_code:
last_sample = db.session.query(Sample).filter(Sample.barcode == bar_code).first()
if not last_sample:
app.logger.error(f'Someone queried for a barcode that does not exist: {bar_code} ', exc_info=True)
raise Exception("No such bar code.")
query = query.filter(Sample.date > last_sample.date)
samples = query.order_by(Sample.date).limit(200).all()
response = SampleSchema(many=True).dump(samples)
return response
def clear_samples():
db.session.query(Notification).delete()
db.session.query(Sample).delete()
2020-09-25 11:56:08 -04:00
db.session.query(Invitation).delete()
db.session.commit()
def update_and_notify():
# These can take a very long time to execute.
executor.submit(_update_data)
executor.submit(_notify_by_email)
executor.submit(_notify_by_text)
return "Task scheduled and running the background"
2020-09-17 11:16:41 -04:00
def update_data():
executor.submit(_update_data)
return "Task scheduled and running the background"
def _update_data():
"""Updates the database based on local files placed by IVY. No longer attempts
to pull files from the Firebase service."""
app.logger.info("Executing Update Data Task")
2020-09-17 11:16:41 -04:00
ivy_service = IvyService()
ivy_service.request_transfer()
files, samples = ivy_service.load_directory()
2020-09-17 11:16:41 -04:00
SampleService().add_or_update_records(samples)
for file in files:
db.session.add(file)
db.session.commit()
if app.config['DELETE_IVY_FILES']:
ivy_service.delete_file(file.file_name)
else:
app.logger.info("Not Deleting Files, per DELETE_IVY_FILES flag")
db.session.commit()
2020-09-17 11:16:41 -04:00
2020-12-30 09:06:46 -05:00
def split_location_column():
sample_service = SampleService()
sample_service.split_all_location_columns()
def correct_computing_id():
sample_service = SampleService()
sample_service.correct_computing_id()
2020-12-30 09:06:46 -05:00
def merge_similar_records():
sample_service = SampleService()
sample_service.merge_similar_records()
def notify_by_email(file_name=None, retry=False):
executor.submit(_notify_by_email, file_name, retry)
return "Task scheduled and running the background"
def _notify_by_email(file_name=None, retry=False):
2020-09-17 11:16:41 -04:00
"""Sends out notifications via email"""
sample_query = db.session.query(Sample) \
.filter(Sample.result_code != None) \
.filter(Sample.email_notified == False)
if file_name:
sample_query = sample_query.filter(Sample.ivy_file == file_name)
samples = sample_query.all()
count = 0
with NotificationService(app) as notifier:
for sample in samples:
last_failure = sample.last_failure_by_type(EMAIL_TYPE)
if last_failure and not retry:
continue
try:
notifier.send_result_email(sample)
count += 1
sample.email_notified = True
db.session.add(Notification(type=EMAIL_TYPE, sample=sample, successful=True))
except smtplib.SMTPServerDisconnected as de:
app.logger.error("Database connection terminated, stopping for now.", exc_info=True)
break
except smtplib.SMTPResponseException as re:
if re.smtp_code == 451:
app.logger.error("Too many messages error from SMTP Service, stopping for now.", exc_info=True)
break
else:
app.logger.error(f'An exception happened in EmailService sending to {sample.email} ', exc_info=True)
app.logger.error(str(e))
db.session.add(Notification(type=EMAIL_TYPE, sample=sample, successful=False,
error_message=str(e)))
except Exception as e:
app.logger.error(f'An exception happened in EmailService sending to {sample.email} ', exc_info=True)
app.logger.error(str(e))
db.session.add(Notification(type=EMAIL_TYPE, sample=sample, successful=False,
error_message=str(e)))
db.session.commit()
sleep(0.5)
if count > 190: # At 2 a second, it should take 80 seconds or around a minute and 1/2 to send out a set.
app.logger.info("Reached the max 190 messages, stopping for now.")
break
def notify_by_text(file_name=None, retry=False):
executor.submit(_notify_by_text, file_name, retry)
return "Task scheduled and running the background"
def _notify_by_text(file_name=None, retry=False):
"""Sends out notifications via SMS Message, but only at reasonable times of day,
Can be resticted to a specific file name, and will attempt to retry on previous
failures if requested to do so. """
with NotificationService(app) as notifier:
if not notifier.is_reasonable_hour_for_text_messages:
print("Skipping text messages, it's not a good time to get one.")
return
sample_query = db.session.query(Sample) \
.filter(Sample.result_code != None) \
.filter(Sample.text_notified == False)
if file_name:
sample_query = sample_query.filter(Sample.ivy_file == file_name)
2020-10-26 17:06:31 -04:00
# Do not limit texts, as errors pile up we end up sending less and less, till none go out.
# sample_query = sample_query.limit(150) # Only send out 150 texts at a time.
samples = sample_query.all()
count = 0
for sample in samples:
last_failure = sample.last_failure_by_type(TEXT_TYPE)
if last_failure and not retry:
continue
try:
notifier.send_result_sms(sample)
count += 1
sample.text_notified = True
db.session.add(Notification(type=TEXT_TYPE, sample=sample, successful=True))
except Exception as e:
db.session.add(Notification(type=TEXT_TYPE, sample=sample, successful=False,
error_message=str(e)))
db.session.commit()
sleep(0.5)
if count > 190:
break