def sendMessage(userKey: ndb.Key): # gevent somehow messes with the ndb context even though it's the same thread with cls.ndbClient.context(): # Create message payload payload = { "chat_id": str(userKey.id()), "text": text, "parse_mode": "HTML", "reply_markup": TelegramMarkup.TemperatureKeyboard, } user: User = userKey.get() try: resp = telegramApi.sendMessage(payload) # User statuses have to be updated right after sending or user may hit an invalid state # when they report their temperature if resp["ok"]: user.temp = User.TEMP_NONE user.status = UserState.TEMP_REPORT user.put() return SUCCESS else: if (resp["description"] == "Forbidden: bot was blocked by the user"): user.reset() user.blocked = True user.put() return BLOCKED else: return FAILED logger.error(resp["description"]) except Exception as e: logger.error(e) return FAILED
def _activitypub_targets(self): """ Returns: list of (Response, string inbox URL) """ # if there's in-reply-to, like-of, or repost-of, they're the targets. # otherwise, it's all followers' inboxes. targets = self._targets() if not targets: # interpret this as a Create or Update, deliver it to followers inboxes = [] for follower in Follower.query().filter( Follower.key > Key('Follower', self.source_domain + ' '), Follower.key < Key( 'Follower', self.source_domain + chr(ord(' ') + 1))): if follower.status != 'inactive' and follower.last_follow: actor = json_loads(follower.last_follow).get('actor') if actor and isinstance(actor, dict): inboxes.append( actor.get('endpoints', {}).get('sharedInbox') or actor.get('publicInbox') or actor.get('inbox')) return [(Response.get_or_create(source=self.source_url, target=inbox, direction='out', protocol='activitypub', source_mf2=json_dumps( self.source_mf2)), inbox) for inbox in inboxes if inbox] resps_and_inbox_urls = [] for target in targets: # fetch target page as AS2 object try: self.target_resp = common.get_as2(target) except (requests.HTTPError, exc.HTTPBadGateway) as e: self.target_resp = getattr(e, 'response', None) if self.target_resp and self.target_resp.status_code // 100 == 2: content_type = common.content_type(self.target_resp) or '' if content_type.startswith('text/html'): # TODO: pass e.response to try_salmon()'s target_resp continue # give up raise target_url = self.target_resp.url or target resp = Response.get_or_create(source=self.source_url, target=target_url, direction='out', protocol='activitypub', source_mf2=json_dumps( self.source_mf2)) # find target's inbox target_obj = self.target_resp.json() resp.target_as2 = json_dumps(target_obj) inbox_url = target_obj.get('inbox') if not inbox_url: # TODO: test actor/attributedTo and not, with/without inbox actor = (util.get_first(target_obj, 'actor') or util.get_first(target_obj, 'attributedTo')) if isinstance(actor, dict): inbox_url = actor.get('inbox') actor = actor.get('url') or actor.get('id') if not inbox_url and not actor: self.error( 'Target object has no actor or attributedTo with URL or id.' ) elif not isinstance(actor, str): self.error( 'Target actor or attributedTo has unexpected url or id object: %r' % actor) if not inbox_url: # fetch actor as AS object actor = common.get_as2(actor).json() inbox_url = actor.get('inbox') if not inbox_url: # TODO: probably need a way to save errors like this so that we can # return them if ostatus fails too. # self.error('Target actor has no inbox') continue inbox_url = urllib.parse.urljoin(target_url, inbox_url) resps_and_inbox_urls.append((resp, inbox_url)) return resps_and_inbox_urls
def delete_book(book_id): key = Key(Book, book_id) if key.get() is None: raise BookNotFound() key.delete()
def delete_member(member_id): member = Key(Member, member_id) if member.get() is None: raise MemberNotFound() member.key.delete()