Folder info and permissions
This commit is contained in:
		@@ -83,7 +83,7 @@ class RegisterWidget(QWidget):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LoginWidget(QWidget):
 | 
			
		||||
    def __init__(self, switcher: State):
 | 
			
		||||
    def __init__(self, switcher: state.State):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
 | 
			
		||||
        self.switcher = switcher
 | 
			
		||||
@@ -116,7 +116,9 @@ class LoginWidget(QWidget):
 | 
			
		||||
        password = self.password_input.text()
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
@@ -129,8 +131,12 @@ class LoginWidget(QWidget):
 | 
			
		||||
                if access_token:
 | 
			
		||||
                    self.switcher.login(access_token)
 | 
			
		||||
                else:
 | 
			
		||||
                    QMessageBox.warning(self, "Error", "No access token received")
 | 
			
		||||
                    QMessageBox.warning(
 | 
			
		||||
                        self, "Error", "No access token received"
 | 
			
		||||
                    )
 | 
			
		||||
            else:
 | 
			
		||||
                QMessageBox.warning(self, "Error", f"Login failed: {response.text}")
 | 
			
		||||
                QMessageBox.warning(
 | 
			
		||||
                    self, "Error", f"Login failed: {response.text}"
 | 
			
		||||
                )
 | 
			
		||||
        except httpx.HTTPError as e:
 | 
			
		||||
            QMessageBox.critical(self, "HTTP Error", str(e))
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,19 @@ import uuid
 | 
			
		||||
from typing import Protocol, Self
 | 
			
		||||
 | 
			
		||||
import create_folder_widget
 | 
			
		||||
import folder_info
 | 
			
		||||
import httpx
 | 
			
		||||
import pydantic
 | 
			
		||||
import state
 | 
			
		||||
import user
 | 
			
		||||
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 (
 | 
			
		||||
    QFileDialog,
 | 
			
		||||
    QHBoxLayout,
 | 
			
		||||
@@ -57,7 +64,9 @@ class File(pydantic.BaseModel):
 | 
			
		||||
        return self.file_name
 | 
			
		||||
 | 
			
		||||
    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:
 | 
			
		||||
        del list
 | 
			
		||||
@@ -114,15 +123,14 @@ class Folder(pydantic.BaseModel):
 | 
			
		||||
        return self.folder_name
 | 
			
		||||
 | 
			
		||||
    def delete(self) -> None:
 | 
			
		||||
        print(
 | 
			
		||||
            RequestClient()
 | 
			
		||||
            .client.delete("/folders", params={"folder_id": self.folder_id})
 | 
			
		||||
            .text
 | 
			
		||||
        response = RequestClient().client.delete(
 | 
			
		||||
            "/folders", params={"folder_id": self.folder_id}
 | 
			
		||||
        )
 | 
			
		||||
        if not response:
 | 
			
		||||
            QMessageBox.warning(None, "Error deleting folder", response.text)
 | 
			
		||||
 | 
			
		||||
    def details(self, list: FileListWidget) -> QWidget:
 | 
			
		||||
        # TODO
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
        return folder_info.FolderInfoWidget(self)
 | 
			
		||||
 | 
			
		||||
    def icon(self) -> QIcon:
 | 
			
		||||
        return QIcon("assets/folder.png")
 | 
			
		||||
@@ -164,7 +172,9 @@ class ListResponse(pydantic.BaseModel):
 | 
			
		||||
        return self.get(self.folder_id)
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
@@ -186,7 +196,7 @@ class TlpResponse:
 | 
			
		||||
    def update(self) -> ResponseProtocol:
 | 
			
		||||
        return self.get()
 | 
			
		||||
 | 
			
		||||
    def create_folder(self):
 | 
			
		||||
    def create_folder(self, _: FileListWidget):
 | 
			
		||||
        return  # Not much to do
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -228,7 +238,6 @@ class FileListWidget(QListWidget):
 | 
			
		||||
 | 
			
		||||
    def dropEvent(self, event: QDropEvent):
 | 
			
		||||
        event.accept()
 | 
			
		||||
        print("hi")
 | 
			
		||||
        for url in event.mimeData().urls():
 | 
			
		||||
            file_path = url.toLocalFile()
 | 
			
		||||
            self.upload_file(file_path)
 | 
			
		||||
@@ -241,7 +250,9 @@ class FileListWidget(QListWidget):
 | 
			
		||||
                response = RequestClient().client.post(
 | 
			
		||||
                    "http://localhost:3000/files",
 | 
			
		||||
                    files=files,
 | 
			
		||||
                    params={"parent_folder": self.current_response().folder_id},
 | 
			
		||||
                    params={
 | 
			
		||||
                        "parent_folder": self.current_response().folder_id
 | 
			
		||||
                    },
 | 
			
		||||
                )
 | 
			
		||||
                if response.is_success:
 | 
			
		||||
                    QMessageBox.information(
 | 
			
		||||
@@ -283,7 +294,6 @@ class FileListWidget(QListWidget):
 | 
			
		||||
        item = self.current_response().items()[row]
 | 
			
		||||
        item.delete()
 | 
			
		||||
        self.update_response()
 | 
			
		||||
        QMessageBox.information(self, "Delete", f"{item.name()} deleted")
 | 
			
		||||
 | 
			
		||||
    def update(self) -> None:
 | 
			
		||||
        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
 | 
			
		||||
        else:
 | 
			
		||||
            url = "/users/current"
 | 
			
		||||
        return User.model_validate_json(
 | 
			
		||||
            RequestClient().client.get(url, params=params).text
 | 
			
		||||
        )
 | 
			
		||||
        response = RequestClient().client.get(url, params=params)
 | 
			
		||||
        if not response.is_success:
 | 
			
		||||
            QMessageBox.warning(
 | 
			
		||||
                None, "Error getting permissions", response.text
 | 
			
		||||
            )
 | 
			
		||||
            return
 | 
			
		||||
        return User.model_validate_json(response.text)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def delete():
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user