我有PyQt5应用程序的问题,不知道如何解决它。
在我的托盘qt应用程序中,我有用户注销操作按钮,该按钮与注销功能相关联。 tray.py 中的退出功能应通过 views.py 中的服务器应用上的响应我的退出功能来激活。在 views.py 中,我有退出httpResponse的退出功能(“用户已注销”)。
我的问题是:“当用户按下该注销按钮时,如何识别我的桌面pyqt应用程序?因为我收到response.status_code = 200它只表示我只收到一个页面,而不是那个用户状态(如果用户是登录或注销)“。一切似乎都没问题,但不知道如何在 tray.py / logout()
中继续执行代码桌面应用 - tray.py
import json
import sys, os, requests, uuid
from Crypto import Random
from Crypto.PublicKey import RSA
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QMenu
from PyQt5.QtWidgets import QSystemTrayIcon
from login import LoginForm
from settings import HTTP_PROTOCOL
from settings import SERVER_URL
from timestamp.form import TimestampForm
class SystemTrayIcon(QSystemTrayIcon):
def __init__(self):
QSystemTrayIcon.__init__(self)
self.setIcon(QIcon('icons/icon-placeholder_128x128_red.png'))
self.http_client = requests.Session()
self.base_url = '{}://{}'.format(HTTP_PROTOCOL, SERVER_URL)
self.set_desktop_timezone()
# Keeping reference to LoginForm object so that window wouldn't close
self.uuid = self.create_uuid('TTASM')
self.create_private_key()
try:
requests.get(self.base_url)
self.server_accessible = True
self.present_login_form()
except:
self.server_accessible = False
pass
self.set_server_public_key()
self.create_ui()
def createURL(self, path):
return '{}{}'.format(self.base_url, path)
# Find Desktop's timezone
def set_desktop_timezone(self):
response = requests.get('http://freegeoip.net/json')
response_json = json.JSONDecoder().decode(response.text)
self.timezone = response_json['time_zone']
def verify_initial_data(self):
url = self.createURL('/initial_synchronization/?timezone={}'.format(self.timezone))
try:
response = self.http_client.get(url)
if response.status_code == 200:
self.last_timestamp = response.text
else:
raise Exception('Server errror: {}'.format(response.status_code))
except:
print('Something is wrong with server comms')
def set_server_public_key(self):
#get server public key
url = self.createURL('/public_key/')
print('Trying to get the public key from:', url)
try:
response = self.http_client.get(url)
except:
print ('No response, server may be down')
try:
if response.status_code == 200:
self.server_rsa_pub = RSA.importKey(response.text)
print ('Server private key aquired')
else:
print ('Server failed to provide public key')
except:
print("\nServer is not responding")
# self.loginForm.close()
def create_private_key(self):
#Create new client RSA private key, public key and public key hash and store them to disk
random_generator = Random.new().read
self.client_rsa = RSA.generate(2048, random_generator)
print ('Client private key created')
# with open('./clientdata/client_RSA', 'wb') as f:
# f.write(cl_rsa.exportKey())
# with open('./clientdata/client_RSA.pub', 'wb') as f:
# f.write(cl_rsa.publickey().exportKey())
# with open('./clientdata/client_RSA.hash', 'w') as f:
# f.write(SHA256.new(cl_rsa.publickey().exportKey()).hexdigest())
print ('Client keys created')
def create_ui(self):
"""Create user interface of Tray icon"""
mainMenu = QMenu()
subMenu = QMenu(mainMenu)
subMenu.setTitle("Util")
subButton_1 = subMenu.addAction("Show token")
subButton_1.triggered.connect(self.show_token)
subButton_2 = subMenu.addAction("Test sockets")
subButton_2.triggered.connect(self.test_sockets)
# Set the order of layout and add everything to main menu
self.logInButton = mainMenu.addAction("Log in")
self.logInButton.triggered.connect(self.present_login_form)
self.simButton = mainMenu.addAction("Let's pretend server is accessible")
self.simButton.triggered.connect(self.enable_login_etc)
mainMenu.addSeparator()
self.msgButton = mainMenu.addAction("Send message") # find a way how to hide this button to preserve action on it before user's log in action
self.msgButton.triggered.connect(self.present_timestamp_form)
if not self.server_accessible:
self.logInButton.setEnabled(False)
self.msgButton.setEnabled(False)
mainMenu.addSeparator()
mainMenu.addMenu(subMenu)
mainMenu.addSeparator()
self.logoutButton = mainMenu.addAction("Log out")
self.logoutButton.triggered.connect(self.logout)
self.logoutButton.setEnabled(False)
mainMenu.addSeparator()
exitButton = mainMenu.addAction("Exit")
exitButton.triggered.connect(self.quit)
self.setContextMenu(mainMenu)
def enable_login_etc(self):
self.logInButton.setEnabled(True)
self.msgButton.setEnabled(True)
def toggle_login_logout_button(self):
self.logInButton.setEnabled(False)
self.logoutButton.setEnabled(True)
def create_uuid(self, UUID_string):
return uuid.uuid3(uuid.NAMESPACE_DNS, UUID_string)
def change_icon_on_login(self):
self.setIcon(QIcon('icons/icon-placeholder_128x128_green.png'))
def present_login_form(self):
self.login_form = LoginForm(self)
self.login_form.show()
def present_timestamp_form(self):
url = self.createURL('/last_activity_duration/')
response = self.http_client.get(url)
self.timestamp_form = TimestampForm(self, response.text)
self.timestamp_form.show()
def show_token(self):
"""Placeholder function"""
try:
self.showMessage('Token',
self.token,
QSystemTrayIcon.Information,
3000)
except:
self.showMessage('Token',
'No token received',
QSystemTrayIcon.Information,
3000)
def test_sockets(self):
"""Placeholder function"""
self.showMessage('Testing',
'Pending implementation',
QSystemTrayIcon.Information,
3000)
#How to logout currently logged in user through get request
def logout(self):
url = self.createURL('/user_logout/')
response = self.http_client.get(url)
if response.status_code == 200:
print("Response from view >>>>>>>", response.text)
**WHAT TO DO HERE?**
def quit(self):
"""Exit program in a clean way."""
if os.path.isfile('pid'):
os.remove('pid')
print ("Deleting pid file")
print ("Exiting")
sys.exit(0)
服务器应用 - urls.py
url(r'^user_logout/$', views.user_logout, name='user_logout'),
服务器应用 - views.py
@verified_email_required
def user_logout(request):
print(request.user)
logout(request)
return HttpResponse('User is logged out')
我的login.py。这就是我用户登录的方式。
from PyQt5 import QtCore
from PyQt5.QtWidgets import QDesktopWidget
from PyQt5.QtWidgets import QFormLayout, QHBoxLayout, QMessageBox
from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton
from PyQt5.QtWidgets import QWidget
#from utility import encrypt_data
class LoginForm(QWidget):
def __init__(self, parent_tray):
super(LoginForm, self).__init__()
# keeping reference to parent
self.parent_tray = parent_tray
# define fixed size
self.fixedWidth = 250
self.fixedHeight = 100
# no min, max, close button
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint |
QtCore.Qt.CustomizeWindowHint |
QtCore.Qt.WindowTitleHint)
self.create_ui()
self.move_to_primary_center()
self.setWindowTitle("Log in")
def create_ui(self):
"""Create user interface for login popup window"""
emailLabel = QLabel("Email:")
passwordLabel = QLabel("Password:")
self.email = QLineEdit()
self.password = QLineEdit()
print (self.email.whatsThis())
self.email.setPlaceholderText("Enter your email")
self.password.setPlaceholderText("Enter your password")
# Show asterisk in input instead of password chars
self.password.setEchoMode(QLineEdit.Password)
submitButton = QPushButton("Submit")
# Usign lambda because Qt doesn't allow for arguments to by passed to slots
# And we want to keep email and password as a private variables so we
# don't want to make them direct members of Class and call them with self
# directly inside self.submit() function
submitButton.clicked.connect(lambda: self.submit(self.parent_tray,
self.email.text(),
self.password.text()))
# Enter pressed inside password line edit
self.password.returnPressed.connect(lambda: self.submit(self.parent_tray,
self.email.text(),
self.password.text()))
self.email.returnPressed.connect(self.password.setFocus)
cancelButton = QPushButton("Cancel")
cancelButton.clicked.connect(self.cancel)
#Design a form layout
formBox = QFormLayout()
formBox.addRow(emailLabel, self.email)
formBox.addRow(passwordLabel, self.password)
# sign up label / link
signUpLabel = QLabel()
signUpLabel.setText('<a href="http://localhost:8000/sign-up/">Sign Up</a>')
signUpLabel.setOpenExternalLinks(True)
signUpLabel.show()
# recover password link
recoverLabel = QLabel()
recoverLabel.setText('<a href="http://localhost:8000/recover-password/">Forgot your password?</a>')
recoverLabel.setOpenExternalLinks(True)
recoverLabel.show()
# build sign up row
signUpRow = QHBoxLayout()
signUpRow.addWidget(signUpLabel)
signUpRow.addWidget(recoverLabel)
#add sign up row
formBox.addRow(signUpRow)
buttonRow = QHBoxLayout()
buttonRow.addWidget(submitButton)
buttonRow.addWidget(cancelButton)
# add button row
formBox.addRow(buttonRow)
# Set layout for the Login Form (self)
self.setLayout(formBox)
try:
last_user = open ('last_user', 'r').read()
self.email.setText(last_user)
self.password.setFocus()
except:
pass
# Disable resize
self.setFixedSize(self.fixedWidth, self.fixedHeight)
def move_to_primary_center(self):
"""Reposition window to center of primary screen"""
desktop = QDesktopWidget()
primaryScreenIndex = desktop.primaryScreen()
rectScreenPrimarty = desktop.screenGeometry(primaryScreenIndex)
# center in the middle of screen, considering window's own size
self.move(rectScreenPrimarty.center().x() - self.fixedWidth/2,
rectScreenPrimarty.center().y() - self.fixedHeight/2)
def submit(self, parentTray, email, password):
"""Send data to server."""
if not email or not password:
msgBox = QMessageBox()
info_text = []
if not email:
info_text.append('Email cannot be empty!')
if not password:
info_text.append('Password cannot be empty!')
joined_info_text = '\n \n'.join(info_text)
msgBox.setInformativeText(joined_info_text)
msgBox.setIcon(QMessageBox.Information)
msgBox.setWindowTitle("Oops!")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
msgBox.exec()
else:
url = parentTray.createURL('/accounts/login/')
print('Trying to authenticate on', url)
try:
response = self.parent_tray.http_client.post(
url,
headers = {
'X-CSRFToken':self.parent_tray.http_client.cookies.get('csrftoken'),
'Content-Type': 'application/x-www-form-urlencoded'
},
data={
'login' : email,
'password' : password,
'client_public_key' : self.parent_tray.client_rsa.publickey().exportKey(),
'uuid' : parentTray.uuid
}
)
print(parentTray.uuid)
except Exception as e:
print ('No response, server may be down')
if response.status_code != 200:
msgBox = QMessageBox()
msgBox.setInformativeText('Invalid email and/or password')
msgBox.setIcon(QMessageBox.Information)
msgBox.setWindowTitle("Oops!")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
msgBox.exec()
self.show()
return False
else: # if user logged in successfully
parentTray.change_icon_on_login()
parentTray.verify_initial_data()
with open ('last_user' ,'w') as f:
f.write(email)
self.parent_tray.showMessage('Success',
'You are logged in as {}'.format(email),
parentTray.Information,
3000)
self.close()
def cancel(self):
"""Close password input"""
self.close()
答案 0 :(得分:0)
这是一个意见问题,它取决于您希望应用程序架构(前端和后端)的运行方式。
如果我按照django的方式做一些事情作为桌面应用程序的后端,我会把它写成API并使用JWOT身份验证。这样我的身份验证状态就是使用令牌,我可以设置过期限制,每个请求都需要此令牌作为身份验证的形式。
我没有看到表单演示的登录方法,您究竟是如何登录用户并跟踪该状态的?如果您回答这个问题,那么回答退出问题会更容易。
对不起答案,根据StackOverflow的精彩规则,无法发表评论。