Fix AttributeError when saving data from the alternative tokens method

This commit is contained in:
Manuel Cortez 2019-04-11 05:29:42 -05:00
commit 2b42c64160
8 changed files with 112 additions and 68 deletions

View File

@ -21,33 +21,6 @@ test_py3:
- '%PYTHON3% -m coverage report --omit="test*"' - '%PYTHON3% -m coverage report --omit="test*"'
coverage: '/TOTAL.+ ([0-9]{1,3}%)/' coverage: '/TOTAL.+ ([0-9]{1,3}%)/'
.alpha:
type: deploy
tags:
- windows
script:
- pip install --upgrade pip
- pip install --upgrade -r requirements.txt
- copy changelog.md doc\changelog.md
- cd doc
- python documentation_importer.py
- cd ..\src
- python ..\doc\generator.py
- python write_version_data.py
- python setup.py py2exe
- cd ..
- cd scripts
- python prepare_zipversion.py
- cd ..
- move src\socializer.zip socializer.zip
only:
- schedules
artifacts:
paths:
- socializer.zip
name: socializer
expire_in: 1 day
alpha_python3: alpha_python3:
type: deploy type: deploy
tags: tags:

View File

@ -7,6 +7,10 @@
* When modifying volume of the playing audio, it will decrease or increase the volume by 2% instead of 5%. * When modifying volume of the playing audio, it will decrease or increase the volume by 2% instead of 5%.
* For users with multiple soundcards, there is a new tab in the preferences dialogue of Socializer, called sound. From there, you can define what soundcard will be used for input and output. * For users with multiple soundcards, there is a new tab in the preferences dialogue of Socializer, called sound. From there, you can define what soundcard will be used for input and output.
* it is possible to select the language used in socializer from the preferences dialog. When changing the language, the application must be restarted for the changes to take effect. * it is possible to select the language used in socializer from the preferences dialog. When changing the language, the application must be restarted for the changes to take effect.
* Improvements in conversation buffers:
* it is possible to retrieve more items for conversation buffers. Due to API limitations, it is possible to load up to the last 600 messages for every conversation. Take into account that the process of loading more items takes some time. You will hear a message when the process is done.
* It is possible to delete entire conversations from the buffer's tree, by using the menu key and selecting "delete conversation". The conversation will be removed from VK.
* Read confirmations will be sent to VK as soon as you read the message. Before, read confirmations were being sent every 3 minutes to the social network.
## Changes in version 0.19 (13.03.2019) ## Changes in version 0.19 (13.03.2019)

View File

@ -911,10 +911,11 @@ class chatBuffer(baseBuffer):
def insert(self, item, reversed=False): def insert(self, item, reversed=False):
""" Add a new item to the list. Uses session.composefunc for parsing the dictionary and create a valid result for putting it in the list.""" """ Add a new item to the list. Uses session.composefunc for parsing the dictionary and create a valid result for putting it in the list."""
# as this tab is based in a text control, we have to overwrite the defaults.
item_ = getattr(renderers, self.compose_function)(item, self.session) item_ = getattr(renderers, self.compose_function)(item, self.session)
# the self.chat dictionary will have (first_line, last_line) as keys and message ID as a value for looking into it when needed. # the self.chat dictionary will have (first_line, last_line) as keys and message ID as a value for looking into it when needed.
# Here we will get first and last line of a chat message appended to the history. # Here we will get first and last line of a chat message appended to the history.
values = self.tab.add_message(item_[0]) values = self.tab.add_message(item_[0], reverse=reversed)
self.chats[values] = item["id"] self.chats[values] = item["id"]
def get_focused_post(self): def get_focused_post(self):
@ -930,7 +931,6 @@ class chatBuffer(baseBuffer):
# position[2]+1 is added because line may start with 0, while in wx.TextCtrl.GetNumberLines() that is not possible. # position[2]+1 is added because line may start with 0, while in wx.TextCtrl.GetNumberLines() that is not possible.
if position[2]+1 >= i[0] and position[2]+1 < i[1]: if position[2]+1 >= i[0] and position[2]+1 < i[1]:
id_ = self.chats[i] id_ = self.chats[i]
# print i
break break
# Retrieve here the object based in id_ # Retrieve here the object based in id_
if id_ != None: if id_ != None:
@ -946,9 +946,10 @@ class chatBuffer(baseBuffer):
msg = self.get_focused_post() msg = self.get_focused_post()
if msg == False: # Handle the case where the last line of the control cannot be matched to anything. if msg == False: # Handle the case where the last line of the control cannot be matched to anything.
return return
if "read_state" in msg and msg["read_state"] == 0 and msg["id"] not in self.reads and "out" in msg and msg["out"] == 0: # Mark unread conversations as read.
if "read_state" in msg and msg["read_state"] == 0 and "out" in msg and msg["out"] == 0:
self.session.soundplayer.play("message_unread.ogg") self.session.soundplayer.play("message_unread.ogg")
self.reads.append(msg["id"]) call_threaded(self.session.vk.client.messages.markAsRead, peer_id=self.kwargs["peer_id"])
self.session.db[self.name]["items"][-1]["read_state"] = 1 self.session.db[self.name]["items"][-1]["read_state"] = 1
if "attachments" in msg and len(msg["attachments"]) > 0: if "attachments" in msg and len(msg["attachments"]) > 0:
self.tab.attachments.list.Enable(True) self.tab.attachments.list.Enable(True)
@ -985,10 +986,11 @@ class chatBuffer(baseBuffer):
event.Skip() event.Skip()
def get_items(self, show_nextpage=False): def get_items(self, show_nextpage=False):
""" Update buffer with newest items or get older items in the buffer."""
if self.can_get_items == False: return if self.can_get_items == False: return
retrieved = True # Control variable for handling unauthorised/connection errors. retrieved = True
try: try:
num = getattr(self.session, "get_messages")(name=self.name, *self.args, **self.kwargs) num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
except VkApiError as err: except VkApiError as err:
log.error("Error {0}: {1}".format(err.code, err.error)) log.error("Error {0}: {1}".format(err.code, err.error))
retrieved = err.code retrieved = err.code
@ -1001,20 +1003,38 @@ class chatBuffer(baseBuffer):
self.create_tab(self.parent) self.create_tab(self.parent)
# Add name to the new control so we could look for it when needed. # Add name to the new control so we could look for it when needed.
self.tab.name = self.name self.tab.name = self.name
if show_nextpage == False: if show_nextpage == False:
if self.tab.history.GetValue() != "" and num > 0: if self.tab.history.GetValue() != "" and num > 0:
v = [i for i in self.session.db[self.name]["items"][:num]] v = [i for i in self.session.db[self.name]["items"][:num]]
# v.reverse()
[self.insert(i, False) for i in v] [self.insert(i, False) for i in v]
else: else:
[self.insert(i) for i in self.session.db[self.name]["items"][:num]] [self.insert(i) for i in self.session.db[self.name]["items"][:num]]
else: else:
if num > 0: if num > 0:
[self.insert(i, False) for i in self.session.db[self.name]["items"][:num]] # At this point we save more CPU and mathematical work if we just delete everything in the chat history and readd all messages.
# Otherwise we'd have to insert new lines at the top and recalculate positions everywhere else.
# Firstly, we'd have to save the current focused object so we will place the user in the right part of the text after loading everything again.
focused_post = self.get_post()
self.chats = dict()
self.tab.history.SetValue("")
v = [i for i in self.session.db[self.name]["items"]]
[self.insert(i) for i in v]
# Now it's time to set back the focus in the post.
for i in self.chats.keys():
if self.chats[i] == focused_post["id"]:
line = i[0]
self.tab.history.SetInsertionPoint(self.tab.history.XYToPosition(0, line))
output.speak(_("Items loaded"))
break
if self.unread == True and num > 0: if self.unread == True and num > 0:
self.session.db[self.name]["items"][-1].update(read_state=0) self.session.db[self.name]["items"][-1].update(read_state=0)
return retrieved return retrieved
def get_more_items(self):
output.speak(_("Getting more items..."))
call_threaded(self.get_items, show_nextpage=True)
def add_attachment(self, *args, **kwargs): def add_attachment(self, *args, **kwargs):
a = presenters.attachPresenter(session=self.session, view=views.attachDialog(voice_messages=True), interactor=interactors.attachInteractor()) a = presenters.attachPresenter(session=self.session, view=views.attachDialog(voice_messages=True), interactor=interactors.attachInteractor())
if len(a.attachments) != 0: if len(a.attachments) != 0:
@ -1093,7 +1113,6 @@ class chatBuffer(baseBuffer):
def __init__(self, unread=False, *args, **kwargs): def __init__(self, unread=False, *args, **kwargs):
super(chatBuffer, self).__init__(*args, **kwargs) super(chatBuffer, self).__init__(*args, **kwargs)
self.unread = unread self.unread = unread
self.reads = []
self.chats = dict() self.chats = dict()
self.peer_typing = 0 self.peer_typing = 0
self.last_keypress = time.time() self.last_keypress = time.time()

View File

@ -114,8 +114,6 @@ class Controller(object):
self.window.realize() self.window.realize()
self.repeatedUpdate = RepeatingTimer(120, self.update_all_buffers) self.repeatedUpdate = RepeatingTimer(120, self.update_all_buffers)
self.repeatedUpdate.start() self.repeatedUpdate.start()
self.readMarker = RepeatingTimer(60, self.mark_as_read)
self.readMarker.start()
def complete_buffer_creation(self, buffer, name_, position): def complete_buffer_creation(self, buffer, name_, position):
answer = buffer.get_items() answer = buffer.get_items()
@ -158,14 +156,6 @@ class Controller(object):
call_threaded(self.chat_from_id, i["last_message"]["peer_id"], setfocus=False, unread=False) call_threaded(self.chat_from_id, i["last_message"]["peer_id"], setfocus=False, unread=False)
time.sleep(0.6) time.sleep(0.6)
def mark_as_read(self):
for i in self.buffers:
if hasattr(i, "reads") and len(i.reads) != 0:
response = self.session.vk.client.messages.markAsRead(peer_id=i.kwargs["peer_id"])
i.clear_reads()
i.reads = []
time.sleep(1)
def get_audio_albums(self, user_id=None, create_buffers=True, force_action=False): def get_audio_albums(self, user_id=None, create_buffers=True, force_action=False):
if self.session.settings["load_at_startup"]["audio_albums"] == False and force_action == False: if self.session.settings["load_at_startup"]["audio_albums"] == False and force_action == False:
return return
@ -350,13 +340,13 @@ class Controller(object):
if "url" in audio_object and audio_object["url"] =="": if "url" in audio_object and audio_object["url"] =="":
self.notify(message=_("This file could not be played because it is not allowed in your country")) self.notify(message=_("This file could not be played because it is not allowed in your country"))
return return
call_threaded(player.player.play, audio_object, fresh=True) pub.sendMessage("play", object=audio_object, fresh=True)
def play_audios(self, audios): def play_audios(self, audios):
""" Play all audios passed in alist, putting the audio in a queue of the media player. """ Play all audios passed in alist, putting the audio in a queue of the media player.
@audios list: A list of Vk audio objects. @audios list: A list of Vk audio objects.
""" """
player.player.play_all(audios, shuffle=self.window.player_shuffle.IsChecked()) pub.sendMessage("play_all", list_of_songs=audios, shuffle=self.window.player_shuffle.IsChecked())
def view_post(self, post_object, controller_): def view_post(self, post_object, controller_):
""" Display the passed post in the passed post presenter. """ Display the passed post in the passed post presenter.
@ -392,7 +382,7 @@ class Controller(object):
elif user_id > 2000000000: elif user_id > 2000000000:
chat = self.session.vk.client.messages.getChat(chat_id=user_id-2000000000) chat = self.session.vk.client.messages.getChat(chat_id=user_id-2000000000)
name = chat["title"] name = chat["title"]
wx.CallAfter(pub.sendMessage, "create_buffer", buffer_type="chatBuffer", buffer_title=name, parent_tab="chats", get_items=True, kwargs=dict(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="render_message", session=self.session, unread=unread, count=200, peer_id=user_id, rev=0, extended=True, fields="id, user_id, date, read_state, out, body, attachments, deleted")) wx.CallAfter(pub.sendMessage, "create_buffer", buffer_type="chatBuffer", buffer_title=name, parent_tab="chats", get_items=True, kwargs=dict(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="render_message", parent_endpoint="messages", endpoint="getHistory", session=self.session, unread=unread, count=200, peer_id=user_id, rev=0, extended=True, fields="id, user_id, date, read_state, out, body, attachments, deleted"))
# if setfocus: # if setfocus:
# pos = self.window.search(buffer.name) # pos = self.window.search(buffer.name)
# self.window.change_buffer(pos) # self.window.change_buffer(pos)
@ -538,7 +528,7 @@ class Controller(object):
data = [message] data = [message]
# Let's add this to the buffer. # Let's add this to the buffer.
# ToDo: Clean this code and test how is the database working with this set to True. # ToDo: Clean this code and test how is the database working with this set to True.
num = self.session.order_buffer(buffer.name, data, True) buffer.session.db[buffer.name]["items"].append(message)
buffer.insert(self.session.db[buffer.name]["items"][-1], False) buffer.insert(self.session.db[buffer.name]["items"][-1], False)
self.session.soundplayer.play("message_received.ogg") self.session.soundplayer.play("message_received.ogg")
wx.CallAfter(self.reorder_buffer, buffer) wx.CallAfter(self.reorder_buffer, buffer)
@ -883,6 +873,7 @@ class Controller(object):
else: else:
option = menu.Append(wx.NewId(), _("Discard groups")) option = menu.Append(wx.NewId(), _("Discard groups"))
widgetUtils.connect_event(menu, widgetUtils.MENU, self.unload_community_buffers, menuitem=option) widgetUtils.connect_event(menu, widgetUtils.MENU, self.unload_community_buffers, menuitem=option)
# Deal with video and audio albums' sections.
elif current_buffer.name == "audio_albums": elif current_buffer.name == "audio_albums":
menu = wx.Menu() menu = wx.Menu()
if self.session.settings["load_at_startup"]["audio_albums"] == False and not hasattr(self.session, "audio_albums"): if self.session.settings["load_at_startup"]["audio_albums"] == False and not hasattr(self.session, "audio_albums"):
@ -899,6 +890,9 @@ class Controller(object):
else: else:
option = menu.Append(wx.NewId(), _("Discard video albums")) option = menu.Append(wx.NewId(), _("Discard video albums"))
widgetUtils.connect_event(menu, widgetUtils.MENU, self.unload_video_album_buffers, menuitem=option) widgetUtils.connect_event(menu, widgetUtils.MENU, self.unload_video_album_buffers, menuitem=option)
elif current_buffer.name.endswith("_messages"):
menu = menus.conversationBufferMenu()
widgetUtils.connect_event(menu, widgetUtils.MENU, self.delete_conversation, menuitem=menu.delete)
if menu != None: if menu != None:
self.window.PopupMenu(menu, self.window.FindFocus().GetPosition()) self.window.PopupMenu(menu, self.window.FindFocus().GetPosition())
@ -1001,3 +995,12 @@ class Controller(object):
self.window.remove_buffer(buff) self.window.remove_buffer(buff)
self.buffers.remove(buffer) self.buffers.remove(buffer)
del self.session.video_albums del self.session.video_albums
def delete_conversation(self, *args, **kwargs):
current_buffer = self.get_current_buffer()
d = commonMessages.delete_conversation()
if d == widgetUtils.YES:
results = self.session.vk.client.messages.deleteConversation(peer_id=current_buffer.kwargs["peer_id"])
buff = self.window.search(current_buffer.name)
self.window.remove_buffer(buff)
self.buffers.remove(current_buffer)

View File

@ -1,40 +1,62 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Audio player module for socializer.
As this player does not have (still) an associated GUI, I have decided to place here the code for the interactor, which connects a bunch of pubsub events, and the presenter itself.
"""
import sys import sys
import random import random
import output
import sound_lib
import logging import logging
import sound_lib
import output
import config import config
from sound_lib.config import BassConfig from sound_lib.config import BassConfig
from sound_lib.stream import URLStream from sound_lib.stream import URLStream
from sound_lib.main import BassError from sound_lib.main import BassError
from mysc.repeating_timer import RepeatingTimer
from pubsub import pub from pubsub import pub
from mysc.repeating_timer import RepeatingTimer
player = None player = None
log = logging.getLogger("player") log = logging.getLogger("player")
# This function will be deprecated when the player works with pubsub events, as will no longer be needed to instantiate and import the player directly.
def setup(): def setup():
global player global player
if player == None: if player == None:
player = audioPlayer() player = audioPlayer()
class audioPlayer(object): class audioPlayer(object):
""" A media player which will play all passed URLS."""
def __init__(self): def __init__(self):
# control variable for checking if another file has been sent to the player before,
# thus avoiding double file playback and other oddities happening in sound_lib from time to time.
self.is_playing = False self.is_playing = False
# This will be the URLStream handler
self.stream = None self.stream = None
self.vol = config.app["sound"]["volume"] self.vol = config.app["sound"]["volume"]
# this variable is set to true when the URLPlayer is decoding something, thus it will block other calls to the play method.
self.is_working = False self.is_working = False
# Playback queue.
self.queue = [] self.queue = []
# Index of the currently playing track.
self.playing_track = 0 self.playing_track = 0
# Status of the player.
self.stopped = True self.stopped = True
# Modify some default settings present in Bass so it will increase timeout connection, thus causing less "connection timed out" errors when playing. # Modify some default settings present in Bass so it will increase timeout connection, thus causing less "connection timed out" errors when playing.
bassconfig = BassConfig() bassconfig = BassConfig()
# Set timeout connection to 30 seconds. # Set timeout connection to 30 seconds.
bassconfig["net_timeout"] = 30000 bassconfig["net_timeout"] = 30000
pub.subscribe(self.play, "play")
pub.subscribe(self.play_all, "play_all")
pub.subscribe(self.pause, "pause")
pub.subscribe(self.stop, "stop")
pub.subscribe(self.play_next, "play_next")
pub.subscribe(self.play_previous, "play_previous")
def play(self, url, set_info=True, fresh=False): def play(self, object, set_info=True, fresh=False):
""" Play an URl Stream.
@object dict: typically an audio object as returned by VK, with a "url" component which must be a valid URL to a media file.
@set_info bool: If true, will set information about the currently playing audio in the application status bar.
@fresh bool: If True, will remove everything playing in the queue and start this file only. otherwise it will play the new file but not remove the current queue."""
if self.stream != None and self.stream.is_playing == True: if self.stream != None and self.stream.is_playing == True:
try: try:
self.stream.stop() self.stream.stop()
@ -50,19 +72,15 @@ class audioPlayer(object):
if self.is_working == False: if self.is_working == False:
self.is_working = True self.is_working = True
# Let's encode the URL as bytes if on Python 3 # Let's encode the URL as bytes if on Python 3
if sys.version[0] == "3": url_ = bytes(object["url"], "utf-8")
url_ = bytes(url["url"], "utf-8")
else:
url_ = url["url"]
try: try:
self.stream = URLStream(url=url_) self.stream = URLStream(url=url_)
except IndexError: except IndexError:
log.error("Unable to play URL") log.error("Unable to play URL %s" % (url_))
log.error(url_)
return return
# Translators: {0} will be replaced with a song's title and {1} with the artist. # Translators: {0} will be replaced with a song's title and {1} with the artist.
if set_info: if set_info:
msg = _("Playing {0} by {1}").format(url["title"], url["artist"]) msg = _("Playing {0} by {1}").format(object["title"], object["artist"])
pub.sendMessage("update-status-bar", status=msg) pub.sendMessage("update-status-bar", status=msg)
self.stream.volume = self.vol/100.0 self.stream.volume = self.vol/100.0
self.stream.play() self.stream.play()
@ -70,6 +88,7 @@ class audioPlayer(object):
self.is_working = False self.is_working = False
def stop(self): def stop(self):
""" Stop audio playback. """
if self.stream != None and self.stream.is_playing == True: if self.stream != None and self.stream.is_playing == True:
self.stream.stop() self.stream.stop()
self.stopped = True self.stopped = True
@ -79,6 +98,7 @@ class audioPlayer(object):
self.queue = [] self.queue = []
def pause(self): def pause(self):
""" pause the current playback, without destroying the queue or the current stream. If the stream is already paused this function will resume the playback. """
if self.stream != None: if self.stream != None:
if self.stream.is_playing == True: if self.stream.is_playing == True:
self.stream.pause() self.stream.pause()
@ -105,11 +125,14 @@ class audioPlayer(object):
if self.stream != None: if self.stream != None:
self.stream.volume = self.vol/100.0 self.stream.volume = self.vol/100.0
def play_all(self, list_of_urls, shuffle=False): def play_all(self, list_of_songs, shuffle=False):
""" Play all passed songs and adds all of those to the queue.
@list_of_songs list: A list of audio objects returned by VK.
@shuffle bool: If True, the files will be played randomly."""
self.playing_track = 0 self.playing_track = 0
self.stop() self.stop()
# Skip all country restricted tracks as they are not playable here. # Skip all country restricted tracks as they are not playable here.
self.queue = [i for i in list_of_urls if i["url"] != ""] self.queue = [i for i in list_of_songs if i["url"] != ""]
if shuffle: if shuffle:
random.shuffle(self.queue) random.shuffle(self.queue)
self.play(self.queue[self.playing_track]) self.play(self.queue[self.playing_track])
@ -117,6 +140,7 @@ class audioPlayer(object):
self.worker.start() self.worker.start()
def player_function(self): def player_function(self):
""" Check if the stream has reached the end of the file so it will play the next song. """
if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position: if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position:
if len(self.queue) == 0 or self.playing_track >= len(self.queue): if len(self.queue) == 0 or self.playing_track >= len(self.queue):
self.worker.cancel() self.worker.cancel()
@ -126,6 +150,7 @@ class audioPlayer(object):
self.play(self.queue[self.playing_track]) self.play(self.queue[self.playing_track])
def play_next(self): def play_next(self):
""" Play the next song in the queue. """
if len(self.queue) == 0: if len(self.queue) == 0:
return return
if self.playing_track < len(self.queue)-1: if self.playing_track < len(self.queue)-1:
@ -135,6 +160,7 @@ class audioPlayer(object):
self.play(self.queue[self.playing_track]) self.play(self.queue[self.playing_track])
def play_previous(self): def play_previous(self):
""" Play the previous song in the queue. """
if len(self.queue) == 0: if len(self.queue) == 0:
return return
if self.playing_track <= 0: if self.playing_track <= 0:
@ -144,6 +170,7 @@ class audioPlayer(object):
self.play(self.queue[self.playing_track]) self.play(self.queue[self.playing_track])
def check_is_playing(self): def check_is_playing(self):
""" check if the player is already playing a stream. """
if self.stream == None: if self.stream == None:
return False return False
if self.stream != None and self.stream.is_playing == False: if self.stream != None and self.stream.is_playing == False:

View File

@ -66,6 +66,9 @@ class vkSession(object):
self.db[name] = {} self.db[name] = {}
self.db[name]["items"] = [] self.db[name]["items"] = []
first_addition = True first_addition = True
# Handles chat messages case, as the buffer is inverted
if name.endswith("_messages") and show_nextpage == True:
show_nextpage = False
for i in data: for i in data:
if "type" in i and not isinstance(i["type"], int) and (i["type"] == "wall_photo" or i["type"] == "photo_tag" or i["type"] == "photo"): if "type" in i and not isinstance(i["type"], int) and (i["type"] == "wall_photo" or i["type"] == "photo_tag" or i["type"] == "photo"):
log.debug("Skipping unsupported item... %r" % (i,)) log.debug("Skipping unsupported item... %r" % (i,))
@ -124,8 +127,11 @@ class vkSession(object):
config_filename = os.path.join(paths.config_path(), self.session_id, "vkconfig.json") config_filename = os.path.join(paths.config_path(), self.session_id, "vkconfig.json")
self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"], token=self.settings["vk"]["token"], secret=self.settings["vk"]["secret"], device_id=self.settings["vk"]["device_id"], alt_token=self.settings["vk"]["use_alternative_tokens"], filename=config_filename) self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"], token=self.settings["vk"]["token"], secret=self.settings["vk"]["secret"], device_id=self.settings["vk"]["device_id"], alt_token=self.settings["vk"]["use_alternative_tokens"], filename=config_filename)
self.settings["vk"]["token"] = self.vk.session_object.token["access_token"] self.settings["vk"]["token"] = self.vk.session_object.token["access_token"]
try:
self.settings["vk"]["secret"] = self.vk.session_object.secret self.settings["vk"]["secret"] = self.vk.session_object.secret
self.settings["vk"]["device_id"] = self.vk.session_object.device_id self.settings["vk"]["device_id"] = self.vk.session_object.device_id
except AttributeError:
pass
self.settings.write() self.settings.write()
self.logged = True self.logged = True
self.get_my_data() self.get_my_data()
@ -192,6 +198,10 @@ class vkSession(object):
if data != None: if data != None:
if "count" not in kwargs: if "count" not in kwargs:
kwargs["count"] = 100 kwargs["count"] = 100
# Let's handle a little exception when dealing with conversation buffers.
# the first results of the query should be reversed before being sent to order_buffer.
if type(data) == dict and "items" in data and endpoint == "getHistory" and kwargs["offset"] == 0:
data["items"].reverse()
if type(data) == dict: if type(data) == dict:
num = self.order_buffer(name, data["items"], show_nextpage) num = self.order_buffer(name, data["items"], show_nextpage)
self.db[name]["offset"] = kwargs["offset"]+kwargs["count"] self.db[name]["offset"] = kwargs["offset"]+kwargs["count"]

View File

@ -64,3 +64,6 @@ def restart_program():
def community_no_items(): def community_no_items():
return wx.MessageDialog(None, _("There are 0 items for this community."), _("Error"), wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("There are 0 items for this community."), _("Error"), wx.ICON_ERROR).ShowModal()
def delete_conversation():
return wx.MessageDialog(None, _("do you really want to delete all messages of this conversation in VK?"), _("Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal()

View File

@ -125,3 +125,8 @@ class communityBufferMenu(wx.Menu):
self.load_videos = load.Append(wx.NewId(), _("Load videos")) self.load_videos = load.Append(wx.NewId(), _("Load videos"))
self.load_documents = load.Append(wx.NewId(), _("Load documents")) self.load_documents = load.Append(wx.NewId(), _("Load documents"))
self.Append(wx.NewId(), _("Load"), load) self.Append(wx.NewId(), _("Load"), load)
class conversationBufferMenu(wx.Menu):
def __init__(self):
super(conversationBufferMenu, self).__init__()
self.delete = self.Append(wx.NewId(), _("Delete conversation"))