def parseResults(): resp = send('List', baseUrl + '/list/hotels') parser = PasskeyParser(resp) if not parser.json: raise RuntimeError("Failed to find search results") hotels = fromJS(parser.json) print("Results: (%s)" % datetime.now()) alerts = [] print(" %-15s %-10s %-80s %s" % ('Distance', 'Price', 'Hotel', 'Room')) for hotel in hotels: for block in hotel['blocks']: # Don't show hotels miles away unless requested if hotel['distanceUnit'] == 3 and not args.show_all: continue connected = ('Skywalk to ICC' in (hotel['messageMap'] or '')) simpleHotel = { 'name': parser.unescape(hotel['name']), 'distance': 'Skywalk' if connected else "%4.1f %s" % (hotel['distanceFromEvent'], distanceUnits.get(hotel['distanceUnit'], '???')), 'price': int(sum(inv['rate'] for inv in block['inventory'])), 'rooms': min(inv['available'] for inv in block['inventory']), 'room': parser.unescape(block['name']), } if simpleHotel['rooms'] == 0: continue result = "%-15s $%-9s %-80s (%d) %s" % (simpleHotel['distance'], simpleHotel['price'], simpleHotel['name'], simpleHotel['rooms'], simpleHotel['room']) # I don't think these distances (yards, meters, kilometers) actually appear in the results, but if they do assume it must be close enough regardless of --max-distance closeEnough = hotel['distanceUnit'] in (2, 4, 5) or \ (hotel['distanceUnit'] == 1 and (args.max_distance is None or (isinstance(args.max_distance, float) and hotel['distanceFromEvent'] <= args.max_distance))) or \ (args.max_distance == 'connected' and connected) cheapEnough = simpleHotel['price'] <= args.budget regexMatch = args.hotel_regex.search(simpleHotel['name']) and args.room_regex.search(simpleHotel['room']) if closeEnough and cheapEnough and regexMatch: alerts.append(simpleHotel) stdout.write(' ! ') else: stdout.write(' ') print(result) global lastAlerts if alerts: alertHash = {(alert['name'], alert['room']) for alert in alerts} if alertHash <= lastAlerts: print("Skipped alerts (no new rooms in nearby hotel list)") else: numHotels = len(set(alert['name'] for alert in alerts)) preamble = "%d %s near the ICC:" % (numHotels, 'hotel' if numHotels == 1 else 'hotels') for fn in alertFns: # Run each alert on its own thread since some (e.g. popups) are blocking and some (e.g. e-mail) can throw Thread(target = fn, args = (preamble, alerts)).start() print("Triggered alerts") else: alertHash = set() print() lastAlerts = alertHash return True
def searchExisting(hash = []): '''Search using an acknowledgement number (for users who have booked a room)''' # The hash doesn't change, so it's only calculated the first time if not hash: send('Session request', baseUrl + '/home') data = { 'ackNum': args.key[0], 'lastName': args.key[1], } resp = send('Finding reservation', Request(baseUrl + '/reservation/find', toJS(data).encode('utf8'), {'Content-Type': 'application/json'})) try: respData = fromJS(resp.read()) except Exception as e: raise RuntimeError("Failed to decode reservation: %s" % e) if respData.get('ackNum', None) != args.key[0]: raise RuntimeError("Reservation not found. Are your acknowledgement number and surname correct?") if 'hash' not in respData: raise RuntimeError("Hash missing from reservation data") hash.append(respData['hash']) data = { 'blockMap': { 'blocks': [{ 'blockId': '0', 'checkIn': args.checkin, 'checkOut': args.checkout, 'numberOfGuests': str(args.guests), 'numberOfRooms': str(args.rooms), 'numberOfChildren': str(args.children), }] }, } send('Loading existing reservation', baseUrl + "/r/%s/%s" % (args.key[0], hash[0])) send('Search', Request(baseUrl + '/rooms/select/search', toJS(data).encode('utf8'), headers = {'Content-Type': 'application/json'}))
def adminReplPost(handler, p_code): def makeStr(v): if isinstance(v, list): return "<ul>%s</ul>" % ''.join("<li>%s</li>" % item for item in v) return str(v) handler.wrappers = False p_code = re.sub('^!([A-Za-z]+)$', 'from \\1 import \\1', p_code) match = re.match('!([A-Za-z ]+)$', p_code) if match: parts = match.group(1).split(' ') res = [] for part in parts: w = ResponseWriter() adminReplPost(handler, "!%s" % part) res.append(fromJS(w.done())) print toJS(res) done() if 'admin-repl' not in handler.session: print toJS({'code': highlightCode(p_code), 'stdout': '', 'stderr': ['Session Expired', 'REPL session no longer exists'], 'vars': {}}) done() writer = ResponseWriter() try: Event.repl(handler, p_code) exec compile(p_code, '<admin repl>', 'single') in handler.session['admin-repl'] stderr = '' except: stderr = map(str, [sys.exc_info()[0].__name__, sys.exc_info()[1]]) stdout = writer.done() vars = sorted([(k, pformat(v), makeStr(v)) for (k, v) in handler.session['admin-repl'].items() if k != '__builtins__'], lambda (k1, v1, vs1), (k2, v2, vs2): cmp(k1, k2)) print toJS({'code': highlightCode(p_code), 'stdout': stdout, 'stderr': stderr, 'vars': vars})
def js(self): print "<script type=\"text/javascript\">" print "$(document).ready(function() {", print "new Highcharts.Chart(", print re.sub('"(?:\\\\n)*function\(\) {(.*)}(?:\\\\n)*"', lambda match: fromJS(match.group(0)), toJS(self._m, sort_keys = True, indent = 4)), print ");", print "});" print "</script>"
def js(self): print "$(%s).highcharts(" % toJS("#" + self._id), js = toJS(self._m, sort_keys=True, indent=4, cls=CustomEncoder) # Unwrap raw data. See the comment above in CustomEncoder for the reason for this insanity js = re.sub( re.escape(toJS(raw.wrapper)).replace("\\%s", "(.*)"), lambda match: fromJS('"%s"' % match.group(1)), js ) print js print ");"
def parseResults(): resp = send('List', baseUrl + '/list/hotels') parser = PasskeyParser(resp) if not parser.json: raise RuntimeError("Failed to find search results") hotels = fromJS(parser.json) print("Results: (%s)" % datetime.now()) alerts = [] print(" %-15s %-10s %-80s %s" % ('Distance', 'Price', 'Hotel', 'Room')) for hotel in hotels: for block in hotel['blocks']: # Don't show hotels miles away unless requested if hotel['distanceUnit'] == 3 and not args.show_all: continue connected = ('Skywalk to ICC' in (hotel['messageMap'] or '')) simpleHotel = { 'name': parser.unescape(hotel['name']), 'distance': 'Skywalk' if connected else "%4.1f %s" % (hotel['distanceFromEvent'], distanceUnits.get(hotel['distanceUnit'], '???')), 'price': int(sum(inv['rate'] for inv in block['inventory'])), 'rooms': min(inv['available'] for inv in block['inventory']), 'room': parser.unescape(block['name']), } if simpleHotel['rooms'] == 0: continue result = "%-15s $%-9s %-80s (%d) %s" % (simpleHotel['distance'], simpleHotel['price'], simpleHotel['name'], simpleHotel['rooms'], simpleHotel['room']) #nameMatch = ('Fair' in simpleHotel['name']) or ('fair' in simpleHotel['name']) or ('Spring' in simpleHotel['name']) or ('spring' in simpleHotel['name']) or ('Court' in simpleHotel['name']) or ('court' in simpleHotel['name']) or ('Embassy' in simpleHotel['name']) or ('embassy' in simpleHotel['name']) #connected = True # I don't think these distances (yards, meters, kilometers) actually appear in the results, but if they do assume it must be close enough regardless of --max-distance closeEnough = connected \ #Uncomment for blocks #or hotel['distanceUnit'] == 1 or hotel['distanceFromEvent'] == 1 or hotel['distanceUnit'] in (2, 4, 5) or \ #(hotel['distanceUnit'] == 1 and (args.max_distance is None or (isinstance(args.max_distance, float) and hotel['distanceFromEvent'] <= args.max_distance))) or \ (args.max_distance == 'connected' and connected) #if closeEnough and nameMatch: if closeEnough: alerts.append(simpleHotel) stdout.write(' ! ') else: stdout.write(' ') print(result) if alerts: notifyPushbullet() notifyDiscord() return True
def searchExisting(hash = []): '''Search using an acknowledgement number (for users who have booked a room)''' # The hash doesn't change, so it's only calculated the first time if not hash: send('Session request', baseUrl + '/home') data = { 'ackNum': args.key, 'lastName': args.surname, } resp = send('Finding reservation', Request(baseUrl + '/reservation/find', toJS(data), {'Content-Type': 'application/json'})) try: respData = fromJS(resp.read()) except Exception, e: raise RuntimeError("Failed to decode reservation: %s" % e) if respData.get('ackNum', None) != args.key: raise RuntimeError("Reservation not found. Are your acknowledgement number and surname correct?") if 'hash' not in respData: raise RuntimeError("Hash missing from reservation data") hash.append(respData['hash'])
def on_message(self, message): console('websocket', "Message received: %s" % message) try: data = fromJS(message) except: return if 'subscribe' in data and isinstance(data['subscribe'], list): addChannels = (set(data['subscribe']) - self.channels) self.channels |= addChannels for channel in addChannels: if channel not in channels: channels[channel] = set() channels[channel].add(self) if 'unsubscribe' in data and isinstance(data['unsubscribe'], list): rmChannels = (self.channels & set(data['unsubscribe'])) self.channels -= rmChannels for channel in rmChannels: channels[channel].remove(self) if len(channels[channel]) == 0: del channels[channel]
def newTaskImportPost(handler, group, source, p_data): def die(msg): print msg done() handler.title("Import Tasks") requirePriv(handler, "User") handler.wrappers = False id = int(group) group = Group.load(id) if not group or group.sprint.isHidden(handler.session["user"]): die("No group with ID <b>%d</b>" % id) sprint = group.sprint if not (sprint.isActive() or sprint.isPlanning()): die("Unable to modify inactive sprint") elif not sprint.canEdit(handler.session["user"]): die("You don't have permission to modify this sprint") id = int(source) source = Sprint.load(id) if not source: die("No sprint with ID <b>%d</b>" % id) try: data = fromJS(p_data) except ValueError: die("Improperly encoded data") if not isinstance(data, list) or not all( set(task.keys()) == {"name", "assigned", "status", "groupid", "hours"} for task in data ): die("Improperly encoded data") usernames = {user.username for user in sprint.members} if not all( set(task["assigned"].split(" ")) <= usernames and task["status"] in statuses and isinstance(task["groupid"], int) and Group.load(task["groupid"]) is not None and isinstance(task["hours"], int) and task["hours"] >= 0 for task in data ): die("Invalid data") dataByGroup = {} for task in data: if task["groupid"] not in dataByGroup: dataByGroup[task["groupid"]] = [] dataByGroup[task["groupid"]].append(task) newGroups = {} # old sprint's group ID -> new sprint's new Group object for groupid in dataByGroup: oldGroup = Group.load(groupid) group = Group.load(sprintid=sprint.id, name=oldGroup.name) if not group: # No group in this sprint with the right name if groupid in newGroups: # Already made a new group group = newGroups[groupid] else: # Need a new group group = newGroups[groupid] = Group(sprint.id, oldGroup.name) group.save() for taskData in dataByGroup[groupid]: task = Task( group.id, sprint.id, handler.session["user"].id, 0, taskData["name"], taskData["status"], taskData["hours"], {User.load(username=username).id for username in taskData["assigned"].split(" ")}, ) task.save() Event.newTask(handler, task) numGroups, numTasks = len(newGroups), len(data) if numGroups > 0 and numGroups > 0: delay( handler, SuccessBox( "Added %d %s, %d %s" % (numGroups, "group" if numGroups == 1 else "groups", numTasks, "task" if numTasks == 1 else "tasks"), close=3, fixed=True, ), ) elif numGroups > 0: delay( handler, SuccessBox("Added %d %s" % (numGroups, "group" if numGroups == 1 else "groups"), close=3, fixed=True), ) elif numTasks > 0: delay( handler, SuccessBox("Added %d %s" % (numTasks, "task" if numTasks == 1 else "tasks"), close=3, fixed=True) ) else: delay(handler, WarningBox("No changes", close=3, fixed=True)) handler.responseCode = 299