Ejemplo n.º 1
0
 def getEntries(self, dayRange=8, dayOffset=0, **kwargs):
     key = get_cache_key(self.login_data, self.cache_key, dayRange=dayRange, dayOffset=dayOffset, useDate=True, **kwargs)
     logger.debug(key)
     entries = self._loadCache(key)
     error = None
     if entries is None:
         (error, bookings) = self.getAllBookings()
         #logger.debug(bookings)
         if not bookings:
             return None
         Range = namedtuple('Range', ['start', 'end'])
         # week = Range(start=datetime.now(), end=datetime.now() + timedelta(days=8))
         entries = []
         for booking, rules, start, duration in bookings:
             # print(list(rules))
             for rule in rules.between(
                     datetime.datetime.combine(datetime.datetime.now().date() + datetime.timedelta(days=dayOffset), datetime.time(0, 0)),
                     datetime.datetime.combine(datetime.datetime.now().date() + datetime.timedelta(days=dayOffset + dayRange),
                                      datetime.time(23, 59)), inc=True):
                 rule_start = datetime.datetime.combine(rule, start.time())
                 r = Range(start=rule_start, end=rule_start + duration)
                 entries.append(self._make_entry(r, booking))
         entries = self.sortBookings(entries, **kwargs)
         if not error:
             redis.set(key, pickle.dumps(entries), ex=24 * 3600)
     return error, entries
Ejemplo n.º 2
0
    def searchEntries(self, text):
        text = text.lower()
        key = get_cache_key(self.login_data, self.cache_key + ':search', text)
        entry_data = self._loadCache(key)
        if entry_data is None:
            entries = []
            error, bookings = self.getEntries(dayRange=365)
            # (error, data) = self._ajaxResponse()
            # if error or not data:
            #     return None
            toomany = False
            for booking in bookings:
                if 'status_id' in booking and int(booking['status_id']) == 99:
                    continue

                if any(key in booking and booking[key] and text in booking[key].lower()
                       for key in ['descr', 'room', 'place', 'note']): # ['text', 'bezeichnung', 'ort', 'notizen']):
                    #entries += self._parseBookings(booking)
                    entries.append(booking)
                    if len(entries) >= 10:
                        toomany = True
                        break
            # entries = self.sortBookings(entries)
            toomanymsg = "Zu viele Ergebnisse, zeige die ersten 10."
            if not error:
                redis.set(key, pickle.dumps((toomanymsg if toomany else None, entries)), ex=12*3600)
            if toomany:
                error = error + toomanymsg if error else toomanymsg
        else:
            error, entries = entry_data
        return error, entries
Ejemplo n.º 3
0
def parseGeburtstage(login_data):
    key = get_cache_key(login_data, 'birthdays', useDate=True)
    msg = loadCache(key)
    if not msg:
        (error, data) = getAjaxResponse('home',
                                        'getBlockData',
                                        login_data=login_data,
                                        timeout=1800)

        if not data:
            print(error)
            return error
        else:
            try:
                html = data['blocks']['birthday']['html']
                # soup = BeautifulSoup(html, 'html.parser')
                # comments = soup.find_all(string=lambda text:isinstance(text, Comment))
                # [comment.extract() for comment in comments]
                # row = str(soup.table.tr)
                split = re.split(
                    "<td><a (data-person-id='[^']+')[^>]+><img[^>]*></a><td[^>]*><a class='tooltip-person'[^>]*>([^<]+)</a><td[^>]*>([0-9]+)</?[^>]+>",
                    html)
                msg = ""
                p_id = None
                for line in split:
                    if not line:
                        continue
                    m = re.search('<th colspan="3">([^<]+)<tr>', line)
                    m2 = re.match('data-person-id=\'([^\']+)\'', line)
                    if m:
                        msg += "<i>%s</i>\n" % m.group(1)
                    elif m2:
                        p_id = m2.group(1)
                        msg += getPersonLink(login_data, p_id)
                    elif re.match('[0-9]+', line):
                        if p_id:
                            msg += f"{line} /P{p_id}\n"
                        else:
                            msg += f"{line}\n"
                        p_id = None
                    elif re.match('[^<>]+', line):
                        msg += "%s</a>: " % line
                if error:
                    msg += f"\n<i>{error}</i>"
                else:
                    redis.set(key, pickle.dumps(msg), ex=3600 * 24)
            except Exception as e:
                return "Error while parsing: %s" % e
    return msg
Ejemplo n.º 4
0
    def _getCategories(self):
        key = get_cache_key(self.login_data, self.cache_key + 'master_data')
        cat_data = self._loadCache(key)
        if not cat_data:
            (error, data) = super()._ajaxResponse(func='getMasterData',
                                                  timeout=None)
            if not data:
                return error, data
            categories = data['category']
            cat_params = {}
            ctr = 0
            for c in categories:
                cat_params[f'category_ids[{ctr}]'] = c
                ctr += 1
            cat_data = categories, cat_params
            redis.set(key, pickle.dumps(cat_data), ex=7 * 24 * 3600)

        return cat_data
Ejemplo n.º 5
0
 def getAllBookings(self):
     key = get_cache_key(self.login_data, self.cache_key, useDate=True)
     entries = self._loadCache(key)
     if not entries:
         entries = []
         (error, data) = self._ajaxResponse()
         if not data:
             return error, entries
         for b in data:
             booking = data[b]
             if int(booking['status_id']) == 99:
                 continue
             rules, start, duration = self._parseBooking(booking)
             entries.append((booking, rules, start, duration))
         if not error:
             redis.set(key, pickle.dumps(entries), ex=12 * 3600)
         return error, entries
     return None, entries
Ejemplo n.º 6
0
    def getAllBookings(self):
        self.categories, cat_params = self._getCategories()

        key = get_cache_key(self.login_data, self.cache_key, useDate=True)
        entries = self._loadCache(key)
        if not entries:
            (error, data) = self._ajaxResponse(**cat_params)

            if not data:
                return error, data
            entries = []
            for c in data:
                category = data[c]
                for b in category:
                    booking = category[b]
                    rules, start, duration = self._parseBooking(booking)
                    entries.append((booking, rules, start, duration))
            if not error:
                redis.set(key, pickle.dumps(entries), ex=3600 * 12)
            return error, entries
        return None, entries
Ejemplo n.º 7
0
def download_file(login_data, url):
    key = get_cache_key(login_data, 'song:download', url)
    res = loadCache(key)
    if not res:
        (success, res) = login(login_data)
        if not success:
            return False, res
        try:
            # path = 'temp_file'
            logger.info(f"Donwloading {url}")
            r = requests.get(url, cookies=res, stream=True, timeout=20)
            if r.status_code == 200:
                res = {}

                if url.endswith('.txt') or url.endswith('.sng'):
                    if url.endswith('.txt'):
                        msg = [r.text]
                    else:  # sng
                        msg = [r.text]

                    res.update({
                        'type': 'msg',
                        'msg': msg,
                    })
                else:
                    bio = BytesIO(r.content)
                    res.update({
                        'type': 'file',
                        'file': bio,
                    })
            else:
                logger.warning(r)
                res['msg'] = r.text[:50]
                return False, res
        except Exception as e:
            logger.warning(e)
            res['msg'] = e
            return False, res
        redis.set(key, pickle.dumps(res))
    return True, res
Ejemplo n.º 8
0
def calendar(context, update, login_data, mode_key, text):
    try:
        if text in RAUM_ZEIT_MARKUP:
            if text == 'Heute':
                msgs = parseCalendarByTime(login_data, dayRange=0)
            elif text == 'Nächste 7 Tage':
                msgs = parseCalendarByTime(login_data, dayRange=7)
            elif text == 'Morgen':
                msgs = parseCalendarByTime(login_data, dayRange=0, dayOffset=1)
            for msg in msgs:
                send_message(context, update, msg, telegram.ParseMode.HTML,
                             mainMarkup())
        elif text == 'Suche':
            redis.set(mode_key, 'calendar_search')
            send_message(
                context, update,
                "Gib den Namen des Kalendereintrags (oder einen Teil davon ein):",
                None, EMPTY_MARKUP)
    except Exception as e:
        eMsg = ''.join(traceback.format_exception(type(e), e, e.__traceback__))
        msg = f"Failed!\nException: {eMsg}"
        logger.error(msg)
        send_message(context, update, msg, None, mainMarkup())
Ejemplo n.º 9
0
def getAjaxResponse(*args,
                    login_data,
                    isAjax=True,
                    timeout=3600,
                    additionalCacheKey=None,
                    **params):
    key = get_cache_key(login_data,
                        *args,
                        additionalCacheKey=additionalCacheKey,
                        **params)
    resp_str = redis.get(key)
    resp = json.loads(resp_str.decode('utf-8')) if resp_str else None
    if not resp or not timeout:
        relogin = False
        while True:

            (success, cookies) = login(login_data, updateCache=relogin)
            if not success:
                return cookies, None
            try:
                if isAjax:
                    resp = cc_func(*args,
                                   cookies=cookies,
                                   login_data=login_data,
                                   params=params)
                else:
                    resp = cc_api(*args,
                                  cookies=cookies,
                                  login_data=login_data,
                                  params=params)
            except Exception as e:
                resp_str = redis.get(key + "_latest")
                if resp_str:
                    resp_time = float(redis.get(key + "_latest:time"))
                    resp = json.loads(resp_str.decode('utf-8'))
                    msg = f'Server unavailable. Data is from {datetime.fromtimestamp(resp_time)}'
                    return msg, resp['data']
                else:
                    return "Error: Server unavailable!", None
            if resp['status'] == 'success':
                break
            elif relogin:
                break
            else:  # retry
                relogin = True
        if resp['status'] != 'success' or 'data' not in resp:
            if 'message' in resp:
                return resp['message'], None
            else:
                return str(resp), None
        else:
            resp_str = json.dumps(resp)
            redis.set(key, resp_str, ex=timeout)
            redis.set(key + "_latest", resp_str)
            redis.set(key + "_latest:time", datetime.now().timestamp())
    return None, resp['data']
Ejemplo n.º 10
0
def findGroup(login_data, name):
    key = get_cache_key(login_data, 'group:find', name)
    res = loadCache(key)
    error = None
    if not res or True:
        (error, data) = getAjaxResponse("db",
                                        "getMasterData",
                                        login_data=login_data,
                                        timeout=None)
        if not data:  # or 'groups':
            return {
                'success': False,
                'msg': error,
            }
        res = {
            'success': False,
            'msg': [f"No group found with the name {name} :("],
        }
        matches = []
        groups = data['groups']
        if re.match('/G([0-9]+)', name):
            g_id = name[2:]
            if g_id in groups:
                matches.append(groups[g_id])
        else:
            name = name.lower()
            for g in data['groups']:
                group = groups[g]
                bez = group['bezeichnung']
                if name in bez.lower():
                    matches.append(group)
        t = []
        if len(matches) == 0:
            pass
        elif len(matches) < 10:
            (error, persons) = getAjaxResponse("db",
                                               "getAllPersonData",
                                               login_data=login_data,
                                               timeout=24 * 3600)

            if not persons:
                return {'success': False, 'msg': error}
            for g in matches:
                g_id = g['id']
                if t:
                    t[-1] += '\n\n'
                url = urljoin(login_data['url'],
                              f'?q=churchdb#GroupView/searchEntry:#{g_id}')
                if len(matches) == 1:
                    #t.append(f'<a href="{url}">{g["bezeichnung"]}</a>\n')
                    t += printGroup(login_data=login_data,
                                    group=g,
                                    persons=persons,
                                    masterData=data,
                                    list=False,
                                    onlyName=False)
                    img_id = g['groupimage_id']
                    if img_id:
                        try:
                            img_data = getAjaxResponse(
                                f'files/{img_id}/metadata',
                                login_data=login_data,
                                isAjax=False,
                                timeout=24 * 3600)
                            res['photo'] = urljoin(login_data['url'],
                                                   img_data[1]['url'])
                        except:
                            pass
                else:
                    t.append(
                        f'<a href="{url}">{g["bezeichnung"]}</a> /G{g_id}\n')

            res.update({'msg': t, 'success': True})

        elif len(matches) <= 50:
            for g in matches:
                g_id = g['id']
                url = urljoin(login_data['url'],
                              f'?q=churchdb#GroupView/searchEntry:#{g_id}')
                t.append(f'<a href="{url}">{g["bezeichnung"]}</a> /G{g_id}\n')
                res.update({'msg': t, 'success': True})
        else:
            res.update({
                'msg': ['Zu viele Gruppen gefunden! Bitte Suche verfeinern'],
                'success':
                False
            })

    if error:
        res['msg'].append(f'\n<i>{error}</i>')
    else:
        redis.set(key, pickle.dumps(res), ex=7 * 24 * 3600)
    return res
Ejemplo n.º 11
0
def message(update, context):
    bot = context.bot
    user_id = update.message.from_user.id
    login_key = get_user_login_key(user_id)
    login_data_str = redis.get(login_key)
    text = update.message.text

    if login_data_str:
        login_data = json.loads(login_data_str)
    else:
        # not logged in, check if login data sent and don't continue afterwards
        check_login(context, update, text)
        return

    bot.send_chat_action(chat_id=update.message.chat_id,
                         action=telegram.ChatAction.TYPING)

    mode = redis.get(mode_key(update))
    if mode:
        mode = mode.decode('UTF-8')
        # print(f"In mode {mode}")
        redis.delete(mode_key(update))
        if mode == 'calendar':
            calendar(context, update, login_data, mode_key(update), text)
        elif mode == 'rooms':
            if text in RAUM_ZEIT_MARKUP:
                cur_time_markup = [[f'{text}: {r}'] for r in room_markup]
                send_message(context, update, "Welche Räume?",
                             telegram.ParseMode.HTML,
                             ReplyKeyboardMarkup(cur_time_markup))
            elif text in RAUM_EXTENDED_MARKUP:
                redis.set(mode_key(update), 'room_search')
                send_message(
                    context, update,
                    "Gib den Namen der Raumbelegung (oder einen Teil ein):",
                    None, EMPTY_MARKUP)
        elif mode == 'song':
            (success, res) = songs.search(login_data, text)
            if success:
                for msg in res:
                    send_message(context, update, msg, telegram.ParseMode.HTML,
                                 mainMarkup())
            else:
                send_message(context, update, res, None, mainMarkup())
        elif mode == 'person':
            success = person(context, update, text, mainMarkup(), login_data)
            if success is False:
                redis.set(mode_key(update), mode)
        elif mode == 'group':
            group(context, update, text, mainMarkup(), login_data=login_data)
        elif mode == 'room_search':
            msgs = parseRaeumeByText(login_data, text)
            for msg in msgs:
                send_message(context, update, msg, telegram.ParseMode.HTML,
                             mainMarkup())
        elif mode == 'calendar_search':
            try:
                msgs = parseCalendarByText(login_data, text)
                for msg in msgs:
                    send_message(context, update, msg, telegram.ParseMode.HTML,
                                 mainMarkup())
            except Exception as e:
                eMsg = ''.join(
                    traceback.format_exception(type(e), e, e.__traceback__))
                msg = f"Failed!\nException: {eMsg}"
                logger.error(msg)
                send_message(context, update, msg, None, mainMarkup())
        elif mode == 'signup':
            parse_signup(context, update, login_data, mainMarkup(), text)

    else:  # no special mode
        m1 = re.match('([A-Za-z0-9äöü ]+): ([A-Za-zäöü]+)', text)
        m2 = re.match('/dl_([0-9]+)_([0-9]+)', text)
        mPerson = re.match('/P([0-9]+)', text)
        mPersonContact = re.match('/C([0-9]+)', text)
        mGroup = re.match('/G([0-9]+)', text)
        mEvent = re.match('/E([0-9]+)', text)
        mQR = re.match('/Q([0-9]+)', text)
        mAgenda = re.match('/A([0-9]+)', text)
        mSong1 = re.match('/S([0-9]+)$', text)
        mSong2 = re.match('/S([0-9]+)_([0-9]+)', text)
        if m1:
            zeit = m1.group(1)
            room = m1.group(2)
        if m1 and zeit in RAUM_ZEIT_MARKUP and room in room_markup:
            try:
                if zeit == 'Heute':
                    msgs = parseRaeumeByTime(login_data, room, dayRange=0)
                elif zeit == 'Nächste 7 Tage':
                    msgs = parseRaeumeByTime(login_data, room, dayRange=7)
                elif zeit == 'Morgen':
                    msgs = parseRaeumeByTime(login_data,
                                             room,
                                             dayRange=0,
                                             dayOffset=1)
                for msg in msgs:
                    send_message(context, update, msg, telegram.ParseMode.HTML,
                                 mainMarkup())
            except Exception as e:
                eMsg = ''.join(
                    traceback.format_exception(type(e), e, e.__traceback__))
                msg = f"Failed!\nException: {eMsg}"
                logger.error(msg)
                send_message(context, update, msg, None, mainMarkup())
        elif m2:
            song_id = m2.group(1)
            file_id = m2.group(2)
            song(context, update, file_id, login_data, mainMarkup(), song_id)
        elif mPerson:
            person(context, update, text, mainMarkup(), login_data)
        elif mPersonContact:
            person(context,
                   update,
                   text,
                   mainMarkup(),
                   login_data,
                   contact=True)
        elif mGroup:
            group(context, update, text, mainMarkup(), login_data=login_data)
        elif mEvent:
            g_id = mEvent.group(1)
            print_event(context, update, g_id, login_data, mainMarkup())
        elif mQR:
            g_id = mQR.group(1)
            qr = groups.get_qrcode(login_data, g_id)
            if qr:
                try:
                    bot.send_photo(update.effective_chat.id,
                                   photo=qr,
                                   caption="QR-Code fürs Check-In",
                                   parse_mode=telegram.ParseMode.HTML,
                                   reply_markup=mainMarkup(),
                                   timeout=30)
                except Exception as e:
                    send_message(
                        context, update,
                        "<i>Konnte QR-Code nicht senden :(</i>\n" + str(e),
                        telegram.ParseMode.HTML, mainMarkup())
            else:
                send_message(context, update,
                             "<i>Konnte QR-Code nicht abrufen :(</i>\n",
                             telegram.ParseMode.HTML, mainMarkup())
        elif mSong1 or mSong2:
            try:
                arrId = None
                if mSong1:
                    songid = mSong1.group(1)
                else:
                    songid = mSong2.group(1)
                    arrId = mSong2.group(2)
                (success, msg) = songs.byID(login_data,
                                            song_id=songid,
                                            arrangement_id=arrId)
                send_message(context, update, msg, telegram.ParseMode.HTML,
                             mainMarkup())

            except Exception as e:
                eMsg = ''.join(
                    traceback.format_exception(type(e), e, e.__traceback__))
                msg = f"Failed!\nException: {eMsg}"
                logger.error(msg)
                send_message(context, update, msg, None, mainMarkup())
        elif mAgenda:
            a_id = mAgenda.group(1)
            agenda(context, update, login_data, a_id, mainMarkup())

        elif text == MARKUP_ROOMS:
            redis.set(mode_key(update), 'rooms')
            send_message(
                context, update, "Welcher Zeitraum?", telegram.ParseMode.HTML,
                ReplyKeyboardMarkup([RAUM_ZEIT_MARKUP, RAUM_EXTENDED_MARKUP]))
        elif text == MARKUP_CALENDAR:
            redis.set(mode_key(update), 'calendar')
            send_message(
                context, update, "Welcher Zeitraum?", telegram.ParseMode.HTML,
                ReplyKeyboardMarkup([RAUM_ZEIT_MARKUP, RAUM_EXTENDED_MARKUP]))
        elif text == MARKUP_BIRTHDAYS:
            try:
                msg = parseGeburtstage(login_data=login_data)
                send_message(context, update, msg, telegram.ParseMode.HTML,
                             mainMarkup())
            except Exception as e:
                msg = f"Failed!\nException: {e}"
                logger.error(msg)
                send_message(context, update, msg, None, mainMarkup())
        elif text == MARKUP_SONGS:
            redis.set(mode_key(update), 'song')
            send_message(context, update,
                         "Gib den Namen/Author (oder einen Teil davon ein):",
                         None, EMPTY_MARKUP)
        elif text == MARKUP_PEOPLE:
            redis.set(mode_key(update), 'person')
            send_message(
                context, update,
                "Gib den Namen (oder einen Teil ein) oder eine Telefonnumer ein:",
                None, EMPTY_MARKUP)
        elif text == MARKUP_GROUPS:
            redis.set(mode_key(update), 'group')
            send_message(context, update,
                         "Gib den Namen (oder einen Teil ein):", None,
                         EMPTY_MARKUP)
        elif text == MARKUP_EVENTS:
            list_events(context, login_data, mainMarkup(), update)
        else:
            send_message(
                context, update,
                "Unbekannter Befehl, du kannst einen der Buttons unten nutzen",
                None, mainMarkup())
Ejemplo n.º 12
0
def login(login_data=None, updateCache=False, login_token=False):
    key = get_cache_key(login_data, 'login_cookies', usePerson=True)
    cookies_pickle = redis.get(key)
    cookies = pickle.loads(cookies_pickle) if cookies_pickle else None

    # Check if session cookie still valid
    if cookies and not updateCache:
        data = cc_func('resource',
                       'pollForNews',
                       cookies,
                       login_data=login_data)
        if not data or 'data' not in data:
            cookies = None
        else:
            data = data['data']
            userid = data['userid']
            if not userid or userid == -1:
                cookies = None

    if not cookies or updateCache:  # need to login using permanent login key
        logger.info(f"Cookie is invalid for {login_data['personid']}")
        key_token = get_cache_key(login_data, 'login_token', usePerson=True)
        login_key_pickle = redis.get(key_token)
        login_key = pickle.loads(
            login_key_pickle) if login_key_pickle else None
        resp1 = requests.head(login_data['url'])
        cookies = resp1.cookies
        if not login_key or login_token:  # login key not valid, try login token
            logger.info(
                f"Getting new login token for {login_data['personid']}")
            login_url = urljoin(
                login_data['url'],
                f"?q=profile&loginstr={login_data['token']}&id={login_data['personid']}"
            )
            resp = requests.get(login_url, cookies=cookies)

            if 'Der verwendete Login-Link ist nicht mehr aktuell und kann deshalb nicht mehr verwendet werden.' in resp.text:
                redis.delete(get_user_login_key(login_data['telegramid']))
                return False, 'Login fehlgeschlagen, versuchs es mit einem neuen Link.'
            else:  # get new login key & cookies using login token
                data = cc_api(f'persons/{login_data["personid"]}/logintoken',
                              cookies=cookies,
                              login_data=login_data,
                              returnJson=True)
                if data['status'] == 'success':
                    inner_data = data['data']
                    # cookies = resp.cookies.get_dict()
                    redis.set(key_token, pickle.dumps(inner_data['data']))
                    redis.set(key, pickle.dumps(cookies.get_dict()))
                else:
                    return False, 'Login fehlgeschlagen, bitte log dich neu ein.'
        else:  # get new cookies using login key
            try:
                token_url = f'whoami?login_token={login_key}&user_id={login_data["personid"]}'
                data = cc_api(token_url,
                              cookies,
                              login_data=login_data,
                              returnJson=True)
                if data['status'] == 'success':
                    logger.info(data)
                    redis.set(key, pickle.dumps(cookies.get_dict()))
                else:
                    logger.warning(data)
                    return False, f'Login fehlgeschlagen, bitte log dich neu ein.'
            except Exception as e:
                return False, f'Could not renew token:\n{str(e)}'
            # redis.delete(get_user_login_key(login_data['telegramid']))
            # return False, 'Login fehlgeschlagen, versuchs es mit einem neuen Link.'

    return True, cookies