Frontend basics
This commit is contained in:
parent
8565ce19fe
commit
e310930d9e
10 changed files with 607 additions and 58 deletions
3
app/web/__init__.py
Normal file
3
app/web/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from .passwords import PasswordsController
|
||||
|
||||
__all__ = ["PasswordsController"]
|
||||
138
app/web/passwords.py
Normal file
138
app/web/passwords.py
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
from typing import Optional, List
|
||||
|
||||
from pykeepass import Group, Entry
|
||||
|
||||
from app.api.models import EntryKind, EntrySimpleDTO, EntryComplexDTO, GroupDTO, NodeDTO, EntryNodeDTO
|
||||
from app.services import Passwords
|
||||
|
||||
|
||||
class PasswordsController:
|
||||
def __init__(self, passwords: Passwords):
|
||||
self._pw = passwords
|
||||
|
||||
@staticmethod
|
||||
def dep() -> "PasswordsController":
|
||||
# prosta fabryka/DI mostkująca injectable
|
||||
return PasswordsController(Passwords())
|
||||
|
||||
# Helpers
|
||||
def _group_by_path(self, path: Optional[str]) -> Group:
|
||||
if not path or path == "/":
|
||||
return self._pw.kp.root_group
|
||||
parts = [p for p in path.split("/") if p]
|
||||
g = self._pw.kp.root_group
|
||||
for p in parts:
|
||||
g = next((x for x in g.subgroups if x.name == p), None)
|
||||
if g is None:
|
||||
raise ValueError(f"Group not found: {path}")
|
||||
return g
|
||||
|
||||
def _ensure_group(self, parent: Group, name: str) -> Group:
|
||||
g = next((x for x in parent.subgroups if x.name == name), None)
|
||||
if g:
|
||||
return g
|
||||
return self._pw.kp.add_group(parent, name)
|
||||
|
||||
def _entry_by_path(self, path: str) -> Entry:
|
||||
# path: /Group1/Sub/Title
|
||||
parts = [p for p in path.split("/") if p]
|
||||
if not parts:
|
||||
raise ValueError("Invalid entry path")
|
||||
title = parts[-1]
|
||||
group_path = "/" + "/".join(parts[:-1]) if len(parts) > 1 else "/"
|
||||
g = self._group_by_path(group_path)
|
||||
e = next((x for x in g.entries if x.title == title), None)
|
||||
if not e:
|
||||
raise ValueError(f"Entry not found: {path}")
|
||||
return e
|
||||
|
||||
def _node_of_group(self, g: Group) -> NodeDTO:
|
||||
def group_path(gr: Group) -> str:
|
||||
names: List[str] = []
|
||||
cur = gr
|
||||
while cur and cur.name:
|
||||
names.append(cur.name)
|
||||
cur = cur.parent
|
||||
names.reverse()
|
||||
return "/" + "/".join(names) if names else "/"
|
||||
|
||||
path = group_path(g)
|
||||
groups = [self._node_of_group(sg) for sg in g.subgroups]
|
||||
entries = [EntryNodeDTO(
|
||||
kind=EntryKind.complex if (e.username or e.url or e.notes) else EntryKind.simple,
|
||||
title=e.title,
|
||||
path=path.rstrip("/") + "/" + e.title
|
||||
) for e in g.entries]
|
||||
return NodeDTO(name=g.name or "", path=path, groups=groups, entries=entries)
|
||||
|
||||
# Tree
|
||||
def get_tree(self) -> NodeDTO:
|
||||
return self._node_of_group(self._pw.kp.root_group)
|
||||
|
||||
# Groups
|
||||
def create_group(self, name: str, parent_path: Optional[str]) -> GroupDTO:
|
||||
parent = self._group_by_path(parent_path)
|
||||
g = self._ensure_group(parent, name)
|
||||
return GroupDTO(name=g.name, path=self._node_of_group(g).path)
|
||||
|
||||
def rename_group(self, path: str, new_name: str) -> GroupDTO:
|
||||
g = self._group_by_path(path)
|
||||
g.name = new_name
|
||||
return GroupDTO(name=g.name, path=self._node_of_group(g).path)
|
||||
|
||||
def delete_group(self, path: str) -> None:
|
||||
g = self._group_by_path(path)
|
||||
if g is self._pw.kp.root_group:
|
||||
raise ValueError("Cannot delete root group")
|
||||
self._pw.kp.delete_group(g)
|
||||
|
||||
# Entries
|
||||
def create_entry_simple(self, parent_path: str, dto: EntrySimpleDTO) -> NodeDTO:
|
||||
parent = self._group_by_path(parent_path)
|
||||
title = dto.key
|
||||
password = dto.value
|
||||
self._pw.kp.add_entry(parent, title=title, username="", password=password)
|
||||
return self._node_of_group(parent)
|
||||
|
||||
def create_entry_complex(self, parent_path: str, dto: EntryComplexDTO) -> NodeDTO:
|
||||
parent = self._group_by_path(parent_path)
|
||||
self._pw.kp.add_entry(
|
||||
parent,
|
||||
title=dto.title,
|
||||
username=dto.username or "",
|
||||
password=dto.password or "",
|
||||
url=dto.url or "",
|
||||
notes=dto.notes or "",
|
||||
)
|
||||
return self._node_of_group(parent)
|
||||
|
||||
def update_entry_simple(self, path: str, dto: EntrySimpleDTO) -> NodeDTO:
|
||||
e = self._entry_by_path(path)
|
||||
parent = e.group
|
||||
e.title = dto.key
|
||||
e.password = dto.value
|
||||
return self._node_of_group(parent)
|
||||
|
||||
def update_entry_complex(self, path: str, dto: EntryComplexDTO) -> NodeDTO:
|
||||
e = self._entry_by_path(path)
|
||||
parent = e.group
|
||||
e.title = dto.title
|
||||
e.username = dto.username
|
||||
e.password = dto.password
|
||||
e.url = dto.url or ""
|
||||
e.notes = dto.notes or ""
|
||||
return self._node_of_group(parent)
|
||||
|
||||
def move_entry(self, path: str, target_group_path: str) -> NodeDTO:
|
||||
e = self._entry_by_path(path)
|
||||
target = self._group_by_path(target_group_path)
|
||||
self._pw.kp.move_entry(e, target)
|
||||
return self._node_of_group(target)
|
||||
|
||||
def delete_entry(self, path: str) -> None:
|
||||
e = self._entry_by_path(path)
|
||||
self._pw.kp.delete_entry(e)
|
||||
|
||||
# Persist
|
||||
def save(self):
|
||||
self._pw.save()
|
||||
Loading…
Add table
Add a link
Reference in a new issue