def test_get_free_busy_info(self): tz = EWSTimeZone('Europe/Copenhagen') server_timezones = list(self.account.protocol.get_timezones(return_full_timezone_data=True)) start = EWSDateTime.now(tz=tz) end = EWSDateTime.now(tz=tz) + datetime.timedelta(hours=6) accounts = [(self.account, 'Organizer', False)] with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=[(123, 'XXX', 'XXX')], start=0, end=0) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=[(self.account, 'XXX', 'XXX')], start=0, end=0) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=[(self.account, 'Organizer', 'XXX')], start=0, end=0) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=accounts, start=end, end=start) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=accounts, start=start, end=end, merged_free_busy_interval='XXX') with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=accounts, start=start, end=end, requested_view='XXX') for view_info in self.account.protocol.get_free_busy_info(accounts=accounts, start=start, end=end): self.assertIsInstance(view_info, FreeBusyView) self.assertIsInstance(view_info.working_hours_timezone, TimeZone) ms_id = view_info.working_hours_timezone.to_server_timezone(server_timezones, start.year) self.assertIn(ms_id, {t[0] for t in CLDR_TO_MS_TIMEZONE_MAP.values()}) # Test account as simple email for view_info in self.account.protocol.get_free_busy_info( accounts=[(self.account.primary_smtp_address, 'Organizer', False)], start=start, end=end ): self.assertIsInstance(view_info, FreeBusyView)
def test_super_methods(self): tz = EWSTimeZone('Europe/Copenhagen') self.assertIsInstance(EWSDateTime.now(), EWSDateTime) self.assertIsInstance(EWSDateTime.now(tz=tz), EWSDateTime) self.assertIsInstance(EWSDateTime.utcnow(), EWSDateTime) self.assertIsInstance(EWSDateTime.fromtimestamp(123456789), EWSDateTime) self.assertIsInstance(EWSDateTime.fromtimestamp(123456789, tz=tz), EWSDateTime) self.assertIsInstance(EWSDateTime.utcfromtimestamp(123456789), EWSDateTime)
def make_a_reservation(preferences, timeslot): logger.info("Trying to make a reservation for {0} minutes.".format(timeslot)) now = tz.localize(EWSDateTime.now()) now = now.replace(minute=(now.minute - (now.minute % 5))) # round down to nearest 5 start_time = now.replace(second=0, microsecond=0) end_time = now.replace(second=0, microsecond=0) + timedelta(minutes=timeslot) logger.debug("Reserving for " + str(start_time) + " - " + str(end_time)) try: credentials = Credentials(username=preferences["username"], password=preferences["password"]) config = Configuration(service_endpoint=preferences["server"], credentials=credentials, auth_type=NTLM) account = Account(primary_smtp_address=preferences["email"], config=config, autodiscover=False, access_type=DELEGATE) item = CalendarItem(folder=account.calendar, subject='Pikavaraus', body='Made with Naurunappula at ' + str(now), start=start_time, end=end_time) except requests.exceptions.RequestException as e: # failure in data communication logger.exception("Exception while contacting the server.") return False if not check_availability(preferences, timeslot): return False try: item.save() return True except Exception as e: return False
def clear_reservations(preferences): logger.info("Cancelling appointments made by the device") appointments = get_appointments(preferences) if appointments is None: logger.error("Failed to cancel requested appointment. Perhaps there is an issue with network connectivity.") return now = tz.localize(EWSDateTime.utcnow()) if(len(appointments) > 0): for app in appointments: start_time = tz.localize(app.start.replace(tzinfo=None)) end_time = tz.localize(app.end.replace(tzinfo=None)) if "Pikavaraus" in app.subject and "Naurunappula" in app.body and now < end_time: logger.info("Cancelling an appointment named {0} at {1} - {2}".format(app.subject, start_time, end_time)) try: app.start = app.start.astimezone(tz) app.end = tz.localize(EWSDateTime.now()) app.save() return True except Exception as e: logger.exception("Couldn't cancel appointment.") return False else: logger.info("No appointments to cancel.") return False
def _get_formatted_end_date(self, number_of_days_from_now): now = self.account.default_timezone.localize(EWSDateTime.now()) end = now + datetime.timedelta(days=number_of_days_from_now) year = end.year month = end.month day = end.day return year, month, day
def get_appointments(): now = tz.localize(EWSDateTime.now()) items = {} try: items = account.calendar.view( start=tz.localize(EWSDateTime(now.year, now.month, now.day, 6, 0)), end=tz.localize(EWSDateTime(now.year, now.month, now.day, 18, 0)), ).order_by('start') except Exception as e: logger.error("Failed to get appointments. Trying again later. Error: {0}".format(e)) return items
def main(): exchAcc = ExchAccount('eas.outlook.com','******@outlook.com','********') exchAcc.login() localTimeZone = EWSTimeZone.localzone() nowDateTime = EWSDateTime.now(tz=localTimeZone) # print(EWSDateTime.now(tz=localTimeZone)) items = exchAcc.account.calendar.view(start=nowDateTime - timedelta(days=1),end=nowDateTime + timedelta(days=6)) for item in items: startTime = item.start.astimezone(tz=localTimeZone) endTime = item.end.astimezone(tz=localTimeZone) print(item.reminder_minutes_before_start)
def make_a_reservation(timeslot): logger.info("Trying to make a reservation for {0} minutes.".format(timeslot)) now = tz.localize(EWSDateTime.now()) start_time = tz.localize(EWSDateTime(now.year, now.month, now.day, now.hour, now.minute, 0, 0)) end_time = tz.localize(EWSDateTime(now.year, now.month, now.day, now.hour, now.minute, 0, 0) + timedelta(minutes=timeslot)) item = CalendarItem(folder=account.calendar, subject='Pikavaraus', body='Made with Naurunappula at '+ str(now), start=start_time, end=end_time) try: item.save() logger.info("Reservation successful.") return True except Exception as e: logger.info("Reservation failed: {0}".format(e)) return False
def Update(self): localTimeZone = EWSTimeZone.localzone() nowDateTime = EWSDateTime.now(tz=localTimeZone) # print(EWSDateTime.now(tz=localTimeZone)) items = self.account.calendar.view( start=nowDateTime - timedelta(days=1), end=nowDateTime + timedelta(days=6), ) retStr = [] unseenStr = [] unseenMails = self.account.inbox.filter(is_read=False) unseenStr.append(('{}'.format(unseenMails.count()))) retStr.append(unseenStr) for item in items: itemStr = [] startTime = item.start.astimezone(tz=localTimeZone) endTime = item.end.astimezone(tz=localTimeZone) dataOffset = startTime - nowDateTime dateOffNum = dataOffset.days+ dataOffset.seconds/(24.0*60.0*60.0) dateOffStr = ('%3.2f' % (dateOffNum))+'天后' if(dateOffNum>0) else ('%3.2f' % (abs(dateOffNum)))+'天前' if startTime.date()== nowDateTime.date(): dateOffStr=('今天') when = '{},{}-{}'.format(dateOffStr,startTime.strftime('%m/%d %H:%M'),endTime.strftime('%H:%M')) subject = (re.sub('(?s)([^<]*)(<.*>)(.*)', '\\1\\3', '{}'.format(item.subject))).replace('None','') detail = (re.sub('(?s)([^<]*)(<.*>)(.*)', '\\1\\3', ':{}'.format(item.body))).replace(':None','') reminderTime = startTime - timedelta(minutes=item.reminder_minutes_before_start) if(nowDateTime.strftime("%m/%d %H:%M") == reminderTime.strftime("%m/%d %H:%M")): remindNow = True else: remindNow = False reminder = ('{} min'.format(item.reminder_minutes_before_start if item.reminder_is_set else 'No remind')) location = ('@{}#{}'.format(item.location,reminder)).replace('None','') itemStr.append(when) itemStr.append('{}{}'.format(subject,detail)) itemStr.append(location) itemStr.append(remindNow) retStr.append(itemStr) return retStr
def delete_malicious_email(recipient_email, attachment_name): # once the recipients are found we parse their mailboxes and delete the malicious email # Args: # recipient_email (str) : malware recipient email address # attachment_name (str) : the attachment file name to identify the malicious email # Returns: # True is it parses the mailboxes, False if an error occurs # TODO: # ban the infected recipient machine with either IP or FortiClient using item.is_read account = Account(primary_smtp_address=recipient_email, config=config, autodiscover=False, access_type=IMPERSONATION) tz = EWSTimeZone.localzone() right_now = tz.localize(EWSDateTime.now()) xmin_ago = right_now - timedelta(minutes=300) try: for item in account.inbox.filter(datetime_received__gt=xmin_ago): for attachment in item.attachments: if isinstance(attachment, FileAttachment): if attachment.name == attachment_name: # Either delete the infected email, or move it to trash #item.delete() item.move_to_trash() #send an alert to the recipient m = Message( account=account, subject='FortiSIEM: You have received a Virus ' + attachment_name, body= 'The maliicous email has been deleted from your inbox, please contact your administrator for further incident response', to_recipients=[ Mailbox(email_address=recipient_email) ], ) m.send() return True except: return False
def find_malicious_email(sender_email, file_name): # identify the attributes of the email with was sent with the malicious attachment # Args: # sender_email (str) : the sender email address # file_name (str) : the attachment file name to identify the malicious email # Returns: # two lists, sibjects of the infected emails, recipients of the infected email # TODO: # Could be imroved by getting the email sent_time and use it as a filter in xmin_ago instead of the current 300 seconds recipient_emails = [] emails_subjects = [] account = Account(primary_smtp_address=sender_email, config=config, autodiscover=False, access_type=IMPERSONATION) tz = EWSTimeZone.localzone() right_now = tz.localize(EWSDateTime.now()) xmin_ago = right_now - timedelta(minutes=300) for item in account.sent.filter(datetime_sent__gt=xmin_ago): #for item in account.sent.all().order_by('-datetime_received')[:10]: for attachment in item.attachments: if isinstance(attachment, FileAttachment): if attachment.name == file_name: emails_subjects.append(item.subject) # logging.debug('Subject: '+item.subject+' '+attachment.name) if item.to_recipients is not None: for index, val in enumerate(item.to_recipients): if val.email_address not in recipient_emails: recipient_emails.append(val.email_address) if item.cc_recipients is not None: for index, val in enumerate(item.cc_recipients): if val.email_address not in recipient_emails: recipient_emails.append(val.email_address) if item.bcc_recipients is not None: for index, val in enumerate(item.bcc_recipients): if val.email_address not in recipient_emails: recipient_emails.append(val.email_address) logging.debug(emails_subjects) logging.debug(recipient_emails) return emails_subjects, recipient_emails
def wait_for_message( self, criterion: str = "", timeout: float = 5.0, interval: float = 1.0, contains: bool = False, save_dir: str = None, ) -> Any: """Wait for email matching `criterion` to arrive into INBOX. :param criterion: wait for message matching criterion :param timeout: total time in seconds to wait for email, defaults to 5.0 :param interval: time in seconds for new check, defaults to 1.0 :param contains: if matching should be done using `contains` matching and not `equals` matching, default `False` is means `equals` matching :param save_dir: set to path where attachments should be saved, default None (attachments are not saved) :return: list of messages """ self.logger.info("Wait for messages") end_time = time.time() + float(timeout) filter_dict = self._get_filter_key_value(criterion, contains) items = None tz = EWSTimeZone.localzone() right_now = tz.localize(EWSDateTime.now()) # pylint: disable=E1101 while time.time() < end_time: items = self.account.inbox.filter( # pylint: disable=E1101 **filter_dict, datetime_received__gte=right_now) if items.count() > 0: break time.sleep(interval) messages = [] for item in items: attachments = [] if save_dir and len(item.attachments) > 0: attachments = self._save_attachments(item, save_dir) messages.append(self._get_email_details(item, attachments)) if len(messages) == 0: self.logger.info("Did not receive any matching items") return messages
def get_appointments(self, acc): # define the timezone now = EWSDateTime.now(self.tz) items = {} try: logger.debug("Getting appointments") items = acc.calendar.view( start=self.tz.localize( EWSDateTime(now.year, now.month, now.day, 4, 0)), end=self.tz.localize( EWSDateTime(now.year, now.month, now.day, 22, 0)), ) logger.debug("Getting appointments was a success") return items, True except Exception as e: logger.error( "Failed to get appointments. Trying again later. Error: {0}". format(traceback.print_exc())) return items, False
def verify_availability(appointments, timeslot): available = True now = tz.localize(EWSDateTime.now()) nowplusdelta = now + timedelta(minutes=timeslot) for app in appointments: # the timeslot has to pass a few rules before it can be reserved if now >= app.start and now < app.end: logger.debug("Meeting room is marked as reserved by rule #1") available = False break if now >= app.start and nowplusdelta <= app.start: logger.debug("Meeting room is marked as reserved by rule #2") available = False break if now <= app.start and (nowplusdelta >= (app.start - timedelta(minutes=5)) and nowplusdelta <= app.end): logger.debug("Meeting room is marked as reserved by rule #3") available = False break return available
def wait_for_message( self, criterion: str = "", timeout: float = 5.0, interval: float = 1.0, contains: bool = False, ) -> Any: """Wait for email matching `criterion` to arrive into INBOX. :param criterion: wait for message matching criterion :param timeout: total time in seconds to wait for email, defaults to 5.0 :param interval: time in seconds for new check, defaults to 1.0 :param contains: if matching should be done using `contains` matching and not `equals` matching, default `False` is means `equals` matching :return: list of messages """ self.logger.info("Wait for messages") end_time = time.time() + float(timeout) filter_dict = self._get_filter_key_value(criterion, contains) items = None tz = EWSTimeZone.localzone() right_now = tz.localize(EWSDateTime.now()) # pylint: disable=E1101 while time.time() < end_time: items = self.account.inbox.filter( # pylint: disable=E1101 **filter_dict, datetime_received__gte=right_now) if items.count() > 0: break time.sleep(interval) messages = [] for item in items: messages.append({ "subject": item.subject, "sender": item.sender, "datetime_received": item.datetime_received, "body": item.body, }) if len(messages) == 0: self.logger.info("Did not receive any matching items") return messages
def test_oof_settings(self): # First, ensure a common starting point self.account.oof_settings = OofSettings(state=OofSettings.DISABLED) oof = OofSettings( state=OofSettings.ENABLED, external_audience='None', internal_reply="I'm on holidays. See ya guys!", external_reply='Dear Sir, your email has now been deleted.', ) self.account.oof_settings = oof self.assertEqual(self.account.oof_settings, oof) oof = OofSettings( state=OofSettings.ENABLED, external_audience='Known', internal_reply='XXX', external_reply='YYY', ) self.account.oof_settings = oof self.assertEqual(self.account.oof_settings, oof) # Scheduled duration must not be in the past tz = self.account.default_timezone start, end = get_random_datetime_range( start_date=EWSDateTime.now(tz).date()) oof = OofSettings( state=OofSettings.SCHEDULED, external_audience='Known', internal_reply="I'm in the pub. See ya guys!", external_reply="I'm having a business dinner in town", start=start, end=end, ) self.account.oof_settings = oof self.assertEqual(self.account.oof_settings, oof) oof = OofSettings(state=OofSettings.DISABLED, ) self.account.oof_settings = oof self.assertEqual(self.account.oof_settings, oof)
def get_calendar_events(self): start = self.account.default_timezone.localize(EWSDateTime.now()) end = start + datetime.timedelta(days=30) events = [] unfolded_items = self.account.calendar.view(start=start, end=end) tz = EWSTimeZone.localzone() for item in unfolded_items: if "Canceled:" in item.subject: continue events.append({ "start": str(item.start.astimezone(tz).isoformat()), "end": str(item.end.astimezone(tz).isoformat()), "required_attendees": str(item.required_attendees), "optional_attendees": str(item.optional_attendees), "location": str(item.location), "message": str(item.text_body), "subject": str(item.subject), }) logging.info('Added "{}" event'.format(item.subject)) return events
def miniprogram_event_patch(eventId): # 修改活动接口,包括报名的部分 db_session = None if "DEVMODE" in os.environ: if os.environ["DEVMODE"] == "True": db_session = orm.init_db(os.environ["DEV_DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) eventPatchBody_dict = connexion.request.get_json() learner = weapp.getLearner() if not learner: db_session.remove() return {'code': -1001, 'message': '没有找到对应的Learner'}, 200 event: orm.Event_db = db_session.query( orm.Event_db).filter(orm.Event_db.id == eventId).one_or_none() pushMessage = db_session.query(orm.PushMessage_db).filter( orm.PushMessage_db.id == event.pushMessageId).one_or_none() if event.initiatorId != learner.id: try: newRsvp = json.loads(pushMessage.rsvp) if pushMessage.rsvp else { 'accept': [], 'decline': [], 'tentative': [] } newEntry = { 'id': learner.id, 'fullname': learner.familyName + learner.givenName } # 登记参加的处理逻辑 if eventPatchBody_dict["rsvp"] == "参加": if newEntry not in newRsvp['accept']: newRsvp["accept"].append(newEntry) existingNotification: orm.Notification_db = db_session.query( orm.Notification_db).filter( orm.Notification_db.learnerId == learner.id ).filter(orm.Notification_db.notificationType == "活动日程").filter(orm.Notification_db.entityId == event.id).one_or_none() if existingNotification: existingNotification.status = "参加" else: newNotification: orm.Notification_db = orm.Notification_db( learnerId=learner.id, notificationType="活动日程", entityId=event.id, createdDateTime=util.EWSDateTimeToDateTime( account.default_timezone.localize( EWSDateTime.now())), expireDateTime=util.EWSDateTimeToDateTime( EWSDateTime.from_string( json.loads( event.eventInfo)["expireDateTime"])), status="参加", title=json.loads(event.eventInfo)["title"], description=json.loads( event.eventInfo)["description"], ) db_session.add(newNotification) for responseType in ["decline"]: if newEntry in newRsvp[responseType]: newRsvp[responseType].remove(newEntry) for responseType in ["tentative"]: if newEntry in newRsvp[responseType]: newRsvp[responseType].remove(newEntry) # 登记不参加的处理逻辑 if eventPatchBody_dict["rsvp"] == "不参加": if newEntry not in newRsvp['decline']: newRsvp["decline"].append(newEntry) for responseType in ["accept", "tentative"]: if newEntry in newRsvp[responseType]: newRsvp[responseType].remove(newEntry) notificationToDelete = db_session.query( orm.Notification_db).filter( orm.Notification_db.learnerId == learner.id).filter( orm.Notification_db.notificationType == "活动日程").filter(orm.Notification_db.entityId == event.id).one_or_none() if notificationToDelete: db_session.delete(notificationToDelete) # 登记待定的处理逻辑 if eventPatchBody_dict["rsvp"] == "待定": if newEntry not in newRsvp['tentative']: newRsvp["tentative"].append(newEntry) existingNotification: orm.Notification_db = db_session.query( orm.Notification_db).filter( orm.Notification_db.learnerId == learner.id ).filter(orm.Notification_db.notificationType == "活动日程").filter(orm.Notification_db.entityId == event.id).one_or_none() if existingNotification: existingNotification.status = "待定" else: newNotification: orm.Notification_db = orm.Notification_db( learnerId=learner.id, notificationType="活动日程", entityId=event.id, createdDateTime=util.EWSDateTimeToDateTime( account.default_timezone.localize( EWSDateTime.now())), expireDateTime=util.EWSDateTimeToDateTime( EWSDateTime.from_string( json.loads( event.eventInfo)["expireDateTime"])), status="参加", title=json.loads(event.eventInfo)["title"], description=json.loads( event.eventInfo)["description"], ) db_session.add(newNotification) for responseType in ["decline", "accept"]: if newEntry in newRsvp[responseType]: newRsvp[responseType].remove(newEntry) setattr(pushMessage, "rsvp", json.dumps(newRsvp)) db_session.commit() except Exception as e: db_session.remove() return {'code': -3002, 'message': '更新rsvp信息失败', 'log': str(e)}, 200 db_session.remove() return {'code': 0, 'message': '成功更新rsvp信息'}, 200 else: try: for itemKey in eventPatchBody_dict: if itemKey == "initiatorDisplayName": event.initiatorDisplayName = eventPatchBody_dict[itemKey] if itemKey == "invitee": event.invitee = json.dumps(eventPatchBody_dict[itemKey]) if itemKey == "thumbnail": event.thumbnail = json.dumps(eventPatchBody_dict[itemKey]) if itemKey == "content": pushMessage.content = json.dumps( eventPatchBody_dict[itemKey]) if itemKey in ["title", "description", "fee", "location"]: newEventInfo = json.loads(event.eventInfo) newEventInfo[itemKey] = eventPatchBody_dict[itemKey] event.eventInfo = json.dumps(newEventInfo) if itemKey in ["endDateTime", "startDateTime"]: newEventInfo = json.loads(event.eventInfo) newEventInfo[itemKey] = eventPatchBody_dict[itemKey] event.eventInfo = json.dumps(newEventInfo) newPatchDateTime = util.EWSDateTimeToDateTime( EWSDateTime.from_string(eventPatchBody_dict[itemKey])), setattr(pushMessage, itemKey, newPatchDateTime) if itemKey == "expireDateTime": newPatchExpireDateTime = util.EWSDateTimeToDateTime( EWSDateTime.from_string(eventPatchBody_dict[itemKey])), setattr(pushMessage, itemKey, newPatchExpireDateTime) setattr(event, "expireDateTime", newPatchExpireDateTime) newModifiedDateTime = util.EWSDateTimeToDateTime( account.default_timezone.localize(EWSDateTime.now())), pushMessage.modifiedDateTime = newModifiedDateTime db_session.commit() db_session.remove() return {'code': 0, 'message': '成功'}, 200 except Exception as e: db_session.remove() return {'code': -3003, 'message': '更新活动失败', 'log': str(e)}, 200
def test_ewsdatetime(self): # Test a static timezone tz = EWSTimeZone.timezone('Etc/GMT-5') dt = tz.localize(EWSDateTime(2000, 1, 2, 3, 4, 5)) self.assertIsInstance(dt, EWSDateTime) self.assertIsInstance(dt.tzinfo, EWSTimeZone) self.assertEqual(dt.tzinfo.ms_id, tz.ms_id) self.assertEqual(dt.tzinfo.ms_name, tz.ms_name) self.assertEqual(str(dt), '2000-01-02 03:04:05+05:00') self.assertEqual( repr(dt), "EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=<StaticTzInfo 'Etc/GMT-5'>)" ) # Test a DST timezone tz = EWSTimeZone.timezone('Europe/Copenhagen') dt = tz.localize(EWSDateTime(2000, 1, 2, 3, 4, 5)) self.assertIsInstance(dt, EWSDateTime) self.assertIsInstance(dt.tzinfo, EWSTimeZone) self.assertEqual(dt.tzinfo.ms_id, tz.ms_id) self.assertEqual(dt.tzinfo.ms_name, tz.ms_name) self.assertEqual(str(dt), '2000-01-02 03:04:05+01:00') self.assertEqual( repr(dt), "EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=<DstTzInfo 'Europe/Copenhagen' CET+1:00:00 STD>)" ) # Test from_string with self.assertRaises(NaiveDateTimeNotAllowed): EWSDateTime.from_string('2000-01-02T03:04:05') self.assertEqual(EWSDateTime.from_string('2000-01-02T03:04:05+01:00'), UTC.localize(EWSDateTime(2000, 1, 2, 2, 4, 5))) self.assertEqual(EWSDateTime.from_string('2000-01-02T03:04:05Z'), UTC.localize(EWSDateTime(2000, 1, 2, 3, 4, 5))) self.assertIsInstance( EWSDateTime.from_string('2000-01-02T03:04:05+01:00'), EWSDateTime) self.assertIsInstance(EWSDateTime.from_string('2000-01-02T03:04:05Z'), EWSDateTime) # Test addition, subtraction, summertime etc self.assertIsInstance(dt + datetime.timedelta(days=1), EWSDateTime) self.assertIsInstance(dt - datetime.timedelta(days=1), EWSDateTime) self.assertIsInstance(dt - EWSDateTime.now(tz=tz), datetime.timedelta) self.assertIsInstance(EWSDateTime.now(tz=tz), EWSDateTime) self.assertEqual( dt, EWSDateTime.from_datetime( tz.localize(datetime.datetime(2000, 1, 2, 3, 4, 5)))) self.assertEqual(dt.ewsformat(), '2000-01-02T03:04:05+01:00') utc_tz = EWSTimeZone.timezone('UTC') self.assertEqual( dt.astimezone(utc_tz).ewsformat(), '2000-01-02T02:04:05Z') # Test summertime dt = tz.localize(EWSDateTime(2000, 8, 2, 3, 4, 5)) self.assertEqual( dt.astimezone(utc_tz).ewsformat(), '2000-08-02T01:04:05Z') # Test normalize, for completeness self.assertEqual( tz.normalize(dt).ewsformat(), '2000-08-02T03:04:05+02:00') self.assertEqual( utc_tz.normalize(dt, is_dst=True).ewsformat(), '2000-08-02T01:04:05Z') # Test in-place add and subtract dt = tz.localize(EWSDateTime(2000, 1, 2, 3, 4, 5)) dt += datetime.timedelta(days=1) self.assertIsInstance(dt, EWSDateTime) self.assertEqual(dt, tz.localize(EWSDateTime(2000, 1, 3, 3, 4, 5))) dt = tz.localize(EWSDateTime(2000, 1, 2, 3, 4, 5)) dt -= datetime.timedelta(days=1) self.assertIsInstance(dt, EWSDateTime) self.assertEqual(dt, tz.localize(EWSDateTime(2000, 1, 1, 3, 4, 5))) # Test ewsformat() failure dt = EWSDateTime(2000, 1, 2, 3, 4, 5) with self.assertRaises(ValueError): dt.ewsformat() # Test wrong tzinfo type with self.assertRaises(ValueError): EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=pytz.utc) with self.assertRaises(ValueError): EWSDateTime.from_datetime(EWSDateTime(2000, 1, 2, 3, 4, 5))
def test_ewsdatetime(self): # Test a static timezone tz = EWSTimeZone('Etc/GMT-5') dt = EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=tz) self.assertIsInstance(dt, EWSDateTime) self.assertIsInstance(dt.tzinfo, EWSTimeZone) self.assertEqual(dt.tzinfo.ms_id, tz.ms_id) self.assertEqual(dt.tzinfo.ms_name, tz.ms_name) self.assertEqual(str(dt), '2000-01-02 03:04:05+05:00') self.assertEqual( repr(dt), "EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=EWSTimeZone(key='Etc/GMT-5'))" ) # Test a DST timezone tz = EWSTimeZone('Europe/Copenhagen') dt = EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=tz) self.assertIsInstance(dt, EWSDateTime) self.assertIsInstance(dt.tzinfo, EWSTimeZone) self.assertEqual(dt.tzinfo.ms_id, tz.ms_id) self.assertEqual(dt.tzinfo.ms_name, tz.ms_name) self.assertEqual(str(dt), '2000-01-02 03:04:05+01:00') self.assertEqual( repr(dt), "EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=EWSTimeZone(key='Europe/Copenhagen'))" ) # Test from_string with self.assertRaises(NaiveDateTimeNotAllowed): EWSDateTime.from_string('2000-01-02T03:04:05') self.assertEqual(EWSDateTime.from_string('2000-01-02T03:04:05+01:00'), EWSDateTime(2000, 1, 2, 2, 4, 5, tzinfo=UTC)) self.assertEqual(EWSDateTime.from_string('2000-01-02T03:04:05Z'), EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=UTC)) self.assertIsInstance( EWSDateTime.from_string('2000-01-02T03:04:05+01:00'), EWSDateTime) self.assertIsInstance(EWSDateTime.from_string('2000-01-02T03:04:05Z'), EWSDateTime) # Test addition, subtraction, summertime etc self.assertIsInstance(dt + datetime.timedelta(days=1), EWSDateTime) self.assertIsInstance(dt - datetime.timedelta(days=1), EWSDateTime) self.assertIsInstance(dt - EWSDateTime.now(tz=tz), datetime.timedelta) self.assertIsInstance(EWSDateTime.now(tz=tz), EWSDateTime) # Test various input for from_datetime() self.assertEqual( dt, EWSDateTime.from_datetime( datetime.datetime(2000, 1, 2, 3, 4, 5, tzinfo=EWSTimeZone('Europe/Copenhagen')))) self.assertEqual( dt, EWSDateTime.from_datetime( datetime.datetime( 2000, 1, 2, 3, 4, 5, tzinfo=zoneinfo.ZoneInfo('Europe/Copenhagen')))) self.assertEqual( dt, EWSDateTime.from_datetime( datetime.datetime( 2000, 1, 2, 3, 4, 5, tzinfo=dateutil.tz.gettz('Europe/Copenhagen')))) self.assertEqual( dt, EWSDateTime.from_datetime( datetime.datetime(2000, 1, 2, 3, 4, 5, tzinfo=pytz.timezone('Europe/Copenhagen')))) self.assertEqual(dt.ewsformat(), '2000-01-02T03:04:05+01:00') utc_tz = EWSTimeZone('UTC') self.assertEqual( dt.astimezone(utc_tz).ewsformat(), '2000-01-02T02:04:05Z') # Test summertime dt = EWSDateTime(2000, 8, 2, 3, 4, 5, tzinfo=tz) self.assertEqual( dt.astimezone(utc_tz).ewsformat(), '2000-08-02T01:04:05Z') # Test in-place add and subtract dt = EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=tz) dt += datetime.timedelta(days=1) self.assertIsInstance(dt, EWSDateTime) self.assertEqual(dt, EWSDateTime(2000, 1, 3, 3, 4, 5, tzinfo=tz)) dt = EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=tz) dt -= datetime.timedelta(days=1) self.assertIsInstance(dt, EWSDateTime) self.assertEqual(dt, EWSDateTime(2000, 1, 1, 3, 4, 5, tzinfo=tz)) # Test ewsformat() failure dt = EWSDateTime(2000, 1, 2, 3, 4, 5) with self.assertRaises(ValueError): dt.ewsformat() # Test wrong tzinfo type with self.assertRaises(ValueError): EWSDateTime(2000, 1, 2, 3, 4, 5, tzinfo=zoneinfo.ZoneInfo('UTC')) with self.assertRaises(ValueError): EWSDateTime.from_datetime(EWSDateTime(2000, 1, 2, 3, 4, 5))
def __collect_metrics(self) -> list: meeting_room_occupancy = GaugeMetricFamily( 'exchange_meeting_room_occupied', 'This metric exposes info about meeting room occupancy', labels=[ "meeting_room_list_name", "meeting_room_name", "meeting_room_email" ]) meeting_room_will_be_occupied = GaugeMetricFamily( 'exchange_meeting_room_will_be_occupied_timestamp', 'This metric exposes timestamp of closest start of the room occupancy.', labels=[ "meeting_room_list_name", "meeting_room_name", "meeting_room_email" ]) meeting_room_will_be_free = GaugeMetricFamily( 'exchange_meeting_room_will_be_free_timestamp', 'This metric exposes timestamp of the most recent time the room will be free.', labels=[ "meeting_room_list_name", "meeting_room_name", "meeting_room_email" ]) today_meetings_left = GaugeMetricFamily( 'exchange_meeting_room_meetings_left_today', 'This metric exposes number of the meetings till the end of this day.', labels=[ "meeting_room_list_name", "meeting_room_name", "meeting_room_email" ]) now = self.__account.default_timezone.localize(EWSDateTime.now()) end = self.__account.default_timezone.localize( EWSDateTime.from_datetime( datetime.combine(now.date() + timedelta(days=1), datetime.min.time()))) room_list_count = 0 room_count = 0 skipped_count = 0 start = datetime.now() try: for room_list in self.__account.protocol.get_roomlists(): self.__logger.debug("processing room list: {}".format( room_list.name)) if not self.__room_list_regex.search(room_list.name): self.__logger.debug( "processing room list {} skipped, not matching regular expression" .format(room_list.name)) continue room_list_count += 1 for room in self.__account.protocol.get_rooms( room_list.email_address): self.__logger.debug("processing room: {}".format( room.name)) if not self.__room_name_regex.search(room.name): self.__logger.debug( "processing room {} skipped, not matching regular expression" .format(room.name)) skipped_count += 1 continue room_count += 1 room_account = self.__get_account(room.email_address) calendar = room_account.calendar.view(start=now, end=end) self.__logger.debug( "checking calendar: start={} end={}".format(now, end)) is_occupied = False will_be_free = now will_be_occupied = self.__account.default_timezone.localize( datetime.max - timedelta(1)) events_count = 0 if calendar.exists(): for i, event in enumerate(calendar): events_count += 1 if event.start <= now <= event.end: is_occupied = True will_be_free = event.end continue if will_be_free == event.start: will_be_free = event.end if not is_occupied: will_be_occupied = calendar[0].start self.__logger.debug( "occupied: {} will_be_free={} will_be_occupied={} events: {}" .format(is_occupied, will_be_free, will_be_occupied, events_count)) meeting_room_occupancy.add_metric( labels=[room_list.name, room.name, room.email_address], value=int(is_occupied)) meeting_room_will_be_occupied.add_metric( labels=[room_list.name, room.name, room.email_address], value=will_be_occupied.timestamp()) meeting_room_will_be_free.add_metric( labels=[room_list.name, room.name, room.email_address], value=will_be_free.timestamp()) today_meetings_left.add_metric( labels=[room_list.name, room.name, room.email_address], value=events_count) self.__logger.info( "finished processing of {} room lists wit total {} rooms and {} rooms skipped, duration {}" .format(room_list_count, room_count, skipped_count, datetime.now() - start)) self.__last_update = datetime.now() except Exception as e: self.__logger.info( "failed to update meeting room data, error: {}".format(e)) errors_total.labels(e.__class__.__name__).inc() up.set(0) return [] up.set(1) return [ meeting_room_occupancy, meeting_room_will_be_occupied, meeting_room_will_be_free, today_meetings_left, ]
###Dates, datetimes and timezones from datetime import datetime, timedelta import pytz from exchangelib import EWSTimeZone, EWSDateTime, EWSDate # EWSTimeZone works just like pytz.timezone() tz = EWSTimeZone.timezone('Europe/Copenhagen') # You can also get the local timezone defined in your operating system tz = EWSTimeZone.localzone() # EWSDate and EWSDateTime work just like datetime.datetime and datetime.date. Always create # timezone-aware datetimes with EWSTimeZone.localize(): localized_dt = tz.localize(EWSDateTime(2017, 9, 5, 8, 30)) right_now = tz.localize(EWSDateTime.now()) # Datetime math works transparently two_hours_later = localized_dt + timedelta(hours=2) two_hours = two_hours_later - localized_dt two_hours_later += timedelta(hours=2) # Dates my_date = EWSDate(2017, 9, 5) today = EWSDate.today() also_today = right_now.date() also_today += timedelta(days=10) # UTC helpers. 'UTC' is the UTC timezone as an EWSTimeZone instance. # 'UTC_NOW' returns a timezone-aware UTC timestamp of current time. from exchangelib import UTC, UTC_NOW
from exchangelib import Credentials, Account, EWSDateTime import settings import email_parser from datetime import datetime, date, timedelta account = settings.get_exchange_account() start = account.default_timezone.localize(EWSDateTime.now() - timedelta( days=settings.get_daysBack())) end = account.default_timezone.localize(EWSDateTime.now()) emits_email_list = account.inbox.filter( sender=settings.jsonConfig["emits_sender"], subject__icontains="Invitation To Tender", datetime_received__range=(start, end), ) collection = settings.get_mongo_collection() for n, item in enumerate(emits_email_list.order_by("-datetime_received")): print(f"Processing record {n} from {len(emits_email_list)}") parsed_values = email_parser.parse_fields(item.text_body) parsed_values["exchange-mail-id"] = item.id query = {"exchange-mail-id": item.id} not_inserted = collection.count_documents(query) == 0 if not_inserted: collection.insert_one(parsed_values)
HTMLBody, Build, Version #SSL certification from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter #no warnings display warnings import requests from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) import re import threading from time import sleep from log_reserve import printl EXCHANGE_SERVER_ADD = 'CASArray.ad4.ad.alcatel.com' tz = EWSTimeZone.timezone('UTC') UTC_NOW = tz.localize(EWSDateTime.now()) # - timedelta(hours=8) user_name = 'ad4\\tarzonz' pwd = '' mail_addr = '*****@*****.**' class MY_OUTLOOK(): def __init__(self, acc, pwd, ser, mail): global UTC_NOW credentials = Credentials(username=acc, password=pwd) config = Configuration(server=ser, credentials=credentials) self.my_account = Account(primary_smtp_address = mail, config=config,\ autodiscover = False, access_type = DELEGATE)
def miniprogram_announcement_announcementId_patch(announcementId, announcementPatchBody): # 修改通知接口 db_session = None if "DEVMODE" in os.environ: if os.environ["DEVMODE"] == "True": db_session = orm.init_db(os.environ["DEV_DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) announcementPatchBody_dict = connexion.request.get_json() learner = weapp.getLearner() if not learner: db_session.remove() return {'code': -1001, 'message': '没有找到对应的Learner'}, 200 announcement = db_session.query(orm.Announcement_db).filter(orm.Announcement_db.id == announcementId).one_or_none() pushMessage = db_session.query(orm.PushMessage_db).filter(orm.PushMessage_db.id == announcement.pushMessageId).one_or_none() try: for itemKey in announcementPatchBody_dict: if itemKey == "initiatorDisplayName": announcement.initiatorDisplayName = announcementPatchBody_dict[itemKey] if itemKey == "recipients": announcement.recipients = json.dumps(announcementPatchBody_dict[itemKey]) if itemKey == "thumbnail": announcement.thumbnail = json.dumps(announcementPatchBody_dict[itemKey]) if itemKey == "content": pushMessage.content = json.dumps(announcementPatchBody_dict[itemKey]) if itemKey == "body": announcement.body = json.dumps(announcementPatchBody_dict[itemKey]) if itemKey == "attachment": announcement.attachment = json.dumps(announcementPatchBody_dict[itemKey]) if itemKey == "title": announcement.title = announcementPatchBody_dict[itemKey] if itemKey == "description": announcement.description = announcementPatchBody_dict[itemKey] if itemKey == "expireDateTime": newExpireDateTime = util.EWSDateTimeToDateTime(EWSDateTime.from_string(announcementPatchBody_dict[itemKey])), setattr(pushMessage, itemKey, newExpireDateTime) newModifiedDateTime = util.EWSDateTimeToDateTime(account.default_timezone.localize(EWSDateTime.now())), pushMessage.modifiedDateTime = newModifiedDateTime db_session.commit() db_session.remove() return {'code': 0, 'message': '成功'}, 200 except Exception as e: db_session.remove() return {'code': -5002, 'message': '更新通知失败', 'log': str(e)}, 200
from exchangelib import EWSDateTime, EWSTimeZone from datetime import timedelta from ews2org import readConfigFile, setupAccount # Read the config file: server, username, emailAddress, password, timezone, daysPast, daysFuture, \ maxItems, outFileName, calName, orgLabels, \ orgStatusFuture, orgStatusCurrent, orgStatusPast, orgStatusCancel, \ orgPrioDefault, orgPrioHigh, orgPrioLow = readConfigFile() # Setup an account: account = setupAccount(username, password, server, emailAddress) # Start and end date to fetch calendar items for: now = account.default_timezone.localize(EWSDateTime.now()) startDate = now - timedelta(days=daysPast) endDate = now + timedelta(days=daysFuture) # startDate = account.default_timezone.localize(EWSDateTime(2019, 11, 7)) # endDate = account.default_timezone.localize(EWSDateTime(2019, 11, 8)) # Desired timezone: if timezone == '': tz = EWSTimeZone.localzone() else: tz = EWSTimeZone.timezone(timezone) # # Line-ending replacement strings: # # https://stackoverflow.com/a/43678795/1386750 # WINDOWS_LINE_ENDING = b'\r\n' # UNIX_LINE_ENDING = b'\n'
def miniprogram_event_post(eventPostBody): # 创建活动接口 db_session = None if "DEVMODE" in os.environ: if os.environ["DEVMODE"] == "True": db_session = orm.init_db(os.environ["DEV_DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) eventPostBody_dict = connexion.request.get_json() learner = weapp.getLearner() if not learner: db_session.remove() return {'code': -1001, 'message': '没有找到对应的Learner'}, 200 # 自定义鉴权 if not learner.isAdmin: if "initiatorDisplayName" in eventPostBody: db_session.remove() return { 'code': -1007, 'message': '需要管理员权限', "detail": "非管理员不可自定义发起者名称" }, 200 initiatorDisplayName = learner.familyName + learner.givenName else: initiatorDisplayName = eventPostBody_dict[ "initiatorDisplayName"] if "initiatorDisplayName" in eventPostBody_dict else learner.familyName + learner.givenName try: newEvent = orm.Event_db( initiatorId=learner.id, initiatorDisplayName=initiatorDisplayName, eventInfo=json.dumps(eventPostBody_dict["eventInfo"]), invitee=json.dumps(eventPostBody_dict["invitee"]), thumbnail=json.dumps(eventPostBody_dict["thumbnail"]), expireDateTime=util.EWSDateTimeToDateTime( EWSDateTime.from_string( eventPostBody_dict["eventInfo"]["expireDateTime"]))) db_session.add(newEvent) db_session.commit() newPushMessage = orm.PushMessage_db( messageType="Event", entityId=newEvent.id, senderId=learner.id, senderDisplayName=initiatorDisplayName, recipients=json.dumps(eventPostBody_dict["invitee"]), rsvp=json.dumps({ "accept": [], "decline": [], "tentative": [] }), sentDateTime=util.EWSDateTimeToDateTime( account.default_timezone.localize(EWSDateTime.now())), modifiedDateTime=util.EWSDateTimeToDateTime( account.default_timezone.localize(EWSDateTime.now())), expireDateTime=util.EWSDateTimeToDateTime( EWSDateTime.from_string( eventPostBody_dict["eventInfo"]["expireDateTime"])), content=json.dumps(eventPostBody_dict["content"])) db_session.add(newPushMessage) db_session.commit() newEvent.pushMessageId = newPushMessage.id db_session.commit() newNotification = orm.Notification_db( learnerId=learner.id, notificationType="活动日程", entityId=newEvent.id, createdDateTime=util.EWSDateTimeToDateTime( account.default_timezone.localize(EWSDateTime.now())), expireDateTime=util.EWSDateTimeToDateTime( EWSDateTime.from_string( json.loads(newEvent.eventInfo)["expireDateTime"])), title=json.loads(newEvent.eventInfo)["title"], description=json.loads(newEvent.eventInfo)["description"]) db_session.add(newNotification) db_session.commit() # TODO: 这里应当添加Microsoft Graph API为initiator添加appointment并发送至recipients except Exception as e: db_session.remove() return {'code': -3001, 'message': '活动创建失败', 'log': str(e)}, 200 response = {"pushMessageId": newPushMessage.id, "id": newEvent.id} db_session.remove() return {'code': 0, 'data': response, 'message': '成功'}, 200
def miniprogram_announcement_post(announcementPostBody): db_session = None if "DEVMODE" in os.environ: if os.environ["DEVMODE"] == "True": db_session = orm.init_db(os.environ["DEV_DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) else: db_session = orm.init_db(os.environ["DATABASEURI"]) announcementPostBody_dict = connexion.request.get_json() learner = weapp.getLearner() if not learner: db_session.remove() return {'code': -1001, 'message': '没有找到对应的Learner'}, 200 # 自定义鉴权 if not learner.isAdmin: db_session.remove() return {'code': -1007, 'message': '需要管理员权限', "detail": "只有管理员有权限发送通知"}, 200 try: newAnnouncement = orm.Announcement_db( initiatorId=learner.id, initiatorDisplayName=announcementPostBody_dict['initiatorDisplayName'], recipients=json.dumps(announcementPostBody_dict['recipients']), sentDateTime=util.EWSDateTimeToDateTime(account.default_timezone.localize(EWSDateTime.now())), modifiedDateTime=util.EWSDateTimeToDateTime(account.default_timezone.localize(EWSDateTime.now())), expireDateTime=util.EWSDateTimeToDateTime(EWSDateTime.from_string(announcementPostBody_dict["expireDateTime"])), thumbnail=json.dumps(announcementPostBody_dict['thumbnail']), title=announcementPostBody_dict['title'], description=announcementPostBody_dict['description'], body=json.dumps(announcementPostBody_dict['body']), attachment=json.dumps(announcementPostBody_dict['attachment']), ) db_session.add(newAnnouncement) db_session.commit() newPushMessage = orm.PushMessage_db( messageType="Announcement", entityId=newAnnouncement.id, senderId=learner.id, senderDisplayName=announcementPostBody_dict['initiatorDisplayName'], recipients=json.dumps(announcementPostBody_dict['recipients']), sentDateTime=util.EWSDateTimeToDateTime(account.default_timezone.localize(EWSDateTime.now())), modifiedDateTime=util.EWSDateTimeToDateTime(account.default_timezone.localize(EWSDateTime.now())), expireDateTime=util.EWSDateTimeToDateTime(EWSDateTime.from_string(announcementPostBody_dict["expireDateTime"])), content=json.dumps(announcementPostBody_dict["content"]) ) db_session.add(newPushMessage) db_session.commit() newAnnouncement.pushMessageId = newPushMessage.id db_session.commit() except Exception as e: db_session.remove() return {'code': -5001, 'message': '创建通知失败', 'log': str(e)}, 200 response = {'pushMessage_id': newPushMessage.id, 'announcment_id': newAnnouncement.id} return {'code': 0, 'data': response, 'message': '成功'}, 200
#Server = jsonData['Server'] Server = "outlook.office365.com" config = Configuration(server=Server, credentials=credentials) account = Account(primary_smtp_address=smtpAddress, config=config, credentials=credentials, autodiscover=False, access_type=DELEGATE) account.root.refresh(); inboxItems = account.inbox.all(); print(inboxItems) unreadcount = account.inbox.unread_count print(unreadcount) """ Sets the timerange within which the mails are extracted """ tz=EWSTimeZone.localzone() two_hours =tz.localize(EWSDateTime.now()) - timedelta(hours=3) recent_mails=account.inbox.filter(datetime_received__range=(two_hours,tz.localize(EWSDateTime.now()))).order_by('-datetime_received') print (recent_mails.count()) for msg in recent_mails: #StartDate = dt.datetime.now().strftime("%m/%d/%Y %H:%M:%S") msgSubject = str(msg.subject) msgBody = str(msg.body) sub = "Task Distribution" if re.search(sub, msgSubject, re.IGNORECASE): for attachment in msg.attachments: if isinstance(attachment, FileAttachment): local_path = os.path.join(os.getcwd(), attachment.name) with open(local_path, 'wb') as f: f.write(attachment.content) print('Saved attachment to', local_path)