Добавлено сохранение/восстановление токенов
This commit is contained in:
@@ -13,13 +13,13 @@ from drf_yasg import openapi
|
|||||||
from .api import router
|
from .api import router
|
||||||
|
|
||||||
schema_view = get_schema_view(
|
schema_view = get_schema_view(
|
||||||
openapi.Info(
|
openapi.Info(
|
||||||
title="ToDo List",
|
title="ToDo List",
|
||||||
default_version='v1',
|
default_version="v1",
|
||||||
description="Swagger Interface for ToDo List",
|
description="Swagger Interface for ToDo List",
|
||||||
),
|
),
|
||||||
public=True,
|
public=True,
|
||||||
permission_classes=(permissions.AllowAny,),
|
permission_classes=(permissions.AllowAny,),
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -28,5 +28,5 @@ urlpatterns = [
|
|||||||
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
||||||
path("api/", include(router.urls)),
|
path("api/", include(router.urls)),
|
||||||
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
|
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
|
||||||
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
|
path("swagger/", schema_view.with_ui("swagger", cache_timeout=0), name="schema-swagger-ui"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ API_LISTS_UPDATE = "api/lists/{0}/"
|
|||||||
API_LISTS_PARTIAL_UPDATE = "api/lists/{0}/"
|
API_LISTS_PARTIAL_UPDATE = "api/lists/{0}/"
|
||||||
API_LISTS_DELETE = "api/lists/{0}/"
|
API_LISTS_DELETE = "api/lists/{0}/"
|
||||||
|
|
||||||
API_TOKEN = "api/token/"
|
API_TOKEN_CREATE = "api/token/"
|
||||||
|
API_TOKEN_REFRESH = "api/token/refresh/"
|
||||||
|
|
||||||
|
|
||||||
class UserApi(object):
|
class UserApi(object):
|
||||||
@@ -61,11 +62,23 @@ class UserApi(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
token = UserApi._raise_or_return_(
|
token = UserApi._raise_or_return_(
|
||||||
requests.post(url=self.get_api(API_TOKEN), json={"username": user, "password": passwd})
|
requests.post(
|
||||||
|
url=self.get_api(API_TOKEN_CREATE), json={"username": user, "password": passwd}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
self.token = SimpleNamespace(**token)
|
self.token = SimpleNamespace(**token)
|
||||||
return self.token
|
return self.token
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
"""
|
||||||
|
Refresh existing token
|
||||||
|
"""
|
||||||
|
token = UserApi._raise_or_return_(
|
||||||
|
requests.post(url=self.get_api(API_TOKEN_REFRESH), json={"refresh": self.token.refresh})
|
||||||
|
)
|
||||||
|
self.token.access = token["access"]
|
||||||
|
return self.token
|
||||||
|
|
||||||
def lists_list(self, **argv):
|
def lists_list(self, **argv):
|
||||||
"""
|
"""
|
||||||
List all the exsiting to-do lists.
|
List all the exsiting to-do lists.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ DEFAULT_URL = "http://127.0.0.1:8000"
|
|||||||
|
|
||||||
user = User(url=DEFAULT_URL)
|
user = User(url=DEFAULT_URL)
|
||||||
user.auth("root", "root")
|
user.auth("root", "root")
|
||||||
|
user.refresh()
|
||||||
|
|
||||||
# Fetch existing lists:
|
# Fetch existing lists:
|
||||||
print_lists(user.fetchUserLists())
|
print_lists(user.fetchUserLists())
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ class LoginFrame(tk.Frame):
|
|||||||
print(ex)
|
print(ex)
|
||||||
message.invalid_login()
|
message.invalid_login()
|
||||||
|
|
||||||
|
# Если захочется реализовать в логине
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def remember(self):
|
||||||
|
return self.rbtn_var.get()
|
||||||
|
"""
|
||||||
|
|
||||||
def initAUTH(self) -> None:
|
def initAUTH(self) -> None:
|
||||||
"""
|
"""
|
||||||
Создает окно авторизации программы
|
Создает окно авторизации программы
|
||||||
@@ -66,3 +73,16 @@ class LoginFrame(tk.Frame):
|
|||||||
# Кнопка авториазции
|
# Кнопка авториазции
|
||||||
btn = tk.Button(self, text="Войти", command=self.login_clicked)
|
btn = tk.Button(self, text="Войти", command=self.login_clicked)
|
||||||
btn.grid(row=14, column=12, columnspan=3, rowspan=1, sticky="nsew")
|
btn.grid(row=14, column=12, columnspan=3, rowspan=1, sticky="nsew")
|
||||||
|
|
||||||
|
# Если захочется реализовать в логине
|
||||||
|
"""
|
||||||
|
# Запомнить пользователя
|
||||||
|
self.rbtn_var = tk.IntVar(value=0)
|
||||||
|
rbtn = tk.Checkbutton(
|
||||||
|
self,
|
||||||
|
text="Запомнить меня",
|
||||||
|
variable=self.rbtn_var,
|
||||||
|
command=None
|
||||||
|
)
|
||||||
|
rbtn.grid(row=15, column=12, columnspan=3, rowspan=1, sticky="nsew")
|
||||||
|
"""
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import sys
|
|||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from login import LoginFrame
|
from login import LoginFrame
|
||||||
from workspace import WorkSpaceFrame
|
from workspace import WorkSpaceFrame
|
||||||
|
from user import User
|
||||||
|
|
||||||
if "win" in sys.platform.lower():
|
if "win" in sys.platform.lower():
|
||||||
DEFAULT_URL = "http://localhost:8000"
|
DEFAULT_URL = "http://localhost:8000"
|
||||||
@@ -24,11 +25,19 @@ class Application(tk.Tk):
|
|||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
"""Возвращает пользователя - его можно потом сериализовать"""
|
"""Возвращает пользователя - его можно потом сериализовать"""
|
||||||
|
# Пользователь сохранен! Авторизация не нужна!
|
||||||
|
user = User.load()
|
||||||
|
if user is not None:
|
||||||
|
return user
|
||||||
|
# Не удалось - нужен логин
|
||||||
self.frame = LoginFrame(master=self, url=DEFAULT_URL)
|
self.frame = LoginFrame(master=self, url=DEFAULT_URL)
|
||||||
while not self.frame.loggedIn:
|
while not self.frame.loggedIn:
|
||||||
self.update_idletasks()
|
self.update_idletasks()
|
||||||
self.update()
|
self.update()
|
||||||
self.frame.destroy()
|
self.frame.destroy()
|
||||||
|
# Нужно запомнить пользователя
|
||||||
|
# if self.frame.remember:
|
||||||
|
# self.frame.user.save()
|
||||||
return self.frame.user
|
return self.frame.user
|
||||||
|
|
||||||
def main(self, user):
|
def main(self, user):
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
from api import UserApi
|
from api import UserApi
|
||||||
|
|
||||||
@@ -12,6 +15,8 @@ UPDATE_ERROR = "Failed to update property: {0}"
|
|||||||
|
|
||||||
DATETIME_STR = "%Y-%m-%dT%H:%M:%S.%fZ"
|
DATETIME_STR = "%Y-%m-%dT%H:%M:%S.%fZ"
|
||||||
|
|
||||||
|
USER_TOKEN_PATH = os.path.join(Path.home(), ".todo_config.json")
|
||||||
|
|
||||||
|
|
||||||
def bad_arguments(x, d):
|
def bad_arguments(x, d):
|
||||||
return list((set(x) - set(d)))
|
return list((set(x) - set(d)))
|
||||||
@@ -150,7 +155,43 @@ class User(UserApi):
|
|||||||
"""
|
"""
|
||||||
if "DEBUG" in os.environ:
|
if "DEBUG" in os.environ:
|
||||||
return
|
return
|
||||||
UserApi.auth(self, user, passwd)
|
return UserApi.auth(self, user, passwd)
|
||||||
|
|
||||||
|
def remove(self):
|
||||||
|
"""
|
||||||
|
Remove the login file from homedir
|
||||||
|
"""
|
||||||
|
if not os.path.exists(USER_TOKEN_PATH):
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
os.remove(USER_TOKEN_PATH)
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError("Failed to remove tokens:", e)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
"""
|
||||||
|
Store user token in homedir
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(USER_TOKEN_PATH, "w") as handler:
|
||||||
|
json.dump(self.token.__dict__, handler)
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError("Failed to store tokens:", e)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load():
|
||||||
|
"""
|
||||||
|
Restore user token from the file in homedir
|
||||||
|
"""
|
||||||
|
if os.path.exists(USER_TOKEN_PATH):
|
||||||
|
try:
|
||||||
|
with open(USER_TOKEN_PATH, "r") as handler:
|
||||||
|
user = User(token=SimpleNamespace(**json.load(handler)))
|
||||||
|
user.refresh()
|
||||||
|
return user
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError("Failed to restore tokens:", e)
|
||||||
|
return None
|
||||||
|
|
||||||
# Storing lists - mostly for debug purposes
|
# Storing lists - mostly for debug purposes
|
||||||
lists_ = make_debug_lists()
|
lists_ = make_debug_lists()
|
||||||
|
|||||||
@@ -118,8 +118,20 @@ class WorkSpaceFrame(tk.Frame):
|
|||||||
self.pack(fill=tk.BOTH, expand=1)
|
self.pack(fill=tk.BOTH, expand=1)
|
||||||
self.initLayout(user)
|
self.initLayout(user)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
tk.Tk.destroy(self)
|
||||||
|
if self.rbtn_var.get() > 0:
|
||||||
|
self.user.save()
|
||||||
|
else:
|
||||||
|
self.user.remove()
|
||||||
|
|
||||||
def initLayout(self, user):
|
def initLayout(self, user):
|
||||||
|
|
||||||
|
# Запомнить пользователя
|
||||||
|
self.rbtn_var = tk.IntVar(value=1)
|
||||||
|
rbtn = tk.Checkbutton(self, text="Запомнить меня", variable=self.rbtn_var, command=None)
|
||||||
|
rbtn.pack(anchor="n")
|
||||||
|
|
||||||
# data
|
# data
|
||||||
self.lists = user.fetchUserLists()
|
self.lists = user.fetchUserLists()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user