def getUpcomingBroadcasts(self, station, all, update, timeLimit, maxTimeRange, limiter = None, notModifiedCheck = None, head = False): now = TimeUtils.now() where = And(Or(Broadcast.BroadcastEnd > now, Broadcast.BroadcastEnd == None), (Broadcast.BroadcastStart < (now + timeLimit))) if not all: where = And(where, Broadcast.Type == u"data") if station is not None: where = And(where, Broadcast.StationID == stationId) broadcasts = self.store.find(Broadcast, where) lastModified = max( broadcasts.max(Broadcast.Modified), station.BroadcastRemoved if station is not None else None, station.Schedule.Modified if (station is not None and station.Schedule is not None) else None ) if head: return (lastModified, None, None, None) if notModifiedCheck is not None: notModifiedCheck(lastModified) if update: untilDate = datetime.fromtimestamp(now) untilDate += timedelta(seconds=timeLimit) untilDate = self.normalizeDate(untilDate) until = TimeUtils.toTimestamp(untilDate) if station is None: validUntil = self.scheduleMaintainer.updateSchedules(until, maxTimeRange) else: validUntil = self.scheduleMaintainer.updateSchedule(station, until, maxTimeRange) # trans.set_header_value("Expires", self.model.formatHTTPTimestamp(validUntil)) return (lastModified, broadcasts if limiter is None else limiter(broadcasts), validUntil >= until, validUntil)
def getTransmissionsByMonth(self, stationId, year, month, limiter = None, notModifiedCheck = None, head = False): if month is not None: startTimestamp = datetime(year, month, 1) if month != 12: endTimestamp = datetime(year, month+1, 1) else: endTimestamp = datetime(year+1, 1, 1) else: startTimestamp = datetime(year, 1, 1) endTimestamp = datetime(year+1, 1, 1) startTimestamp = TimeUtils.toTimestamp(startTimestamp) endTimestamp = TimeUtils.toTimestamp(endTimestamp) transmissions = self.store.find((Transmission, Broadcast), Transmission.BroadcastID == Broadcast.ID, And(Broadcast.StationID == stationId, And(Transmission.Timestamp >= startTimestamp, Transmission.Timestamp < endTimestamp))) lastModified = max( transmissions.max(Transmission.Modified), self.store.find(Broadcast, Broadcast.StationID == stationId).max(Broadcast.TransmissionRemoved), self.store.get(Station, stationId).BroadcastRemoved ) if head: return (lastModified, None) if notModifiedCheck is not None: notModifiedCheck(lastModified) transmissions.order_by(Desc(Transmission.Timestamp)) if limiter is not None: transmissions = limiter(transmissions) return (lastModified, (transmission for (transmission, broadcast) in transmissions))
def getData(self, station = None, years=None, **kwargs): where = Broadcast.BroadcastEnd != None if station is not None: where = And(where, Broadcast.StationID == station.ID) if years is not None: now = TimeUtils.nowDate() where = And(where, Broadcast.BroadcastStart >= TimeUtils.toTimestamp(datetime(year=now.year-years, month=now.month, day=1))) data = self.store.find( ( Station, Func("YEAR", Func("FROM_UNIXTIME", Broadcast.BroadcastStart)), Func("MONTH", Func("FROM_UNIXTIME", Broadcast.BroadcastStart)), Func("SUM", Broadcast.BroadcastEnd - Broadcast.BroadcastStart) ), Broadcast.StationID == Station.ID, where ).group_by(Station, Func("YEAR", Func("FROM_UNIXTIME", Broadcast.BroadcastStart)), Func("MONTH", Func("FROM_UNIXTIME", Broadcast.BroadcastStart))) data = list(self._splitData(data)) if len(data) == 0: raise NoDataArgError(kwargs, station=station, years=years) monthList = list(self._getMonthList(data)) data = list(self._mapData(data, monthList)) data.sort(key=lambda x: unicode(x[0])) dateList = [datetime(year, month+1, day=1, hour=0, minute=0) for year, month in monthList] xticks = list(self._filterTicksExt(dateList, monthList)) tickCoords = [float(i)+0.5 for i in self._filterTicksExt(range(len(monthList)), monthList)] coords = [i for i in xrange(len(monthList))] return (data, coords, xticks, tickCoords)
def getSession(self): store = Store.of(self) if store is None: return None if len(self.UserName) == 0 or len(self.EMail) == 0 or len( self.PasswordHash) == 0: return None # delete old sessions old = store.find(APISession, APISession.UserID == self.ID).any() if old is not None: old.delete() # generate a new session id sid = unicode(sha256(unicode(int(TimeUtils.now()))).hexdigest()) while store.find(APISession, APISession.Key == sid).any() is not None: sid = unicode( sha256( unicode(int(TimeUtils.now())) + unicode(rnd.randint(0, 655535))).hexdigest()) # create a new session session = APISession(sid, self.ID, int(TimeUtils.now() + 86400)) store.add(session) for cap in self.Capabilities: session.Capabilities.add(cap) return session
def priyom_timestamp(s): if allowNone and (((type(s) == str or type(s) == unicode) and (len(s) == 0 or s.lower() == "none")) or s is None): return None if type(s) == int or type(s) == float: if asDate: return TimeUtils.fromTimestamp(s) else: return s if asDate: return datetime.strptime(s, Formatting.priyomdate) else: return TimeUtils.toTimestamp(datetime.strptime(s, Formatting.priyomdate))
def getStationFrequencies(self, station, notModifiedCheck = None, head = False): global UPCOMING, PAST, ONAIR broadcasts = self.store.find(Broadcast, Broadcast.StationID == station.ID) lastModified = max( broadcasts.max(Broadcast.Modified), station.BroadcastRemoved ) if station.Schedule is not None: scheduleLeafs = self.store.find(ScheduleLeaf, ScheduleLeaf.StationID == station.ID) lastModified = lastModified if station.Schedule.Modified < lastModified else station.Schedule.Modified if head: return (lastModified, None) if notModifiedCheck is not None: notModifiedCheck(lastModified) if station.Schedule is None: now = TimeUtils.now() frequencies = self.store.find( (Max(Broadcast.BroadcastEnd), Min(Broadcast.BroadcastStart), Broadcast.BroadcastStart > now, BroadcastFrequency.Frequency, Modulation.Name), BroadcastFrequency.ModulationID == Modulation.ID, BroadcastFrequency.BroadcastID == Broadcast.ID, Broadcast.StationID == station.ID) frequencies.group_by(Or(Func("ISNULL", Broadcast.BroadcastEnd), And(Broadcast.BroadcastEnd >= now, Broadcast.BroadcastStart <= now)), Broadcast.BroadcastStart > now, BroadcastFrequency.Frequency, Modulation.Name) return (lastModified, ((freq, modulation, UPCOMING if isUpcoming == 1 else (ONAIR if lastUse is None else PAST), nextUse if isUpcoming else lastUse) for (lastUse, nextUse, isUpcoming, freq, modulation) in frequencies))
def __unicode__(self): return u"{1} event \"{0}\" at {2}".format( self.Description, unicode(self.EventClass) if self.EventClass is not None else u"raw", TimeUtils.fromTimestamp(self.StartTime).strftime( Formatting.priyomdate))
def getUpcomingBroadcasts(self, station, all, update, timeLimit, maxTimeRange, limiter=None, notModifiedCheck=None, head=False): now = TimeUtils.now() where = And( Or(Broadcast.BroadcastEnd > now, Broadcast.BroadcastEnd == None), (Broadcast.BroadcastStart < (now + timeLimit))) if not all: where = And(where, Broadcast.Type == u"data") if station is not None: where = And(where, Broadcast.StationID == stationId) broadcasts = self.store.find(Broadcast, where) lastModified = max( broadcasts.max(Broadcast.Modified), station.BroadcastRemoved if station is not None else None, station.Schedule.Modified if (station is not None and station.Schedule is not None) else None) if head: return (lastModified, None, None, None) if notModifiedCheck is not None: notModifiedCheck(lastModified) if update: untilDate = datetime.fromtimestamp(now) untilDate += timedelta(seconds=timeLimit) untilDate = self.normalizeDate(untilDate) until = TimeUtils.toTimestamp(untilDate) if station is None: validUntil = self.scheduleMaintainer.updateSchedules( until, maxTimeRange) else: validUntil = self.scheduleMaintainer.updateSchedule( station, until, maxTimeRange) # trans.set_header_value("Expires", self.model.formatHTTPTimestamp(validUntil)) return (lastModified, broadcasts if limiter is None else limiter(broadcasts), validUntil >= until, validUntil)
def editorToTree(self, parent): super(Timestamp, self).editorToTree(parent) dt = self.Value if dt is None: value = "" else: value = TimeUtils.toDatetime(self.Value).strftime(Formatting.priyomdate) self.input.set(u"value", value)
def appendDateElement(parentNode, name, value, useNamespace=namespace): date = TimeUtils.fromTimestamp(value) node = appendTextElement(parentNode, name, date.strftime(Formatting.priyomdate), useNamespace=useNamespace) node.set(u"unix", unicode(value)) return node
def getIsOnAir(self): now = datetime.datetime.utcnow() start = TimeUtils.toDatetime(self.BroadcastStart) if now > start: if self.BroadcastEnd is None: return True else: end = datetime.datetime.fromtimestamp(self.BroadcastEnd) return now < end else: return False
def getTransmissionsByMonth(self, stationId, year, month, limiter=None, notModifiedCheck=None, head=False): if month is not None: startTimestamp = datetime(year, month, 1) if month != 12: endTimestamp = datetime(year, month + 1, 1) else: endTimestamp = datetime(year + 1, 1, 1) else: startTimestamp = datetime(year, 1, 1) endTimestamp = datetime(year + 1, 1, 1) startTimestamp = TimeUtils.toTimestamp(startTimestamp) endTimestamp = TimeUtils.toTimestamp(endTimestamp) transmissions = self.store.find( (Transmission, Broadcast), Transmission.BroadcastID == Broadcast.ID, And( Broadcast.StationID == stationId, And(Transmission.Timestamp >= startTimestamp, Transmission.Timestamp < endTimestamp))) lastModified = max( transmissions.max(Transmission.Modified), self.store.find(Broadcast, Broadcast.StationID == stationId).max( Broadcast.TransmissionRemoved), self.store.get(Station, stationId).BroadcastRemoved) if head: return (lastModified, None) if notModifiedCheck is not None: notModifiedCheck(lastModified) transmissions.order_by(Desc(Transmission.Timestamp)) if limiter is not None: transmissions = limiter(transmissions) return (lastModified, (transmission for (transmission, broadcast) in transmissions))
def getSession(self): store = Store.of(self) if store is None: return None if len(self.UserName) == 0 or len(self.EMail) == 0 or len(self.PasswordHash) == 0: return None # delete old sessions old = store.find(APISession, APISession.UserID == self.ID).any() if old is not None: old.delete() # generate a new session id sid = unicode(sha256(unicode(int(TimeUtils.now()))).hexdigest()) while store.find(APISession, APISession.Key == sid).any() is not None: sid = unicode(sha256(unicode(int(TimeUtils.now()))+unicode(rnd.randint(0, 655535))).hexdigest()) # create a new session session = APISession(sid, self.ID, int(TimeUtils.now() + 86400)) store.add(session) for cap in self.Capabilities: session.Capabilities.add(cap) return session
def updateSchedule(self, station, until, limit=None): now = TimeUtils.now() if station.Schedule is None: return until if until is None or (until - now) > limits.schedule.maxLookahead: until = now + limits.schedule.maxLookahead if station.ScheduleUpToDateUntil is None: start = now else: start = station.ScheduleUpToDateUntil if until <= start: return start if limit is not None and (until - start) > limit: until = start + limit self._rebuildStationSchedule(station, start, until) self.store.flush() return until
def updateSchedule(self, station, until, limit = None): now = TimeUtils.now() if station.Schedule is None: return until if until is None or (until - now) > limits.schedule.maxLookahead: until = now + limits.schedule.maxLookahead if station.ScheduleUpToDateUntil is None: start = now else: start = station.ScheduleUpToDateUntil if until <= start: return start if limit is not None and (until - start) > limit: until = start + limit self._rebuildStationSchedule(station, start, until) self.store.flush() return until
def respond(self, trans): if not trans.get_request_method() in self.allowedMethods: trans.set_response_code(405) trans.set_header_value("Allow", ", ".join(self.allowedMethods)) print >> trans.get_response_stream( ), "Request method {0} is not allowed on this resource.".format( trans.get_request_method()) raise EndOfResponse self.parsePreferences(trans) self.store.autoreload() # to make sure we get current data self.trans = trans self.out = trans.get_response_stream() self.query = trans.get_fields_from_path() self.postQuery = {} if trans.get_content_type( ).media_type == "application/x-www-form-urlencoded": self.postQuery = trans.get_fields_from_body("utf-8") self.query.update(self.postQuery) trans.post_query = self.postQuery ifModifiedSince = trans.get_header_values("If-Modified-Since") if len(ifModifiedSince) > 0: try: self.ifModifiedSince = self.model.parseHTTPDate( ifModifiedSince[-1]) except ValueError as e: trans.set_response_code(400) print >> self.out, "If-Modified-Since date given in a invalid format: %s" % str( e) raise EndOfResponse self.ifModifiedSinceUnix = TimeUtils.toTimestamp( self.ifModifiedSince) else: self.ifModifiedSince = None self.ifModifiedSinceUnix = None self.normalizeQueryDict(self.query) self.normalizeQueryDict(self.postQuery) self.setupModel() self.head = trans.get_request_method() == "HEAD" try: result = self.handle(trans) finally: self.store.flush() return result
def updateSchedules(self, until, limit = None): now = TimeUtils.now() if until is None or (until - now) > limits.schedule.maxLookahead: until = now + limits.schedule.maxLookahead validUntil = until if limit is None: limit = until for station in self.store.find(Station, Station.Schedule != None, Or(Station.ScheduleUpToDateUntil < until, Station.ScheduleUpToDateUntil == None)): start = now if station.ScheduleUpToDateUntil is not None: start = station.ScheduleUpToDateUntil if until <= start: continue if (until - start) > limit: self._rebuildStationSchedule(station, start, start+limit) validUntil = min(validUntil, start+limit) else: self._rebuildStationSchedule(station, start, until) self.store.flush() return validUntil
def getStationFrequencies(self, station, notModifiedCheck=None, head=False): global UPCOMING, PAST, ONAIR broadcasts = self.store.find(Broadcast, Broadcast.StationID == station.ID) lastModified = max(broadcasts.max(Broadcast.Modified), station.BroadcastRemoved) if station.Schedule is not None: scheduleLeafs = self.store.find( ScheduleLeaf, ScheduleLeaf.StationID == station.ID) lastModified = lastModified if station.Schedule.Modified < lastModified else station.Schedule.Modified if head: return (lastModified, None) if notModifiedCheck is not None: notModifiedCheck(lastModified) if station.Schedule is None: now = TimeUtils.now() frequencies = self.store.find( (Max(Broadcast.BroadcastEnd), Min( Broadcast.BroadcastStart), Broadcast.BroadcastStart > now, BroadcastFrequency.Frequency, Modulation.Name), BroadcastFrequency.ModulationID == Modulation.ID, BroadcastFrequency.BroadcastID == Broadcast.ID, Broadcast.StationID == station.ID) frequencies.group_by( Or( Func("ISNULL", Broadcast.BroadcastEnd), And(Broadcast.BroadcastEnd >= now, Broadcast.BroadcastStart <= now)), Broadcast.BroadcastStart > now, BroadcastFrequency.Frequency, Modulation.Name) return (lastModified, ((freq, modulation, UPCOMING if isUpcoming == 1 else (ONAIR if lastUse is None else PAST), nextUse if isUpcoming else lastUse) for (lastUse, nextUse, isUpcoming, freq, modulation) in frequencies))
def respond(self, trans): if not trans.get_request_method() in self.allowedMethods: trans.set_response_code(405) trans.set_header_value("Allow", ", ".join(self.allowedMethods)) print >>trans.get_response_stream(), "Request method {0} is not allowed on this resource.".format(trans.get_request_method()) raise EndOfResponse self.parsePreferences(trans) self.store.autoreload() # to make sure we get current data self.trans = trans self.out = trans.get_response_stream() self.query = trans.get_fields_from_path() self.postQuery = {} if trans.get_content_type().media_type == "application/x-www-form-urlencoded": self.postQuery = trans.get_fields_from_body("utf-8") self.query.update(self.postQuery) trans.post_query = self.postQuery ifModifiedSince = trans.get_header_values("If-Modified-Since") if len(ifModifiedSince) > 0: try: self.ifModifiedSince = self.model.parseHTTPDate(ifModifiedSince[-1]) except ValueError as e: trans.set_response_code(400) print >>self.out, "If-Modified-Since date given in a invalid format: %s" % str(e) raise EndOfResponse self.ifModifiedSinceUnix = TimeUtils.toTimestamp(self.ifModifiedSince) else: self.ifModifiedSince = None self.ifModifiedSinceUnix = None self.normalizeQueryDict(self.query) self.normalizeQueryDict(self.postQuery) self.setupModel() self.head = trans.get_request_method() == "HEAD" try: result = self.handle(trans) finally: self.store.flush() return result
def updateSchedules(self, until, limit=None): now = TimeUtils.now() if until is None or (until - now) > limits.schedule.maxLookahead: until = now + limits.schedule.maxLookahead validUntil = until if limit is None: limit = until for station in self.store.find( Station, Station.Schedule != None, Or(Station.ScheduleUpToDateUntil < until, Station.ScheduleUpToDateUntil == None), ): start = now if station.ScheduleUpToDateUntil is not None: start = station.ScheduleUpToDateUntil if until <= start: continue if (until - start) > limit: self._rebuildStationSchedule(station, start, start + limit) validUntil = min(validUntil, start + limit) else: self._rebuildStationSchedule(station, start, until) self.store.flush() return validUntil
def isValid(self): store = Store.of(self) return (store is not None) and (len(self.Key) > 0) and (self.Expires > TimeUtils.now())
def handleException(self, trans, exceptionType, exception, tb): plainTextMessage = u"""On request: {0} {1} the following exception occured at {2}: """.format(trans.get_request_method(), trans.get_path(), TimeUtils.nowDate().isoformat()) plainTextMessage += self.generatePlainTextMessage(trans, exceptionType, exception, tb) print(plainTextMessage.encode("utf-8")) if "mail-to" in errors: try: mailConfig = errors["mail-to"] subject = mailConfig["subject"].format(exceptionType.__name__, unicode(exception)) to = mailConfig["to"] sender = mailConfig["sender"] smtp = mailConfig["smtp"] mail = MIMEText(plainTextMessage.encode("utf-8"), _charset="utf-8") mail["Subject"] = subject mail["To"] = ",".join(to) mail["From"] = sender mail["Date"] = self.model.formatHTTPTimestamp(TimeUtils.now()) host = smtp["host"] port = int(smtp.get("port", 25)) user = smtp.get("user", None) password = smtp.get("password", None) secure = smtp.get("secure", None) if not secure in ["starttls", "ssl"]: raise ValueError("Invalid value for secure: {0}".format(secure)) if secure == "ssl": conn = smtplib.SMTP_SSL(host, port) else: conn = smtplib.SMTP(host, port) if secure == "starttls": conn.starttls() if user is not None and password is not None: conn.login(user, password) conn.sendmail(mail["From"], mail["To"], mail.as_string()) conn.quit() except Exception as e : print("Could not send exception mail: {0}".format(e)) trans.rollback() trans.set_response_code(500) self.out = trans.get_response_stream() trans.set_content_type(ContentType("text/html", "utf-8")) s = u""" <html> <head> <title>Priyom.org internal API error</title> <link rel="stylesheet" type="text/css" href="{0}"/> </head> <body> <h1>Internal API error</h1>""".format(application.get("urlroot", u"") + u"/css/error.css") if self.show: s += u""" <h2>Error information</h2> <dl class="exc-info"> <dt>Exception class:</dt> <dd>{1}</dd> <dt>Message:</dt> <dd>{2}</dd> </dl> <h2>Stacktrace</h2> <p>(most recent call last)</p> <ul>{0}</ul>""".format( u"\n".join((u"""<li><div class="tb-item-head">File "<span class="tb-file">{0}</span>", line <span class="tb-lineno">{1:d}</span>, in <span class="tb-func">{2}</span></div><div class="tb-item-code">{3}</div>""".format(escape(os.path.relpath(filename, application["root"])), lineno, escape(funcname), escape(text)) for (filename, lineno, funcname, text) in traceback.extract_tb(tb))), escape(unicode(exceptionType)), escape(unicode(exception)).replace("\n", "<br/>") ) else: s += u""" <p>An internal error has occured. Please report this to <a href="mailto:{0}">{1}</a></p>""".format(admin["mail"], admin["name"]) s += u""" </body> </html>""" print >>self.out, s.encode("utf-8")
def transmissionRemoved(self): self.TransmissionRemoved = int(TimeUtils.now())
def handleException(self, trans, exceptionType, exception, tb): plainTextMessage = u"""On request: {0} {1} the following exception occured at {2}: """.format(trans.get_request_method(), trans.get_path(), TimeUtils.nowDate().isoformat()) plainTextMessage += self.generatePlainTextMessage( trans, exceptionType, exception, tb) print(plainTextMessage.encode("utf-8")) if "mail-to" in errors: try: mailConfig = errors["mail-to"] subject = mailConfig["subject"].format(exceptionType.__name__, unicode(exception)) to = mailConfig["to"] sender = mailConfig["sender"] smtp = mailConfig["smtp"] mail = MIMEText(plainTextMessage.encode("utf-8"), _charset="utf-8") mail["Subject"] = subject mail["To"] = ",".join(to) mail["From"] = sender mail["Date"] = self.model.formatHTTPTimestamp(TimeUtils.now()) host = smtp["host"] port = int(smtp.get("port", 25)) user = smtp.get("user", None) password = smtp.get("password", None) secure = smtp.get("secure", None) if not secure in ["starttls", "ssl"]: raise ValueError( "Invalid value for secure: {0}".format(secure)) if secure == "ssl": conn = smtplib.SMTP_SSL(host, port) else: conn = smtplib.SMTP(host, port) if secure == "starttls": conn.starttls() if user is not None and password is not None: conn.login(user, password) conn.sendmail(mail["From"], mail["To"], mail.as_string()) conn.quit() except Exception as e: print("Could not send exception mail: {0}".format(e)) trans.rollback() trans.set_response_code(500) self.out = trans.get_response_stream() trans.set_content_type(ContentType("text/html", "utf-8")) s = u""" <html> <head> <title>Priyom.org internal API error</title> <link rel="stylesheet" type="text/css" href="{0}"/> </head> <body> <h1>Internal API error</h1>""".format( application.get("urlroot", u"") + u"/css/error.css") if self.show: s += u""" <h2>Error information</h2> <dl class="exc-info"> <dt>Exception class:</dt> <dd>{1}</dd> <dt>Message:</dt> <dd>{2}</dd> </dl> <h2>Stacktrace</h2> <p>(most recent call last)</p> <ul>{0}</ul>""".format( u"\n".join(( u"""<li><div class="tb-item-head">File "<span class="tb-file">{0}</span>", line <span class="tb-lineno">{1:d}</span>, in <span class="tb-func">{2}</span></div><div class="tb-item-code">{3}</div>""" .format( escape(os.path.relpath(filename, application["root"])), lineno, escape(funcname), escape(text)) for (filename, lineno, funcname, text) in traceback.extract_tb(tb))), escape(unicode(exceptionType)), escape(unicode(exception)).replace("\n", "<br/>")) else: s += u""" <p>An internal error has occured. Please report this to <a href="mailto:{0}">{1}</a></p>""".format( admin["mail"], admin["name"]) s += u""" </body> </html>""" print >> self.out, s.encode("utf-8")
def broadcastRemoved(self): self.BroadcastRemoved = int(TimeUtils.now())
def toTableRow(self, tr): HTMLIntf.SubElement(tr, u"td").text = TimeUtils.fromTimestamp(self.Timestamp).strftime(priyomdate) HTMLIntf.SubElement(tr, u"th").text = self.Title HTMLIntf.SubElement(HTMLIntf.SubElement(tr, u"td"), u"p").text = self.Contents
def timestamp(value): return TimeUtils.fromTimestamp(value).strftime(priyomdate)
def __unicode__(self): return u"{1} event \"{0}\" at {2}".format( self.Description, unicode(self.EventClass) if self.EventClass is not None else u"raw", TimeUtils.fromTimestamp(self.StartTime).strftime(Formatting.priyomdate) )
def toTableRow(self, tr): HTMLIntf.SubElement(tr, u"td").text = TimeUtils.fromTimestamp( self.Timestamp).strftime(priyomdate) HTMLIntf.SubElement(tr, u"th").text = self.Title HTMLIntf.SubElement(HTMLIntf.SubElement(tr, u"td"), u"p").text = self.Contents