class CloseBroadcastsAPI(API): title = u"getCloseBroadcasts" shortDescription = u"Find broadcasts close to a given timestamp" docArgs = [ Argument(u"stationId", u"station ID", u"id of the station at which to search for broadcasts", metavar=u"stationid"), Argument(u"time", u"unix timestamp", u"center of the time area which to take into account", metavar=u"timestamp"), Argument(u"jitter", u"seconds", u"amount of seconds to look around the given timestamp. defaults to 600 seconds", metavar=u"seconds", optional=True) ] docCallSyntax = CallSyntax(docArgs, u"?{0}&{1}&{2}") def handle(self, trans): stationId = self.getQueryInt("stationId", "int; id of the station") time = self.getQueryInt("time", "int; unix timestamp at which to look") jitter = self.getQueryIntDefault("jitter", 600, "int; jitter in seconds") if jitter < 0 or jitter > 600: self.parameterError("jitter", "jitter %d out of bounds (0..600)" % (jitter)) lastModified, broadcasts = self.priyomInterface.getCloseBroadcasts(stationId, time, jitter, notModifiedCheck=self.autoNotModified, head=self.head) trans.set_content_type(ContentType("application/xml", self.encoding)) trans.set_header_value("Last-Modified", self.model.formatHTTPTimestamp(lastModified)) if self.head: return self.model.exportListToFile(self.out, broadcasts, Broadcast, encoding=self.encoding)
class TransmissionsByMonthAPI(API): title = u"getTransmissionsByMonth" shortDescription = u"list the transmissions of a given calendar month" docArgs = [ Argument(u"stationId", u"station id", u"select the station at which to look", metavar="stationid"), Argument(u"year", u"integer year", u"year to look at", metavar="year"), Argument(u"month", u"integer month (1-12)", u"month of year to look at", metavar="month") ] docCallSyntax = CallSyntax(docArgs, u"?{0}&{1}&{2}") def handle(self, trans): stationId = self.getQueryInt("stationId", "must be integer") year = self.getQueryInt("year", "must be integer") month = self.getQueryInt("month", "must be integer") if month < 1 or month > 12: self.parameterError("month", "Month %d out of bounds (1..12)" % (month)) return lastModified, transmissions = self.priyomInterface.getTransmissionsByMonth( stationId, year, month, limiter=None, notModifiedCheck=self.autoNotModified, head=self.head) trans.set_header_value( 'Last-Modified', self.model.formatHTTPTimestamp(float(lastModified))) trans.set_content_type(ContentType('application/xml', self.encoding)) if self.head: return self.model.exportListToFile(self.out, transmissions, Transmission, encoding=self.encoding, flags={"with-freqs"})
class StationFrequenciesAPI(API): title = u"getStationFrequencies" shortDescription = u"get a list of frequencies the station uses" docArgs = [ Argument(u"stationId", u"station id", u"select the station at which to look", metavar="stationid") ] docCallSyntax = CallSyntax(docArgs, u"?{0}") def handle(self, trans): stationId = self.getQueryInt("stationId", "must be integer") station = self.store.get(Station, stationId) if station is None: self.parameterError("stationId", "Station does not exist") lastModified, frequencies = self.priyomInterface.getStationFrequencies( station, notModifiedCheck=self.autoNotModified, head=self.head) trans.set_content_type(ContentType("application/xml", self.encoding)) trans.set_header_value("Last-Modified", self.model.formatHTTPTimestamp(lastModified)) if self.head: return doc = self.model.getExportTree("station-frequencies") rootNode = doc.getroot() for (freq, modulation, state, timestamp) in frequencies: node = XMLIntf.appendTextElement(rootNode, u"station-frequency", unicode(freq), attrib={ u"modulation": modulation, u"state": state }) if state != ONAIR: node.set(u"unix", unicode(timestamp)) self.model.etreeToFile(self.out, doc, encoding=self.encoding)
class InstanciateSchedulesAPI(API): title = u"instanciateSchedules" shortDescription = u"instanciate schedules" docArgs = [ Argument(u"stationId", u"station ID", u"Restrict the instanciation to a single station", metavar="stationid", optional=True), ] docCallSyntax = CallSyntax(docArgs, u"?{0}") docRequiredPrivilegues = u"instanciate" def __init__(self, model): super(InstanciateSchedulesAPI, self).__init__(model) self.allowedMethods = frozenset(("POST", "GET", "HEAD")) def handle(self, trans): stationId = self.getQueryIntDefault("stationId", None, "must be integer") trans.set_content_type(ContentType("text/plain", self.encoding)) if self.head: return if trans.get_request_method() == "GET": print >> self.out, u"failed: Call this resource with POST to perform instanciation.".encode( self.encoding) return generatedUntil = 0 if stationId is None: generatedUntil = self.priyomInterface.scheduleMaintainer.updateSchedules( None) else: generatedUntil = self.priyomInterface.scheduleMaintainer.updateSchedule( self.store.get(Station, stationId), None) print >> self.out, u"success: valid until {0}".format( datetime.fromtimestamp(generatedUntil).strftime( priyomdate)).encode(self.encoding)
class TransmissionStatsAPI(API): title = u"getTransmissionStats" shortDescription = u"get the amount of transmissions grouped by calendar months" docArgs = [ Argument(u"stationId", u"station id", u"select the station at which to look", metavar="stationid") ] docCallSyntax = CallSyntax(docArgs, u"?{0}") def handle(self, trans): stationId = self.getQueryInt("stationId", "must be integer") lastModified, months = self.priyomInterface.getTransmissionStats( stationId, notModifiedCheck=self.autoNotModified, head=self.head) trans.set_content_type(ContentType("application/xml", self.encoding)) trans.set_header_value( 'Last-Modified', self.model.formatHTTPTimestamp(float(lastModified))) if self.head: return doc = self.model.getExportTree("transmission-stats") rootNode = doc.getroot() for month in months: XMLIntf.appendTextElement(rootNode, u"transmission-count", unicode(month[2]), attrib={ u"year": unicode(month[0]), u"month": unicode(month[1]) }) self.model.etreeToFile(self.out, doc, encoding=self.encoding)
class DuplicatedTransmissionItemsAPI(API): title = u"getDuplicatedTransmissionItems" shortDescription = u"get a list of duplicated transmission items" docArgs = [ Argument(u"stationId", u"station id", u"select the station at which to look", metavar="stationid"), Argument(u"tableId", u"class table id", u"select the transmission class table to look at", metavar="classtableid"), Argument(u"equalFields", u"comma separated list", u"transmission item fields to look at (all if omitted)", metavar="equalfields", optional=True), Argument(u"includeOtherStationsWithin", u"integer seconds", u"how many seconds transmissions of other stations with same contents may be away to be selected", metavar="seconds", optional=True) ] docCallSyntax = CallSyntax(docArgs, u"?{0}&{1}&{2}&{3}") def handle(self, trans): stationId = self.getQueryInt("stationId", "must be a station id") station = self.store.get(Station, stationId) if station is None: self.parameterError("stationId", "Station does not exist") tableId = self.getQueryInt("tableId", "must be a class table id") table = self.store.get(TransmissionTable, tableId) if table is None: self.parameterError("tableId", "Table does not exist") matchFields = [s for s in (item.lstrip().rstrip() for item in self.query.get("equalFields", u"").split(u",")) if len(s) > 0] if len(matchFields) == 0: matchFields = None else: for field in matchFields: if not hasattr(table, field): self.parameterError("equalFields", "{0} is not a valid field for this table.".format(field)) includeOtherStationsWithin = self.getQueryIntDefault("includeOtherStationsWithin", 86400, "must be integer seconds") lastModified, items = self.priyomInterface.getDuplicateTransmissions(table, station, matchFields, includeOtherStationsWithin, notModifiedCheck=self.autoNotModified, head=self.head) trans.set_content_type(ContentType("application/xml", self.encoding)) trans.set_header_value("Last-Modified", self.model.formatHTTPTimestamp(float(lastModified))) if self.head: return doc = self.model.getExportTree("duplicated-transmissions") rootNode = doc.getroot() dupeDict = {} for bc1, tx1, txItem1, bc2, tx2, txItem2 in items: if matchFields is None: key = unicode(txItem1) else: key = u" ".join((getattr(txItem1, field) for field in matchFields)) if key in dupeDict: rec = dupeDict[key] rec.add(bc1, tx1, txItem1) rec.add(bc2, tx2, txItem2) dupeDict[key] = rec continue node = XMLIntf.SubElement(rootNode, u"duplicated-transmission") #node.setAttribute("key", key) rec = DupeRecord(doc, node) rec.add(bc1, tx1, txItem1) rec.add(bc2, tx2, txItem2) dupeDict[key] = rec self.model.etreeToFile(self.out, doc, encoding=self.encoding)
class SessionAPI(API): title = u"getSession" shortDescription = u"Login and get a session id" docArgs = [ Argument(u"user", u"string", u"user name", metavar=u"username"), Argument(u"pass", u"string", u"password", metavar=u"password") ] docCallSyntax = CallSyntax(docArgs, u"?{0}&{1}") docReturnValue = u"Returns the session id on success or “failed: message” in case of an error, whereas message will be replaced by the error message." def __init__(self, model): super(SessionAPI, self).__init__(model) self.allowedMethods = frozenset(["GET", "POST"]) def handle(self, trans): trans.hide_post = True trans.set_content_type(ContentType("text/plain", self.encoding)) if (not "user" in self.query) or (not "pass" in self.query): if "cookie" in self.query: trans.set_content_type(ContentType("text/html", self.encoding)) print >> self.out, u"""<html> <head> <title>{0}</title> </head> <body> <form name="login" action="getSession?cookie" method="POST"> Username: <input type="text" name="user" value="" /><br /> Password: <input type="password" name="pass" value="" /><br /> <input type="submit" name="submit" value="Login" /> </form> </body> </html>""".format(self.model.formatHTMLTitle(u"Login")).encode( self.encoding, 'replace') return else: print >> self.out, ( u"failed: need user and pass arguments").encode( self.encoding) return userName = self.query["user"] password = self.query["pass"] user = self.store.find(APIUser, APIUser.UserName == userName).any() if user is None: print >> self.out, (u"failed: user (%s) not found" % userName).encode(self.encoding) return if not user.checkPassword(password): print >> self.out, (u"failed: password invalid").encode( self.encoding) return password = None session = user.getSession() if "cookie" in self.query: trans.set_cookie_value("priyom-api-session", trans.encode_cookie_value(session.Key), '/', session.Expires) trans.set_content_type(ContentType("text/plain", self.encoding)) print >> self.out, u"You are now logged in (a cookie has been set).".encode( self.encoding, 'replace') else: print >> self.out, session.Key.encode(self.encoding, 'replace')