예제 #1
0
 def query(self, _id):
     L.info("Calling query id: %s " % _id)
     try:
         result = self.server.query()
         self.update_pending(result)
         self.send_query_result(_id, result, self.pending)
     except ServerException as e:
         self.send_query_result(_id, None, self.pending, e.status)
예제 #2
0
 def stop_service(self):
     if self.service is None:
         return
     L.info("Trying to stop service")
     if platform == 'android':
         from android import AndroidService
         self.service.stop()
         self.service = None
예제 #3
0
 def start_service(self):
     if self.service is not None:
         return
     L.info("Trying to start service")
     if platform == 'android':
         from android import AndroidService
         service = AndroidService('AndroidPark(ing)', 'en ejecución...')
         service.start('service started')
         self.service = service
예제 #4
0
 def modify(self, _id):
     L.info("Calling modify id:%s " % _id)
     try:
         result = self.server.modify(self.pending, lambda (s): self.send_modify_partial_result(_id, s))
         self.last_time = datetime.datetime.now(tz=self.met)
         self.notified = False
         self.update_pending(result)
         self.send_modify_result(_id, "OK")
     except ServerException as e:
         self.send_modify_result(_id, e.status)
예제 #5
0
    def modify(self, operations, partial):
        status = self.query()
        last_text = ""
        today = datetime.datetime.now(tz=self.met)
        for i in sorted(operations):
            if i.month == 1 and today.month == 12:
                mes = 1
            else:
                mes = i.month - today.month
            if mes not in (0, 1):
                L.error(str(i) + " is neither current nor next month")
                partial(str(i) + " no es parte del mes actual o siguiente")
                continue

            if operations[i] == DayStatus.TO_REQUEST:
                if i not in status or status[i].status in (
                    DayStatus.RESERVED,
                    DayStatus.NOT_AVAILABLE,
                    DayStatus.REQUESTED,
                    DayStatus.BUSY,
                ):
                    partial(str(i) + " está ya solicitado")
                    continue
            if operations[i] in (DayStatus.TO_FREE, DayStatus.TO_UNREQUEST):
                # Operation is to free/unrequest
                if i not in status or status[i].status in (DayStatus.AVAILABLE, DayStatus.NOT_AVAILABLE):
                    partial(str(i) + " está ya liberado")
                    continue
            try:
                L.debug("Requesting " + str(i) + ": " + self.map_operation(operations[i]))
                r = self.session.post(
                    "http://" + self.host + "/perfil.php", data={"dia": i.day, "mes": mes, "libre": operations[i]}
                )

                if r.status_code != requests.codes.ok:
                    L.error("Failed request on " + self.host + ", response:" + r)
                    partial(str(i) + "`: Failed request on server response:" + r)
                    continue

                # Parse the web page to obtain the result message
                last_text = self.get_response_text(r)
                result = self.parse_result(last_text)
                if result == "":
                    result = "La modificación de " + str(i) + " no fue aceptada"
                partial(result)
                L.info(str(i) + ": " + result)
            except (KeyboardInterrupt, requests.ConnectionError):
                L.debug("Petición fallida en " + self.host + ", con:\n" + traceback.format_exc())

        if last_text != "":
            return self.parse_months(last_text)
        else:
            # We didn't send any operation, use the status retrieved
            # when we entered the method.
            return status
예제 #6
0
 def update_notification(self, text):
     L.info("Notification: " + text)
     if platform == 'android':
         try:
             service = PythonService.mService
             builder = NotificationBuilder(service)
             builder.setSmallIcon(service.getApplicationInfo().icon)
             builder.setContentTitle("AndroidPark(ing)")
             builder.setContentText(text)
             context_intent = Intent(service, Class.forName('org.renpy.android.PythonActivity'))
             pending_intent = PendingIntent.getActivity(service, 0, context_intent,
                                                        PendingIntent.FLAG_UPDATE_CURRENT)
             builder.setContentIntent(pending_intent)
             manager = service.getSystemService(Context.NOTIFICATION_SERVICE)
             manager.notify(1, builder.build())
         except:
             L.error("Exception:\n" + traceback.format_exc())
예제 #7
0
    def update_pending(self, result):
        """
        Update the pending operations with the result retrieved from the web.
        :param result:
        :return: None
        """
        self.check_next_month(result)
        to_delete = []

        L.info("pending (before) " + str(self.pending))

        for i in sorted(self.pending):
            today = datetime.datetime.now(tz=self.met)
            if(i.month==1 and today.month==12):
                mes = 1
            else:
                mes = i.month - today.month
            if mes not in (0, 1):
                L.error(str(i) + " is neither current nor next month")
                to_delete.append(i)
                continue
            if self.pending[i] == DayStatus.TO_FREE:
                # Request was to Free... target should be Free.
                if i not in result or result[i].status in (DayStatus.AVAILABLE, DayStatus.NOT_AVAILABLE):
                    to_delete.append(i)

            if self.pending[i] == DayStatus.TO_REQUEST:
                # Request was to Request.... target is Assigned.
                if i not in result or result[i].status in (DayStatus.RESERVED, DayStatus.NOT_AVAILABLE):
                    to_delete.append(i)

            if self.pending[i] == DayStatus.TO_UNREQUEST:
                # Request was to Unrequest.
                if i not in result or result[i].status in (DayStatus.AVAILABLE, DayStatus.NOT_AVAILABLE):
                    to_delete.append(i)

        for i in to_delete:
            del self.pending[i]

        for i in [i for i in result if result[i].status == DayStatus.REQUESTED]:
            self.pending[i] = DayStatus.TO_REQUEST

        L.info("pending (after) " + str(self.pending))
예제 #8
0
 def check_interval(self):
     """
     Check if it is time for a new attempt
     :return: True if it is time for a new attempt
     """
     now = datetime.datetime.now(tz=self.met)
     tomorrow = now.date() + datetime.timedelta(days=1)
     f1 = 0
     f2 = 0
     if self.config is not None:
         f1 = int(self.config.get("timers", "frequency")) * 60
         f2 = int(self.config.get("timers", "frequency2")) * 60
     if len(self.pending) > 0 and \
             ((self.t1 <= now.time() < self.t2) or (self.t3 <= now.time() < self.t4)):
         # Period 00:00 - 14:59: attempt every 30 min
         if self.last_time is None or (0 < f1 < (now - self.last_time).total_seconds()):
             L.info("modify on regular interval")
             return True
     if (self.t2 <= now.time() < self.t3) and tomorrow in self.pending:
         # Period 15:00 - 17:30: attempt 1 min (but only if there's something pending for tomorrow
         if self.last_time is None or (0 < f2 < (now - self.last_time).total_seconds()):
             L.info("modify on repesca interval")
             return True
     if len(self.pending) > 0 and \
        now.hour == 14 and now.minute > 50 and \
        now.second > random.randrange(0, 60) and \
        ((self.last_time is None) or ((now - self.last_time).total_seconds() > (10 * 60))):
         # One final at 14:50 + random seconds
         # and only if we haven't requested  more than 10 minutes ago.
         L.info("modify on Last call")
         return True
     return False
예제 #9
0
    def parse_months(self, text):
        """
        Parse the web page to obtain the
        list of the days and their status
        :param text: the text from the http response
        :return: a dictionary with the status of the days
        """
        result = []
        out = {}

        soup = bs4.BeautifulSoup(text, "html5lib")
        # get the cells... this is better reference I could get
        toptables = soup.select("body > table ")

        if len(toptables) != 6:
            L.error("Parsing: did not found 6 tables")
            return None

        tables = [toptables[4].tbody.tr.td.table, toptables[5].tbody.contents[1].td.table]

        # Now, for each table.
        for t in tables:
            month = []
            # for each week (row)
            for w in t.select("tr"):
                # for each day (cell)
                for d in w.select("td"):
                    # only pay attention to colored cells
                    if "bgcolor" in d.attrs:
                        # Try to parse the cell
                        cell_list = d.select("div")
                        if len(cell_list) == 0:
                            # No divs... not interested in this
                            continue
                        elif len(cell_list) < 2:
                            # only one div
                            day = cell_list[0]
                            slot = None
                        else:
                            # two divs.
                            (day, slot) = cell_list

                        # some days appear with two nested divs.
                        if day.string is not None:
                            mday = int(day.string.strip())
                        else:
                            mday = int([x for x in day.stripped_strings][0])
                        rslot = None
                        # parse the status based on the color
                        if d.attrs["bgcolor"] == "#999999":
                            status = DayStatus.NOT_AVAILABLE
                        elif d.attrs["bgcolor"] == "#FF9900":
                            status = DayStatus.RESERVED
                            if slot is not None:
                                rslot = [x for x in slot.stripped_strings][0]
                        elif d.attrs["bgcolor"] == "#339900":
                            status = DayStatus.AVAILABLE
                        elif d.attrs["bgcolor"] == "#000000":
                            status = DayStatus.REQUESTED
                        else:
                            status = DayStatus.BUSY
                        month.append(DayStatus(mday, status, rslot))
            result.append(month)

        if len(result) != 2:
            L.error("Parsing: did not found 2 months")
            return None
        # Now rebuild the date
        today = datetime.datetime.now(tz=self.met)
        today = datetime.date(today.year, today.month, 1)
        for d in [x.fix(today) for x in result[0]]:
            out[d.date] = d
        for d in [x.fix(today + datetime.timedelta(days=31)) for x in result[1]]:
            out[d.date] = d

        busy = len([x for x in out if out[x].status == DayStatus.BUSY])
        requested = len([x for x in out if out[x].status == DayStatus.REQUESTED])
        reserved = len([x for x in out if out[x].status == DayStatus.RESERVED])
        available = len([x for x in out if out[x].status == DayStatus.AVAILABLE])
        L.info("Parsed: %d busy,%d requested, %d reserved, %d available" % (busy, requested, reserved, available))
        return out
예제 #10
0
 def modify_partial_callback(self, status):
     L.info(status)
     self.status_bar.text = status.decode('utf-8', 'replace').encode('utf-8')