diff options
author | John Smith <mrdoctorwho@helldev.net> | 2019-05-14 07:25:18 +0300 |
---|---|---|
committer | John Smith <mrdoctorwho@helldev.net> | 2019-05-14 07:25:18 +0300 |
commit | d687b7b62278580afdd5b881ed71fe7c59d03bb2 (patch) | |
tree | b83a9c0db37f52f76cf293a19ac89e5ffe415e60 | |
parent | 42bea0f685fc83b9e9b172a4cd301b0a297a6000 (diff) |
Bring API v5 back. Add timezone support, use intellectual date format
-rw-r--r-- | extensions/attachments.py | 6 | ||||
-rw-r--r-- | extensions/avatar_hash.py | 2 | ||||
-rw-r--r-- | extensions/forwarded_messages.py | 45 | ||||
-rw-r--r-- | extensions/groupchats.py | 13 | ||||
-rw-r--r-- | gateway.py | 81 | ||||
-rw-r--r-- | library/longpoll.py | 2 | ||||
-rw-r--r-- | library/rostermanager.py | 4 | ||||
-rw-r--r-- | library/utils.py | 4 | ||||
-rw-r--r-- | library/vkapi.py | 4 | ||||
-rw-r--r-- | modules/mod_iq_disco.py | 2 |
10 files changed, 102 insertions, 61 deletions
diff --git a/extensions/attachments.py b/extensions/attachments.py index 1aca767..3b65376 100644 --- a/extensions/attachments.py +++ b/extensions/attachments.py @@ -10,7 +10,7 @@ VK_AUDIO_SEARCH_LINK = "https://vk.com/search?c[q]=%s&c[section]=audio" WALL_LINK = "https://vk.com/wall%(to_id)s_%(id)s" WALL_COMMENT_LINK = "https://vk.com/wall%(owner_id)s_%(post_id)s?w=wall%(owner_id)s3_%(post_id)s" -PHOTO_SIZES = ("src_xxxbig", "src_xxbig", "src_xbig", "src_big", "src", "url", "src_small") +PHOTO_SIZES = ("photo_2560", "photo_1280", "photo_807", "photo_604", "photo_130", "photo_75") STICKER_SIZES = ("photo_256", "photo_128", "photo_64") ATTACHMENT_REGEX = re.compile(r"^(?P<type>Photo|Document|Sticker)\:\s(?P<name>“.+?”\s—\s)?(?P<url>http[s]?:\/\/[^\s]+)$", re.UNICODE) @@ -87,7 +87,7 @@ def parseAttachments(self, msg, spacer=""): elif type == "wall_reply": # TODO: What if it's a community? from_id will be negative. # TODO: Remove "[idxxx|Name]," from the text or make it a link if XHTML is allowed - current["name"] = self.vk.getName(current["uid"]) + current["name"] = self.vk.getName(current["from_id"]) current["text"] = uhtml(compile_eol.sub("\n" + spacer, current["text"])) current["url"] = WALL_COMMENT_LINK % current @@ -105,7 +105,7 @@ def parseAttachments(self, msg, spacer=""): current["desc"] += "%(views)d views" % current current["time"] = "%d:%d" % (current["duration"] // 60, current["duration"] % 60) - body += "Video: %(title)s (%(desc)s, %(time)s min) — https://vk.com/video%(owner_id)s_%(vid)s" % current + body += "Video: %(title)s (%(desc)s, %(time)s min) — https://vk.com/video%(owner_id)s_%(id)s" % current elif type in SIMPLE_ATTACHMENTS: body += SIMPLE_ATTACHMENTS[type] % current diff --git a/extensions/avatar_hash.py b/extensions/avatar_hash.py index 3e62946..2f2a7e1 100644 --- a/extensions/avatar_hash.py +++ b/extensions/avatar_hash.py @@ -42,7 +42,7 @@ class AvatarHash(object): return data def sendPhotoRequest(self, user, uids): - data = user.vk.method("execute.getPhotos", + data = user.vk.method("execute.getPhotos_new", {"users": self.join(uids), "size": PhotoSize}) or [] return data diff --git a/extensions/forwarded_messages.py b/extensions/forwarded_messages.py index 98c7095..f052ec7 100644 --- a/extensions/forwarded_messages.py +++ b/extensions/forwarded_messages.py @@ -2,7 +2,7 @@ # This file is a part of VK4XMPP transport # © simpleApps, 2013 — 2015. -from datetime import datetime +from datetime import datetime, timedelta, tzinfo, date if not require("attachments"): raise AssertionError("'forwardMessages' requires 'attachments'") @@ -10,27 +10,58 @@ if not require("attachments"): BASE_SPACER = chr(32) + unichr(183) + chr(32) +class TimezoneOffset(tzinfo): + + def __init__(self, offset=0): + self.offset = timedelta(hours=offset) + + def utcoffset(self, dt): + return self.offset + + def tzname(self, dt): + return None + + def dst(self, dt): + return timedelta(0) + + def parseForwardedMessages(self, msg, depth=0): body = "" - if msg.has_key("fwd_messages"): + if "fwd_messages" in msg: spacer = BASE_SPACER * depth body = "\n" + spacer body += _("Forwarded messages:") fwd_messages = sorted(msg["fwd_messages"], sortMsg) for fwd in fwd_messages: - source = fwd["uid"] - date = fwd["date"] + source = fwd["user_id"] fwdBody = escape("", uhtml(compile_eol.sub("\n" + spacer + BASE_SPACER, fwd["body"]))) - date = datetime.fromtimestamp(date).strftime("%d.%m.%Y %H:%M:%S") + date = getUserDate(self, fwd["date"]) name = self.vk.getName(source) - body += "\n%s[%s] <%s> %s" % (spacer + BASE_SPACER, date, name, fwdBody) + body += "\n%s[%s] %s> %s" % (spacer + BASE_SPACER, date, name, fwdBody) body += parseAttachments(self, fwd, spacer + (BASE_SPACER * 2)) if depth < MAXIMUM_FORWARD_DEPTH: body += parseForwardedMessages(self, fwd, (depth + 1)) return body + +def getUserDate(user, timestamp): + timezone = user.vk.getUserPreferences()[1] + offset = TimezoneOffset(timezone) + _date = datetime.fromtimestamp(timestamp, offset) + today = datetime.fromtimestamp(time.time(), offset) + _format = "" + delta = today - _date + if delta.days > 0: + _format += "%d.%m" + if delta.days > 300: + _format += ".%Y" + if _format: + _format += " " + _format += "%H.%M:%S" + return _date.strftime(_format) + + if not isdef("MAXIMUM_FORWARD_DEPTH"): MAXIMUM_FORWARD_DEPTH = 29 registerHandler("msg01", parseForwardedMessages) - diff --git a/extensions/groupchats.py b/extensions/groupchats.py index 04cbaf8..ed6632f 100644 --- a/extensions/groupchats.py +++ b/extensions/groupchats.py @@ -144,8 +144,10 @@ def handleOutgoingChatMessage(user, vkChat): """ Handles outging VK messages and sends them to XMPP """ + # peer_id for newer APIs + chatID = vkChat.get("chat_id", 0) - if "chat_id" in vkChat: + if chatID: # check if the groupchats support enabled in user's settings if not user.settings.groupchats: return None @@ -153,7 +155,6 @@ def handleOutgoingChatMessage(user, vkChat): if not hasattr(user, "chats"): user.chats = {} - chatID = vkChat["chat_id"] chatJID = "%s_chat#%s@%s" % (user.vk.userID, chatID, ConferenceServer) chat = createChat(user, chatJID) if not chat.initialized: @@ -292,8 +293,8 @@ class Chat(object): # how would it get in there? if TransportID in everyone: everyone.remove(TransportID) - if userObject.vk.getUserID() in everyone: - everyone.remove(userObject.vk.getUserID()) + if userObject.vk.getUserPreferences()[0] in everyone: + everyone.remove(userObject.vk.getUserPreferences()[0]) for user in everyone: jid = vk2xmpp(user) @@ -368,7 +369,7 @@ class Chat(object): body += parseAttachments(user, vkChat) body += parseForwardedMessages(user, vkChat) if body: - chatMessage(self.jid, body, vk2xmpp(vkChat["uid"]), None) + chatMessage(self.jid, body, vk2xmpp(vkChat["from_id"]), None) else: source = "unknown" userObject = self.getUserObject(self.jid) @@ -448,7 +449,7 @@ class Chat(object): def getUserByID(id): for jid, user in Users.iteritems(): if hasattr(user, "vk"): - if user.vk.getUserID() == id: + if user.vk.getUserPreferences()[0] == id: return user return None @@ -228,7 +228,7 @@ badChars = [x for x in xrange(32) if x not in (9, 10, 13)] + [57003, 65535] escape = re.compile("|".join(unichr(x) for x in badChars), re.IGNORECASE | re.UNICODE | re.DOTALL).sub -sortMsg = lambda first, second: first.get("mid", 0) - second.get("mid", 0) +sortMsg = lambda first, second: first.get("id", 0) - second.get("id", 0) require = lambda name: os.path.exists("extensions/%s.py" % name) isdef = lambda var: var in globals() findUserInDB = lambda source: runDatabaseQuery("select * from users where jid=?", (source,), many=False) @@ -261,14 +261,15 @@ class VK(object): self.engine = None self.cache = {} self.permissions = 0 + self.timezone = 0 logger.debug("VK initialized (jid: %s)", source) def __str__(self): - return ("user id: %s; online: %s; token: %s" % - (self.userID, self.online, self.token)) + return ("user id: %s; timezone: %s; online: %s; token: %s" % + (self.userID, self.timezone, self.online, self.token)) def init(self): - self.getUserID() + self.getUserPreferences() self.getPermissions() getToken = lambda self: self.engine.token @@ -442,9 +443,10 @@ class VK(object): """ fields = fields or self.friends_fields raw = self.method("friends.get", {"fields": str.join(",", fields)}) or {} + raw = raw.get("items", {}) friends = {} for friend in raw: - uid = friend["uid"] + uid = friend["id"] online = friend["online"] name = self.formatName(friend) friends[uid] = {"name": name, "online": online, "lists": friend.get("lists")} @@ -452,16 +454,6 @@ class VK(object): friends[uid][key] = friend.get(key) return friends - def getLists(self): - """ - Receive the list of the user friends' groups - Returns: - a list of user friends groups - """ - if not self.lists: - self.lists = self.method("friends.getLists") - return self.lists - @staticmethod def getPeerIds(conversations, source=None): """ @@ -507,15 +499,15 @@ class VK(object): "start_message_id": mid, "count": count}) if response: - for message in response: + messages.extend(response[0].get("items", [])) # skipping count-only reponses - if len(message) > 1: - if isinstance(message, list): - first = message[0] - # removing the unread count - if isinstance(first, (int, long)): - message.remove(first) - messages.extend(message) + # if len(message) > 1: + # if isinstance(message, list): + # first = message[0] + # # removing the unread count + # if isinstance(first, (int, long)): + # message.remove(first) + # messages.extend(message) else: # not sure if that's okay # VK is totally unpredictable now @@ -543,15 +535,19 @@ class VK(object): return self.getMessagesBulk(peers, count=count, mid=mid) # TODO: put this in the DB - def getUserID(self): + def getUserPreferences(self): """ - Receives the user id + Receives the user's id and timezone Returns: The current user id """ - if not self.userID: - self.userID = self.method("execute.getUserID") - return self.userID + if not self.userID or not self.timezone: + data = self.method("users.get", {"fields": "timezone"}) + if data: + data = data.pop() + self.timezone = data.get("timezone") + self.userID = data.get("id") + return (self.userID, self.timezone) def getPermissions(self): """ @@ -563,6 +559,16 @@ class VK(object): self.permissions = self.method("account.getAppPermissions") return self.permissions + def getLists(self): + """ + Receive the list of the user friends' groups + Returns: + a list of user friends groups + """ + if not self.lists: + self.lists = self.method("friends.getLists") + return self.lists + @utils.cache def getGroupData(self, gid, fields=None): """ @@ -746,7 +752,7 @@ class User(object): self.sendInitPresence() if resource: self.resources.add(resource) - utils.runThread(self.vk.getUserID) + utils.runThread(self.vk.getUserPreferences) if first: self.sendMessages(True, filter_="unread") else: @@ -820,12 +826,13 @@ class User(object): # check if message wasn't sent by our user if not message["out"]: Stats["msgin"] += 1 - frm = message["uid"] - mid = message["mid"] + frm = message["user_id"] + mid = message["id"] if frm in self.typing: del self.typing[frm] fromjid = vk2xmpp(frm) - body = uhtml(message["body"]) + body = message["body"] + body = uhtml(body) iter = Handlers["msg01"].__iter__() for func in iter: try: @@ -846,11 +853,11 @@ class User(object): self.lastMsgByUser[frm] = mid sendMessage(self.source, fromjid, escape("", body), date, mid=mid) if messages: - newLastMsgID = messages[-1]["mid"] - if self.lastMsgID < newLastMsgID: - self.lastMsgID = newLastMsgID - runDatabaseQuery("update users set lastMsgID=? where jid=?", - (newLastMsgID, self.source), True) + newLastMsgID = messages[-1]["id"] + # if self.lastMsgID < newLastMsgID: + self.lastMsgID = newLastMsgID + runDatabaseQuery("update users set lastMsgID=? where jid=?", + (newLastMsgID, self.source), True) def updateTypingUsers(self, cTime): """ diff --git a/library/longpoll.py b/library/longpoll.py index fb3e814..51d5de8 100644 --- a/library/longpoll.py +++ b/library/longpoll.py @@ -112,7 +112,7 @@ def processPollResult(user, data): chat = (uid > MIN_CHAT_UID) # a groupchat always has uid > 2000000000 if not out: if not attachments and not chat: - message = [{"out": 0, "uid": uid, "mid": mid, "date": date, "body": body}] + message = [{"out": 0, "user_id": uid, "id": mid, "date": date, "body": body}] utils.runThread(user.sendMessages, (False, message, mid - 1, uid), "sendMessages-%s" % user.source) elif typ == TYPE_MSG_READ_OUT: diff --git a/library/rostermanager.py b/library/rostermanager.py index 896f204..6a52d89 100644 --- a/library/rostermanager.py +++ b/library/rostermanager.py @@ -6,7 +6,7 @@ from __main__ import * from __main__ import _ # Finds list name by id -findListByID = lambda id, list: [key for key in list if key["lid"] == id] +findListByID = lambda id, list: [key for key in list if key["id"] == id] RosterSemaphore = threading.Semaphore() @@ -35,7 +35,7 @@ class Roster: for uid, value in dist.iteritems(): item = cls.getNode(vk2xmpp(uid), value["name"], action) if lists and value["lists"]: - list = findListByID(value["lists"][0], lists) + list = findListByID(value["lists"][0], lists["items"]) if list: item.setTagData("group", list[0]["name"]) items.append(item) diff --git a/library/utils.py b/library/utils.py index f9e4875..a79be40 100644 --- a/library/utils.py +++ b/library/utils.py @@ -84,8 +84,8 @@ def cache(func): result = func(self, uid, fields) if result: result["fields"] = fieldsStr - if "uid" in result: - del result["uid"] + if "user_id" in result: + del result["user_id"] if uid in self.cache: self.cache[uid].update(result) else: diff --git a/library/vkapi.py b/library/vkapi.py index b7860ef..2058bc2 100644 --- a/library/vkapi.py +++ b/library/vkapi.py @@ -30,6 +30,8 @@ REQUEST_RETRIES = 3 APP_ID = 3789129 # VK APP scope SCOPE = 69638 +# VK API VERSION +API_VERSION = "5.13" socket.setdefaulttimeout(SOCKET_TIMEOUT) @@ -332,7 +334,7 @@ class APIBinding(RequestProcessor): values = values or {} if not notoken: values["access_token"] = self.token - values["v"] = "3.0" + values["v"] = API_VERSION if "key" in self.captcha: values["captcha_sid"] = self.captcha["sid"] diff --git a/modules/mod_iq_disco.py b/modules/mod_iq_disco.py index 7622cac..660759c 100644 --- a/modules/mod_iq_disco.py +++ b/modules/mod_iq_disco.py @@ -134,7 +134,7 @@ def checkAPIToken(token): raise api.AuthError("Auth failed!") else: vk.online = True - userID = vk.getUserID() + userID = vk.getUserPreferences()[0] name = vk.getUserData(userID) data = {"auth": auth, "name": name, "friends_count": len(vk.getFriends())} except (api.VkApiError, Exception): |