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 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 verify_availability(appointments, timeslot): now = tz.localize(EWSDateTime.utcnow()) nowplusdelta = now + timedelta(minutes=timeslot) for app in appointments: # the timeslot has to pass a few rules before it can be reserved start_time = tz.localize(app.start.replace(tzinfo=None)) end_time = tz.localize(app.end.replace(tzinfo=None)) if now >= start_time and now < end_time: logger.info("Meeting room is marked as reserved by rule #1") return app, False if now >= start_time and nowplusdelta <= start_time: logger.info("Meeting room is marked as reserved by rule #2") return app, False if now <= start_time and (nowplusdelta >= (start_time - timedelta(minutes=1)) and nowplusdelta <= end_time): logger.info("Meeting room is marked as reserved by rule #3") return app, False logger.info("Meeting room is free at the moment.") return None, True
def get_appointments(preferences): now = tz.localize(EWSDateTime.utcnow()) items = {} 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) logger.info("Getting reservations for {0}".format(account.primary_smtp_address)) items = account.calendar.view( start=tz.localize(EWSDateTime(now.year, now.month, now.day, 0, 0)), end=tz.localize(EWSDateTime(now.year, now.month, now.day, 23, 59)), ).order_by('start') except requests.exceptions.RequestException as e: # failure in data communication logger.exception("Failure while contacting the server.") return None except Exception as e: logger.exception("Failed to get appointments. Try again later.") return None return items
def poll_availability(preferences): available = True now = tz.localize(EWSDateTime.utcnow()) logger.info("Getting appointments for today and checking availability.") try: appointments = get_appointments(preferences) if appointments is None: return "{\"subject\": \"Error\", \"start\": \"\", \"end\": \"\", \"duration\": \"0\", \"available\": \"False\"}" blocking_appointment, available = verify_availability(appointments, 5) except Exception as e: logger.exception("Failed to parse appointments.") return "{\"subject\": \"Error\", \"start\": \"\", \"end\": \"\", \"duration\": \"0\", \"available\": \"False\"}" event_subject = "" event_start_time = "" event_end_time = "" event_found = False duration = 0 if not available: logger.info("Meeting room reserved at the moment!") event_subject = blocking_appointment.subject duration = (tz.localize(blocking_appointment.end.replace(tzinfo=None)) - now).total_seconds() / 60 if event_subject is None or event_subject is "": event_subject = "Nimetön varaus" event_subject = event_subject.replace("\"", "'") event_start_time = blocking_appointment.start.astimezone(tz) #adjust timezone to local timezone event_end_time = blocking_appointment.end.astimezone(tz) #adjust timezone to local timezone return "{\"subject\": \"" + event_subject + "\", \"start\": \"" + event_start_time.strftime('%H:%M') + "\", \"end\": \"" + event_end_time.strftime('%H:%M') + "\", \"duration\": " + str(duration) + ", \"available\": \"False\"}" else: # find if there are upcoming events try: for app in appointments: event_subject = app.subject if event_subject is None or event_subject is "": event_subject = "Nimetön varaus" event_subject = event_subject.replace("\"", "'") event_start_time = app.start.astimezone(tz) #adjust timezone to local timezone for rendering event_end_time = app.end.astimezone(tz) #adjust timezone to local timezone for rendering if(now < tz.localize(app.start.replace(tzinfo=None)) and event_found == False): event_found = True duration = (tz.localize(app.start.replace(tzinfo=None)) - now).total_seconds() / 60 break except requests.exceptions.RequestException as e: # failure in data communication logger.exception("Failed to parse data.") return "{\"subject\": \"Error\", \"start\": \"\", \"end\": \"\", \"duration\": \"0\", \"available\": \"False\"}" if event_found: return "{\"subject\": \"" + event_subject + "\", \"start\": \"" + event_start_time.strftime('%H:%M') + "\", \"end\": \"" + event_end_time.strftime('%H:%M') + "\", \"duration\": " + str(duration) + ", \"available\": \"True\"}" else: return "{\"subject\": \"\", \"start\": \"\", \"end\": \"\", \"duration\": \"0\", \"available\": \"True\"}"
def work(self): logger.debug("Starting work thread") calendar_data = {} #dictionary containing the data progress_step = 100 / len(self.calendars) progress_now = 0 try: for key, value in self.calendars.items(): calendar_name = key calendar_email = value logger.debug( "Fetching data for calendar: {0}".format(calendar_name)) logger.debug("Setting up EWS account for calendar: {0}".format( calendar_email)) try: account = Account(primary_smtp_address=str(calendar_email), config=self.config, autodiscover=False, access_type=DELEGATE) except Exception as e: logger.error("Failure: {0}".format(traceback.print_exc())) continue calendar_data[calendar_name], result = self.get_appointments( account) if result is not True: logger.error( "Failed to fetch calendar data for calendar: {0}". format(calendar_email)) progress_now += progress_step self.progress.emit(progress_now) logger.debug("Done with calendar: {0}".format(calendar_email)) except Exception as e: logger.debug( "General failure occured when fetching calendar data! Error: {0}" .format(traceback.print_exc())) self.statusupdate.emit(-1, "Failure while fetching calendar data!") self.progress.emit(100) return logger.debug("Calendar data retrieved. Outputting webpage...") if not os.path.exists(self.workdirectory + "/web/"): os.makedirs(self.workdirectory + "/web/") try: content = "" content += "<table>\n" content += "<colgroup\n" content += "<col class=\"column10\"/>\n" content += "<col class=\"column30\"/>\n" content += "<col class=\"column15\"/>\n" content += "<col class=\"column30\"/>\n" content += "<col class=\"column15\"/>\n" content += "</colgroup>\n" content += "<tr>" content += "<th>Huone</th>" content += "<th>Tällä hetkellä / Seuraavaksi</th>" content += "<th></th>" content += "<th>Myöhemmin tänä päivänä</th>" content += "<th></th>" content += "</tr>" now = self.tz.localize(EWSDateTime.utcnow()) for calendar in calendar_data: primary_event_found = False secondary_event_found = False content += "<tr>\n" content += "<td class=\"meetingroom\">" + calendar + "</td>\n" try: for item in calendar_data[calendar]: subject = item.subject item.start = item.start.astimezone( self.tz) #adjust timezone to local timezone item.end = item.end.astimezone( self.tz) #adjust timezone to local timezone if subject is None or subject is "": subject = "Varaus ilman otsikkoa" if (now < item.end and primary_event_found == False): primary_event_found = True content += "<td class=\"event_primary\">" + str( subject) + "</td>\n" content += "<td class=\"eventdate_primary\">%s - %s</td>\n" % ( item.start.strftime("%H:%M"), item.end.strftime("%H:%M")) elif (now < item.end and secondary_event_found == False): secondary_event_found = True content += "<td class=\"event_secondary\">" + str( subject) + "</td>\n" content += "<td class=\"eventdate_secondary\">%s - %s</td>\n" % ( item.start.strftime("%H:%M"), item.end.strftime("%H:%M")) break except Exception as e: # failure in data communication logger.error("Failed to parse calendar data: {0}".format( traceback.print_exc())) content += "<td class=\"event_primary\">Virhe tiedonsiirrossa</td>\n" content += "<td class=\"eventdate_primary\"></td>\n" content += "<td class=\"event_secondary\">Virhe tiedonsiirrossa</td>\n" content += "<td class=\"eventdate_secondary\"></td>\n" primary_event_found = True secondary_event_found = True continue if (primary_event_found != True): logger.debug("Ei varauksia kalenterille " + calendar) content += "<td class=\"event_primary\">Vapaa</td>\n" content += "<td class=\"eventdate_primary\"></td>\n" if (secondary_event_found != True): logger.debug("Ei toissijaisia kalenterille " + calendar) content += "<td class=\"event_secondary\">Vapaa</td>\n" content += "<td class=\"eventdate_secondary\"></td>\n" content += "</tr>\n" content += "</table>" logger.debug("Updating webpage content!") with codecs.open(self.workdirectory + "/web/content.html", "w+", "utf-8") as f: f.write(content) # write the file first if os.path.isfile( self.workdirectory + "/web/index.html" ) is False: # if index.html already exists. Don't rewrite it constantly with codecs.open(self.workdirectory + "/web/index.html", "w+", "utf-8") as f: f.write( WebpageTemplate.template.replace( "%REPLACE_THIS_WITH_CONTENT%", "")) if os.path.isfile( self.workdirectory + "/web/stylesheet.css" ) is False: # if the stylesheet already exists. Don't rewrite it constantly with codecs.open(self.workdirectory + "/web/stylesheet.css", "w+", "utf-8") as f: f.write(WebpageTemplate.css_template) except FileNotFoundError: logger.error("Failed to open files for page generation.") self.statusupdate.emit( -1, "Failed to open files for page generation.") self.progress.emit(100) return self.statusupdate.emit(1, "Calendar data succesfully fetched!")