Folder info and permissions
This commit is contained in:
parent
37940d633a
commit
4c01ca7510
@ -83,7 +83,7 @@ class RegisterWidget(QWidget):
|
|||||||
|
|
||||||
|
|
||||||
class LoginWidget(QWidget):
|
class LoginWidget(QWidget):
|
||||||
def __init__(self, switcher: State):
|
def __init__(self, switcher: state.State):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.switcher = switcher
|
self.switcher = switcher
|
||||||
@ -116,7 +116,9 @@ class LoginWidget(QWidget):
|
|||||||
password = self.password_input.text()
|
password = self.password_input.text()
|
||||||
|
|
||||||
if not username or not password:
|
if not username or not password:
|
||||||
QMessageBox.warning(self, "Input Error", "Email and Password are required")
|
QMessageBox.warning(
|
||||||
|
self, "Input Error", "Email and Password are required"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -129,8 +131,12 @@ class LoginWidget(QWidget):
|
|||||||
if access_token:
|
if access_token:
|
||||||
self.switcher.login(access_token)
|
self.switcher.login(access_token)
|
||||||
else:
|
else:
|
||||||
QMessageBox.warning(self, "Error", "No access token received")
|
QMessageBox.warning(
|
||||||
|
self, "Error", "No access token received"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
QMessageBox.warning(self, "Error", f"Login failed: {response.text}")
|
QMessageBox.warning(
|
||||||
|
self, "Error", f"Login failed: {response.text}"
|
||||||
|
)
|
||||||
except httpx.HTTPError as e:
|
except httpx.HTTPError as e:
|
||||||
QMessageBox.critical(self, "HTTP Error", str(e))
|
QMessageBox.critical(self, "HTTP Error", str(e))
|
||||||
|
@ -7,12 +7,19 @@ import uuid
|
|||||||
from typing import Protocol, Self
|
from typing import Protocol, Self
|
||||||
|
|
||||||
import create_folder_widget
|
import create_folder_widget
|
||||||
|
import folder_info
|
||||||
import httpx
|
import httpx
|
||||||
import pydantic
|
import pydantic
|
||||||
import state
|
import state
|
||||||
import user
|
import user
|
||||||
from PyQt6.QtCore import QPoint, Qt
|
from PyQt6.QtCore import QPoint, Qt
|
||||||
from PyQt6.QtGui import QAction, QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon
|
from PyQt6.QtGui import (
|
||||||
|
QAction,
|
||||||
|
QDragEnterEvent,
|
||||||
|
QDragMoveEvent,
|
||||||
|
QDropEvent,
|
||||||
|
QIcon,
|
||||||
|
)
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QFileDialog,
|
QFileDialog,
|
||||||
QHBoxLayout,
|
QHBoxLayout,
|
||||||
@ -57,7 +64,9 @@ class File(pydantic.BaseModel):
|
|||||||
return self.file_name
|
return self.file_name
|
||||||
|
|
||||||
def delete(self) -> None:
|
def delete(self) -> None:
|
||||||
RequestClient().client.delete("/files", params={"file_id": self.file_id})
|
RequestClient().client.delete(
|
||||||
|
"/files", params={"file_id": self.file_id}
|
||||||
|
)
|
||||||
|
|
||||||
def details(self, list: FileListWidget) -> QWidget:
|
def details(self, list: FileListWidget) -> QWidget:
|
||||||
del list
|
del list
|
||||||
@ -114,15 +123,14 @@ class Folder(pydantic.BaseModel):
|
|||||||
return self.folder_name
|
return self.folder_name
|
||||||
|
|
||||||
def delete(self) -> None:
|
def delete(self) -> None:
|
||||||
print(
|
response = RequestClient().client.delete(
|
||||||
RequestClient()
|
"/folders", params={"folder_id": self.folder_id}
|
||||||
.client.delete("/folders", params={"folder_id": self.folder_id})
|
|
||||||
.text
|
|
||||||
)
|
)
|
||||||
|
if not response:
|
||||||
|
QMessageBox.warning(None, "Error deleting folder", response.text)
|
||||||
|
|
||||||
def details(self, list: FileListWidget) -> QWidget:
|
def details(self, list: FileListWidget) -> QWidget:
|
||||||
# TODO
|
return folder_info.FolderInfoWidget(self)
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def icon(self) -> QIcon:
|
def icon(self) -> QIcon:
|
||||||
return QIcon("assets/folder.png")
|
return QIcon("assets/folder.png")
|
||||||
@ -164,7 +172,9 @@ class ListResponse(pydantic.BaseModel):
|
|||||||
return self.get(self.folder_id)
|
return self.get(self.folder_id)
|
||||||
|
|
||||||
def create_folder(self, file_list: FileListWidget):
|
def create_folder(self, file_list: FileListWidget):
|
||||||
return create_folder_widget.CreateFolderWidget(self.folder_id, file_list)
|
return create_folder_widget.CreateFolderWidget(
|
||||||
|
self.folder_id, file_list
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(slots=True)
|
@dataclasses.dataclass(slots=True)
|
||||||
@ -186,7 +196,7 @@ class TlpResponse:
|
|||||||
def update(self) -> ResponseProtocol:
|
def update(self) -> ResponseProtocol:
|
||||||
return self.get()
|
return self.get()
|
||||||
|
|
||||||
def create_folder(self):
|
def create_folder(self, _: FileListWidget):
|
||||||
return # Not much to do
|
return # Not much to do
|
||||||
|
|
||||||
|
|
||||||
@ -228,7 +238,6 @@ class FileListWidget(QListWidget):
|
|||||||
|
|
||||||
def dropEvent(self, event: QDropEvent):
|
def dropEvent(self, event: QDropEvent):
|
||||||
event.accept()
|
event.accept()
|
||||||
print("hi")
|
|
||||||
for url in event.mimeData().urls():
|
for url in event.mimeData().urls():
|
||||||
file_path = url.toLocalFile()
|
file_path = url.toLocalFile()
|
||||||
self.upload_file(file_path)
|
self.upload_file(file_path)
|
||||||
@ -241,7 +250,9 @@ class FileListWidget(QListWidget):
|
|||||||
response = RequestClient().client.post(
|
response = RequestClient().client.post(
|
||||||
"http://localhost:3000/files",
|
"http://localhost:3000/files",
|
||||||
files=files,
|
files=files,
|
||||||
params={"parent_folder": self.current_response().folder_id},
|
params={
|
||||||
|
"parent_folder": self.current_response().folder_id
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if response.is_success:
|
if response.is_success:
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
@ -283,7 +294,6 @@ class FileListWidget(QListWidget):
|
|||||||
item = self.current_response().items()[row]
|
item = self.current_response().items()[row]
|
||||||
item.delete()
|
item.delete()
|
||||||
self.update_response()
|
self.update_response()
|
||||||
QMessageBox.information(self, "Delete", f"{item.name()} deleted")
|
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
self.clear()
|
self.clear()
|
||||||
|
152
desktop_client/folder_info.py
Normal file
152
desktop_client/folder_info.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from request_client import RequestClient
|
||||||
|
import enum
|
||||||
|
import file_widgets
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QWidget,
|
||||||
|
QMessageBox,
|
||||||
|
QLabel,
|
||||||
|
QPushButton,
|
||||||
|
QComboBox,
|
||||||
|
QHBoxLayout,
|
||||||
|
QVBoxLayout,
|
||||||
|
QLineEdit,
|
||||||
|
)
|
||||||
|
import pydantic
|
||||||
|
from functools import cache, partial
|
||||||
|
import user
|
||||||
|
|
||||||
|
|
||||||
|
class Permission(enum.StrEnum):
|
||||||
|
read = enum.auto()
|
||||||
|
write = enum.auto()
|
||||||
|
manage = enum.auto()
|
||||||
|
|
||||||
|
def set(self, folder_id: uuid.UUID, user_id: int):
|
||||||
|
response = RequestClient().client.post(
|
||||||
|
"/permissions",
|
||||||
|
json={
|
||||||
|
"folder_id": str(folder_id),
|
||||||
|
"permission_type": str(self),
|
||||||
|
"user_id": int(user_id),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if not response.is_success:
|
||||||
|
QMessageBox.warning(
|
||||||
|
None, "Error setting permissions", response.text
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete(folder_id: uuid.UUID, user_id: int, widget: FolderInfoWidget):
|
||||||
|
response = RequestClient().client.delete(
|
||||||
|
"/permissions",
|
||||||
|
params={
|
||||||
|
"folder_id": folder_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if not response.is_success:
|
||||||
|
QMessageBox.warning(
|
||||||
|
None, "Error deleting permissions", response.text
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
widget.redraw()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True)
|
||||||
|
class Permissions:
|
||||||
|
mapping: dict[int, Permission]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(folder_id: uuid.UUID) -> Permissions:
|
||||||
|
mapping = pydantic.TypeAdapter(dict[str, Permission]).validate_json(
|
||||||
|
RequestClient()
|
||||||
|
.client.get("/permissions", params={"folder_id": folder_id})
|
||||||
|
.text
|
||||||
|
)
|
||||||
|
return Permissions(mapping)
|
||||||
|
|
||||||
|
|
||||||
|
class FolderInfoWidget(QWidget):
|
||||||
|
def __init__(self, folder: file_widgets.Folder):
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Folder info")
|
||||||
|
self.folder = folder
|
||||||
|
self.user_cache = cache(user.User.get)
|
||||||
|
self.user_mapping: dict[str, int] = {}
|
||||||
|
self.redraw()
|
||||||
|
|
||||||
|
def redraw(self):
|
||||||
|
self.permissions = Permissions.get(self.folder.folder_id)
|
||||||
|
main_layout = QVBoxLayout()
|
||||||
|
|
||||||
|
owner_name = self.user_cache(self.folder.owner_id)
|
||||||
|
main_layout.addWidget(
|
||||||
|
QLabel(
|
||||||
|
f"Owner: {owner_name}\n"
|
||||||
|
+ f"Folder name: {self.folder.folder_name}\n"
|
||||||
|
+ f"Created at: {self.folder.created_at}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for user_id, permissions in self.permissions.mapping.items():
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
name = QLabel(self.user_cache(user_id).username)
|
||||||
|
combo = QComboBox()
|
||||||
|
combo.addItems(map(str, Permission))
|
||||||
|
combo.setCurrentText(str(permissions))
|
||||||
|
combo.currentTextChanged.connect(
|
||||||
|
partial(self.change, user_id=user_id)
|
||||||
|
)
|
||||||
|
delete = QPushButton("Delete")
|
||||||
|
delete.clicked.connect(
|
||||||
|
partial(
|
||||||
|
Permission.delete, self.folder.folder_id, user_id, self
|
||||||
|
)
|
||||||
|
)
|
||||||
|
layout.addWidget(name)
|
||||||
|
layout.addWidget(combo)
|
||||||
|
layout.addWidget(delete)
|
||||||
|
main_layout.addLayout(layout)
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
self.search_str = QLineEdit()
|
||||||
|
layout.addWidget(self.search_str)
|
||||||
|
search = QPushButton("Search")
|
||||||
|
search.clicked.connect(self.search)
|
||||||
|
layout.addWidget(search)
|
||||||
|
main_layout.addLayout(layout)
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
self.search_combo = QComboBox()
|
||||||
|
self.perm_combo = QComboBox()
|
||||||
|
self.perm_combo.addItems(map(str, Permission))
|
||||||
|
button = QPushButton("+")
|
||||||
|
button.clicked.connect(self.search_save)
|
||||||
|
layout.addWidget(self.search_combo)
|
||||||
|
layout.addWidget(self.perm_combo)
|
||||||
|
layout.addWidget(button)
|
||||||
|
main_layout.addLayout(layout)
|
||||||
|
|
||||||
|
if self.layout():
|
||||||
|
QWidget().setLayout(self.layout())
|
||||||
|
self.setLayout(main_layout)
|
||||||
|
|
||||||
|
def change(self, text: str, *, user_id: int):
|
||||||
|
Permission(text).set(self.folder.folder_id, user_id)
|
||||||
|
|
||||||
|
def search(self):
|
||||||
|
result = user.UserSearch.search(self.search_str.text())
|
||||||
|
self.search_combo.clear()
|
||||||
|
self.user_mapping.clear()
|
||||||
|
for item in result:
|
||||||
|
self.user_mapping[item.username] = item.user_id
|
||||||
|
self.search_combo.addItem(item.username)
|
||||||
|
|
||||||
|
def search_save(self):
|
||||||
|
permission = Permission(self.perm_combo.currentText())
|
||||||
|
user_id = self.user_mapping[self.search_combo.currentText()]
|
||||||
|
permission.set(self.folder.folder_id, user_id)
|
||||||
|
self.redraw()
|
@ -27,9 +27,13 @@ class User(pydantic.BaseModel):
|
|||||||
params["user_id"] = user_id
|
params["user_id"] = user_id
|
||||||
else:
|
else:
|
||||||
url = "/users/current"
|
url = "/users/current"
|
||||||
return User.model_validate_json(
|
response = RequestClient().client.get(url, params=params)
|
||||||
RequestClient().client.get(url, params=params).text
|
if not response.is_success:
|
||||||
)
|
QMessageBox.warning(
|
||||||
|
None, "Error getting permissions", response.text
|
||||||
|
)
|
||||||
|
return
|
||||||
|
return User.model_validate_json(response.text)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete():
|
def delete():
|
||||||
|
Reference in New Issue
Block a user