Improved GUI for topic comments. Authentication errors should be handled gracefully now

This commit is contained in:
Manuel Cortez 2019-02-12 17:49:33 -06:00
parent a50ddd25b2
commit fb50f2783f
9 changed files with 65 additions and 14 deletions

View File

@ -32,6 +32,9 @@
* It is possible to load topics, audios and videos for a group. In order to do so, you need to go to the group buffer and press the menu key, or right mouse click, in the tree item representing the group. New buffers will be created inside the current group's buffer. * It is possible to load topics, audios and videos for a group. In order to do so, you need to go to the group buffer and press the menu key, or right mouse click, in the tree item representing the group. New buffers will be created inside the current group's buffer.
* You can create or delete all buffers for groups by pressing the menu key or right mouse click in the "communities" buffer. * You can create or delete all buffers for groups by pressing the menu key or right mouse click in the "communities" buffer.
* There is support for group topics. When opening them, they will be displayed as a list of posts. You can like or reply to such posts, as well as adding new posts in the topic. * There is support for group topics. When opening them, they will be displayed as a list of posts. You can like or reply to such posts, as well as adding new posts in the topic.
* Authentication errors should be handled gracefully by the application:
* When there is a password change, Socializer must be reauthorized again. An error message will indicate this if the user forgot to do that. After the error, the app will be restarted, prompting the user to introduce the new data for authorizing the application.
* If the user introduced incorrect or invalid data, Socializer will display an error and prompt the user again for valid information.
## Changes in version 0.18 (21.01.2019) ## Changes in version 0.18 (21.01.2019)

View File

@ -4,7 +4,7 @@ import random
import requests import requests
import logging import logging
from hashlib import md5 from hashlib import md5
from .wxUI import two_factor_auth from .wxUI import two_factor_auth, bad_password
log = logging.getLogger("authenticator.official") log = logging.getLogger("authenticator.official")
@ -49,7 +49,7 @@ def get_non_refreshed(login, password, scope=scope):
""" Retrieves a non-refreshed token, this should be the first token needed to authenticate in VK. """ Retrieves a non-refreshed token, this should be the first token needed to authenticate in VK.
returns the access_token which still needs to be refreshed, device_id, and secret code, needed to sign all petitions in VK.""" returns the access_token which still needs to be refreshed, device_id, and secret code, needed to sign all petitions in VK."""
if not (login or password): if not (login or password):
raise ValueError raise ValueError("Both user and password are required.")
device_id = get_device_id() device_id = get_device_id()
# Let's authenticate. # Let's authenticate.
url = "https://oauth.vk.com/token" url = "https://oauth.vk.com/token"
@ -89,8 +89,12 @@ def refresh_token(token, secret, device_id):
return perform_request(method, postdata, secret) return perform_request(method, postdata, secret)
def login(user, password): def login(user, password):
access_token, secret, device_id = get_non_refreshed(user, password) try:
response = refresh_token(access_token, secret, device_id) access_token, secret, device_id = get_non_refreshed(user, password)
response = refresh_token(access_token, secret, device_id)
except AuthenticationError:
bad_password()
raise AuthenticationError("")
try: try:
return response["response"]["token"], secret, device_id return response["response"]["token"], secret, device_id
except KeyError: except KeyError:

View File

@ -22,3 +22,6 @@ def get_code():
code = dlg.GetValue() code = dlg.GetValue()
dlg.Destroy() dlg.Destroy()
dlg.Destroy() dlg.Destroy()
def bad_password():
return wx.MessageDialog(None, _("Your password or email address are incorrect. Please fix the mistakes and try it again."), _("Wrong data"), wx.ICON_ERROR).ShowModal()

View File

@ -13,6 +13,7 @@ import config
from vk_api.exceptions import LoginRequired, VkApiError from vk_api.exceptions import LoginRequired, VkApiError
from requests.exceptions import ConnectionError from requests.exceptions import ConnectionError
from pubsub import pub from pubsub import pub
from mysc import restart
from mysc.repeating_timer import RepeatingTimer from mysc.repeating_timer import RepeatingTimer
from mysc.thread_utils import call_threaded from mysc.thread_utils import call_threaded
from mysc import localization from mysc import localization
@ -386,6 +387,7 @@ class Controller(object):
def authorisation_failed(self): def authorisation_failed(self):
""" display an informative message about a failed authorization process.""" """ display an informative message about a failed authorization process."""
commonMessages.bad_authorisation() commonMessages.bad_authorisation()
restart.restart_program()
def user_profile(self, person): def user_profile(self, person):
""" display someone's profile. For now, only users are supported.""" """ display someone's profile. For now, only users are supported."""

View File

@ -500,6 +500,20 @@ class displayCommentPresenter(displayPostPresenter):
a = displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) a = displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment())
self.clear_comments_list() self.clear_comments_list()
class displayTopicCommentPresenter(displayCommentPresenter):
def get_post_information(self):
from_ = self.session.get_user(self.post[self.user_identifier])
title = from_["user1_nom"]
self.send_message("set_title", value=title)
message = ""
message = get_message(self.post)
self.send_message("set", control="post_view", value=message)
self.get_attachments(self.post, message)
self.check_image_load()
self.send_message("disable_control", control="reply")
self.send_message("disable_control", control="comments")
class displayTopicPresenter(displayPostPresenter): class displayTopicPresenter(displayPostPresenter):
def __init__(self, session, postObject, group_id, view, interactor): def __init__(self, session, postObject, group_id, view, interactor):
@ -616,6 +630,11 @@ class displayTopicPresenter(displayPostPresenter):
topic_id = self.post["id"] topic_id = self.post["id"]
call_threaded(self.do_last, comment, group_id=group_id, topic_id=topic_id, reply_to_comment=c["id"]) call_threaded(self.do_last, comment, group_id=group_id, topic_id=topic_id, reply_to_comment=c["id"])
def show_comment(self, comment_index):
c = self.comments["items"][comment_index]
c["post_id"] = self.post["id"]
a = displayTopicCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment())
class displayAudioPresenter(base.basePresenter): class displayAudioPresenter(base.basePresenter):
def __init__(self, session, postObject, view, interactor): def __init__(self, session, postObject, view, interactor):
super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio") super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio")

View File

@ -110,6 +110,8 @@ class vkSession(object):
# log.exception("The session configuration has failed.") # log.exception("The session configuration has failed.")
def login(self): def login(self):
if self.logged == True:
return
try: try:
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)
@ -119,11 +121,19 @@ class vkSession(object):
self.settings.write() self.settings.write()
self.logged = True self.logged = True
self.get_my_data() self.get_my_data()
except ValueError: except VkApiError as error:
self.settings["vk"]["user"] = "" if error.code == 5: # this means invalid access token.
self.settings["vk"]["password"] = "" self.settings["vk"]["user"] = ""
self.settings.write() self.settings["vk"]["password"] = ""
pub.sendMessage("authorisation-failed") self.settings["vk"]["token"] = ""
self.settings["vk"]["secret"] = ""
self.settings["vk"]["device_id"] = ""
self.settings.write()
pub.sendMessage("authorisation-failed")
else: # print out error so we we will handle it.
log.exception("Fatal error when authenticating the application.")
log.exception(error.code)
log.exception(error.message)
def post_wall_status(self, message, *args, **kwargs): def post_wall_status(self, message, *args, **kwargs):
""" Sends a post to an user, group or community wall.""" """ Sends a post to an user, group or community wall."""
@ -242,8 +252,9 @@ class vkSession(object):
ids = ids + "{0},".format(i["id"],) ids = ids + "{0},".format(i["id"],)
gids = "" gids = ""
for i in data["groups"]: for i in data["groups"]:
self.db["groups"][i["id"]] = dict(nom=i["name"], gen=i["name"], dat=i["name"], acc=i["name"], ins=i["name"], abl=i["name"]) if i["id"] not in self.db["groups"]:
gids = "{0},".format(i["id"],) self.db["groups"][i["id"]] = dict(nom=i["name"], gen=i["name"], dat=i["name"], acc=i["name"], ins=i["name"], abl=i["name"])
gids = "{0},".format(i["id"],)
user_fields = "first_name_nom, last_name_nom, first_name_gen, last_name_gen, first_name_ins, last_name_ins, first_name_dat, last_name_dat, first_name_abl, last_name_abl, first_name_acc, last_name_acc, sex" user_fields = "first_name_nom, last_name_nom, first_name_gen, last_name_gen, first_name_ins, last_name_ins, first_name_dat, last_name_dat, first_name_abl, last_name_abl, first_name_acc, last_name_acc, sex"
user_fields_list = user_fields.split(", ") user_fields_list = user_fields.split(", ")
if ids != "": if ids != "":

View File

@ -2,10 +2,11 @@
import os import os
import sys import sys
import widgetUtils import widgetUtils
from . import wxUI as view
import paths import paths
import time import time
import logging import logging
from authenticator.official import AuthenticationError
from . import wxUI as view
from . import session from . import session
from .config_utils import Configuration from .config_utils import Configuration
@ -53,4 +54,9 @@ class sessionManagerController(object):
if dl.ShowModal() == widgetUtils.OK: if dl.ShowModal() == widgetUtils.OK:
c.settings["vk"]["user"] = dl.get_email() c.settings["vk"]["user"] = dl.get_email()
c.settings["vk"]["password"] = dl.get_password() c.settings["vk"]["password"] = dl.get_password()
c.settings.write() try:
c.login()
except AuthenticationError:
c.settings["vk"]["password"] = ""
c.settings["vk"]["user"]
return self.get_authorisation(c)

View File

@ -179,3 +179,6 @@ class list(object):
return 0 return 0
else: else:
return selected return selected
def Enable(self, value):
return self.list.Enable(value)

View File

@ -24,7 +24,7 @@ def show_error_code(code):
return wx.MessageDialog(None, message, title, style=wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, message, title, style=wx.ICON_ERROR).ShowModal()
def bad_authorisation(): def bad_authorisation():
return wx.MessageDialog(None, _("authorisation failed. Your configuration will not be saved. Please close and open again the application for authorising your account. Make sure you have typed your credentials correctly."), _("Error"), style=wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("authorisation failed. Your configuration will be deleted. If you recently changed your password in VK, you need to reauthorize Socializer. The application will be restarted and prompt you again for your user and password. Press OK to continue."), _("Error"), style=wx.ICON_ERROR).ShowModal()
def no_audio_albums(): def no_audio_albums():
return wx.MessageDialog(None, _("You do not have audio albums."), _("Error"), style=wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, _("You do not have audio albums."), _("Error"), style=wx.ICON_ERROR).ShowModal()