595 lines
22 KiB
Python
595 lines
22 KiB
Python
import flet as ft
|
|
import requests
|
|
from helpers.roles import Roles
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
|
|
@dataclass
|
|
class State:
|
|
|
|
file_picker: ft.FilePicker | None = None
|
|
picked_files: list[ft.FilePickerFile] = field(default_factory=list)
|
|
|
|
|
|
state = State()
|
|
|
|
class DocumenteJuridice:
|
|
def __init__(self, page: ft.Page):
|
|
self.page = page
|
|
self.editing_category_id = None
|
|
self.category_id_to_delete = None
|
|
self.document_id_to_delete = None
|
|
self.current_category_id = None
|
|
|
|
self.search_bar = ft.TextField(
|
|
label="Cauta",
|
|
on_submit=self.on_search_bar_submit,
|
|
expand=True
|
|
)
|
|
self.category_name = ft.TextField(
|
|
label="Nume categorie",
|
|
)
|
|
|
|
self.roles_checkboxes = [
|
|
ft.Checkbox(label=role.upper())
|
|
for role in [
|
|
Roles.USER, Roles.PROPRIETAR, Roles.CENZOR,
|
|
Roles.ADMINISTRATOR, Roles.PRESEDINTE, Roles.EXPERT
|
|
]
|
|
]
|
|
|
|
self.access_levels = ft.Column(
|
|
controls=self.roles_checkboxes,
|
|
height=200,
|
|
scroll=ft.ScrollMode.AUTO
|
|
)
|
|
|
|
self.add_categories_dialog = ft.AlertDialog(
|
|
title=ft.Text("Adauga Categorie"),
|
|
content=ft.Column(
|
|
[
|
|
self.category_name,
|
|
ft.Text("Nivele Acces:"),
|
|
self.access_levels
|
|
],
|
|
height=300,
|
|
tight=True
|
|
),
|
|
actions=[
|
|
ft.FilledButton(
|
|
"Salveaza",
|
|
on_click=self.on_save_category_btn_click
|
|
),
|
|
ft.FilledButton(
|
|
"Anuleaza",
|
|
on_click=self.on_cancel_category_btn_click,
|
|
bgcolor=ft.Colors.GREY,
|
|
),
|
|
],
|
|
)
|
|
|
|
self.delete_confirmation_dialog = ft.AlertDialog(
|
|
title=ft.Text("Doriti sa stergeti categoria?"),
|
|
content=ft.Text("Stergerea categoriei implica si stergerea tuturor documentelor din aceasta categorie."),
|
|
actions=[
|
|
ft.FilledButton(
|
|
"Da",
|
|
on_click=self.confirm_delete_category
|
|
),
|
|
ft.FilledButton(
|
|
"Nu",
|
|
bgcolor=ft.Colors.GREY,
|
|
on_click=self.close_delete_dialog
|
|
),
|
|
],
|
|
)
|
|
|
|
self.delete_document_confirmation_dialog = ft.AlertDialog(
|
|
title=ft.Text("Doriti sa stergeti documentul?"),
|
|
content=ft.Text("Aceasta actiune este permanenta."),
|
|
actions=[
|
|
ft.FilledButton(
|
|
"Da",
|
|
on_click=self.confirm_delete_document
|
|
),
|
|
ft.FilledButton(
|
|
"Nu",
|
|
bgcolor=ft.Colors.GREY,
|
|
on_click=self.close_delete_document_dialog
|
|
),
|
|
],
|
|
)
|
|
|
|
self.all_categories = self.get_categories()
|
|
self.category_list = ft.ListView(
|
|
controls=self.create_category_list(
|
|
self.all_categories,
|
|
self.on_edit_category_btn_click,
|
|
self.on_delete_category_btn_click
|
|
),
|
|
spacing=10,
|
|
expand=True
|
|
)
|
|
|
|
self.add_document = ft.Button(
|
|
"Adauga Document",
|
|
icon=ft.Icons.ADD,
|
|
on_click=self.add_new_document
|
|
)
|
|
|
|
self.all_documents = []
|
|
self.documents_list = ft.ListView(
|
|
spacing=10,
|
|
expand=True
|
|
)
|
|
|
|
self.category = ft.Dropdown(
|
|
label="Selectează Categoria",
|
|
options=[
|
|
ft.dropdown.Option(key=str(cat['id']), text=cat['name'])
|
|
for cat in self.all_categories
|
|
]
|
|
)
|
|
|
|
self.documenet_title = None
|
|
self.documenet_displayed_title = ft.TextField(label="Document",read_only=True)
|
|
self.add_new_document_dialog = ft.AlertDialog(
|
|
title=ft.Text("Adauga document"),
|
|
content=ft.Column(
|
|
[
|
|
ft.Row(
|
|
[
|
|
self.documenet_displayed_title,
|
|
ft.Button(
|
|
"Incarca",
|
|
icon=ft.Icons.UPLOAD,
|
|
on_click=self.handle_file_upload
|
|
),
|
|
]
|
|
),
|
|
self.category
|
|
],
|
|
height=160,
|
|
),
|
|
actions=[
|
|
ft.FilledButton(
|
|
"Salveaza",
|
|
on_click=self.on_save_document_btn_click,
|
|
|
|
),
|
|
ft.FilledButton(
|
|
"Anuleaza",
|
|
bgcolor=ft.Colors.GREY,
|
|
on_click=self.on_cancel_save_dialog_btn_click,
|
|
),
|
|
],
|
|
)
|
|
|
|
def on_add_btn_click(self, e):
|
|
self.editing_category_id = None
|
|
self.category_name.value = ""
|
|
for cb in self.roles_checkboxes:
|
|
cb.value = False
|
|
self.add_categories_dialog.title = ft.Text("Adauga Categorie")
|
|
self.page.show_dialog(self.add_categories_dialog)
|
|
self.page.update()
|
|
|
|
def on_save_category_btn_click(self, e):
|
|
category = self.category_name.value
|
|
access = ",".join([cb.label for cb in self.roles_checkboxes if cb.value])
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
|
|
if self.editing_category_id:
|
|
url = f'{base_url}/documents/categories/update/{self.editing_category_id}'
|
|
method = requests.put
|
|
else:
|
|
url = f'{base_url}/documents/categories/add'
|
|
method = requests.post
|
|
|
|
response = method(
|
|
url,
|
|
json={
|
|
"name": category,
|
|
"access": access
|
|
},
|
|
headers = {
|
|
'Authorization': f'Bearer {token}',
|
|
'Content-Type': 'application/json'
|
|
}
|
|
)
|
|
|
|
if response.status_code in [200, 201]:
|
|
self.update_category_list()
|
|
self.category_name.value = None
|
|
self.editing_category_id = None
|
|
self.page.pop_dialog()
|
|
else:
|
|
raise Exception("Operatiuna nu sa putut realiza, token-ul a expirat, va rugam sa va autentificati. Daca eroarea persita contactati echipa de IT!")
|
|
|
|
|
|
def update_category_list(self):
|
|
self.all_categories = self.get_categories()
|
|
self.category_list.controls = self.create_category_list(
|
|
self.all_categories,
|
|
self.on_edit_category_btn_click,
|
|
self.on_delete_category_btn_click
|
|
)
|
|
self.category_list.update()
|
|
|
|
# Actualizăm și opțiunile din dropdown-ul pentru documente
|
|
self.category.options = [
|
|
ft.dropdown.Option(key=str(cat['id']), text=cat['name'])
|
|
for cat in self.all_categories
|
|
]
|
|
|
|
def on_cancel_category_btn_click(self, e):
|
|
self.category_name.value = None
|
|
self.page.pop_dialog()
|
|
|
|
def on_search_bar_submit(self, e):
|
|
# Luăm textul din search bar și îl convertim la litere mici pentru o căutare case-insensitive
|
|
query = self.search_bar.value.strip().lower()
|
|
|
|
# Filtrăm lista de documente stocată în self.all_documents
|
|
if not query:
|
|
filtered_docs = self.all_documents
|
|
else:
|
|
filtered_docs = [
|
|
doc for doc in self.all_documents
|
|
if query in doc['name'].lower()
|
|
]
|
|
|
|
# Actualizăm interfața cu lista filtrată
|
|
self.documents_list.controls = self.create_documents_list(
|
|
filtered_docs,
|
|
lambda doc: self.page.run_task(self.on_download_document_btn_click, doc),
|
|
self.on_delete_document_btn_click
|
|
)
|
|
self.documents_list.update()
|
|
|
|
def add_new_document(self, e):
|
|
self.page.show_dialog(self.add_new_document_dialog)
|
|
|
|
async def handle_file_upload(self, e: ft.Event[ft.Button]):
|
|
print('File uploaded')
|
|
try:
|
|
state.file_picker = ft.FilePicker()
|
|
files = await state.file_picker.pick_files(allow_multiple=False)
|
|
print("Picked file:", files)
|
|
|
|
state.picked_files = files
|
|
uploaded_file_name = f"{datetime.now().strftime('%Y%m%d%H%M%S')}_{state.picked_files[0].name}"
|
|
await state.file_picker.upload(
|
|
files=[
|
|
ft.FilePickerUploadFile(
|
|
name=file.name,
|
|
upload_url=self.page.get_upload_url(uploaded_file_name, 60),
|
|
|
|
)
|
|
|
|
for file in state.picked_files
|
|
]
|
|
)
|
|
self.documenet_title = uploaded_file_name
|
|
self.documenet_displayed_title.value = uploaded_file_name.split("_")[1]
|
|
self.documenet_displayed_title.update()
|
|
return f'{uploaded_file_name}'
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def on_save_document_btn_click(self, e):
|
|
if not self.category.value or not self.documenet_title:
|
|
# Opțional: Poți adăuga un mesaj de eroare vizibil pentru utilizator
|
|
return
|
|
|
|
selected_cat_id = int(self.category.value)
|
|
# Identificăm obiectul categoriei pentru a-i moșteni accesul și numele
|
|
category = next((cat for cat in self.all_categories if cat['id'] == selected_cat_id), None)
|
|
|
|
if not category:
|
|
return
|
|
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
|
|
# Construim path-ul relativ (Categorie/NumeFisier)
|
|
dest_path = f"{category['name']}/{self.documenet_title}"
|
|
|
|
payload = {
|
|
"category_id": selected_cat_id,
|
|
"name": self.documenet_displayed_title.value,
|
|
"path": dest_path,
|
|
"access": category.get('access', '') # Moștenim accesul de la categorie
|
|
}
|
|
|
|
response = requests.post(
|
|
f"{base_url}/documents/standards/add",
|
|
json=payload,
|
|
headers={'Authorization': f'Bearer {token}'}
|
|
)
|
|
|
|
if response.status_code == 201:
|
|
self.page.pop_dialog()
|
|
self.list_all_category_documents(selected_cat_id)
|
|
# Resetăm câmpurile după salvarea cu succes
|
|
self.documenet_title = None
|
|
self.documenet_displayed_title.value = ""
|
|
|
|
def on_cancel_save_dialog_btn_click(self, e):
|
|
self.documenet_title = None
|
|
self.documenet_displayed_title.value = ""
|
|
self.page.pop_dialog()
|
|
|
|
def create_category_list(self, items, on_click_handler, on_click_handler2):
|
|
"""Helper to create list items for a column."""
|
|
return [
|
|
ft.Container(
|
|
content=ft.Row(
|
|
[
|
|
|
|
ft.Row(
|
|
[
|
|
ft.Icon(ft.Icons.ARROW_RIGHT, size=20),
|
|
ft.Text(value=item['name'])
|
|
]
|
|
),
|
|
|
|
ft.Row(
|
|
[
|
|
ft.IconButton(
|
|
icon=ft.Icons.EDIT,
|
|
on_click=lambda e, id=item: on_click_handler(id),
|
|
),
|
|
ft.IconButton(
|
|
icon=ft.Icons.REFRESH,
|
|
on_click=lambda e, id=item['id']: self.on_refresh_category_click(id),
|
|
icon_color=ft.Colors.BLUE_400,
|
|
),
|
|
ft.IconButton(
|
|
icon=ft.Icons.DELETE,
|
|
on_click=lambda e, id=item['id']: on_click_handler2(id),
|
|
icon_color=ft.Colors.RED,
|
|
),
|
|
]
|
|
)
|
|
|
|
],
|
|
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
|
),
|
|
expand=True,
|
|
bgcolor=ft.Colors.BLUE_50,
|
|
border = ft.Border.all(1, ft.Colors.GREY),
|
|
padding=10,
|
|
border_radius=8,
|
|
ink=True,
|
|
on_click=lambda e, cid=item['id']: self.list_all_category_documents(cid)
|
|
)
|
|
for item in items
|
|
]
|
|
|
|
def on_edit_category_btn_click(self, category):
|
|
self.editing_category_id = category['id']
|
|
self.category_name.value = category['name']
|
|
|
|
access_list = category.get('access', '').split(',')
|
|
for cb in self.roles_checkboxes:
|
|
cb.value = cb.label in access_list
|
|
|
|
self.add_categories_dialog.title = ft.Text("Editeaza Categorie")
|
|
self.page.show_dialog(self.add_categories_dialog)
|
|
self.page.update()
|
|
|
|
def on_refresh_category_click(self, category_id):
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
|
|
try:
|
|
response = requests.post(
|
|
f'{base_url}/documents/categories/refresh/{category_id}',
|
|
headers={'Authorization': f'Bearer {token}'}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
added = response.json().get("added", 0)
|
|
# Daca suntem in categoria care s-a improspatat, reincarcam lista de documente
|
|
if self.current_category_id == category_id:
|
|
self.list_all_category_documents(category_id)
|
|
|
|
# Notificare succes
|
|
self.page.snack_bar = ft.SnackBar(
|
|
content=ft.Text(f"Refresh complet. S-au adaugat {added} documente."),
|
|
bgcolor=ft.Colors.GREEN_400
|
|
)
|
|
self.page.snack_bar.open = True
|
|
self.page.update()
|
|
except Exception as e:
|
|
print(f"Error during category refresh: {e}")
|
|
|
|
def on_delete_category_btn_click(self, category_id):
|
|
self.category_id_to_delete = category_id
|
|
self.page.show_dialog(self.delete_confirmation_dialog)
|
|
self.page.update()
|
|
|
|
def confirm_delete_category(self, e):
|
|
if self.category_id_to_delete:
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
|
|
response = requests.delete(
|
|
f'{base_url}/documents/categories/delete/{self.category_id_to_delete}',
|
|
headers={'Authorization': f'Bearer {token}'}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
# Dacă categoria ștearsă este cea ale cărei documente sunt afișate, golim lista
|
|
if self.current_category_id == self.category_id_to_delete:
|
|
self.documents_list.controls = []
|
|
self.documents_list.update()
|
|
self.current_category_id = None
|
|
|
|
self.update_category_list()
|
|
|
|
self.category_id_to_delete = None
|
|
self.page.pop_dialog()
|
|
|
|
def close_delete_dialog(self, e):
|
|
self.category_id_to_delete = None
|
|
self.page.pop_dialog()
|
|
|
|
def get_categories(self):
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
try:
|
|
response = requests.get(
|
|
f'{base_url}/documents/categories',
|
|
headers={'Authorization': f'Bearer {token}'}
|
|
)
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
except Exception as e:
|
|
print(f"Error fetching categories: {e}")
|
|
return []
|
|
|
|
def list_all_category_documents(self, category_id):
|
|
self.current_category_id = category_id
|
|
self.all_documents = self.get_all_documents(category_id) or []
|
|
self.documents_list.controls = self.create_documents_list(
|
|
self.all_documents,
|
|
lambda doc: self.page.run_task(self.on_download_document_btn_click, doc),
|
|
self.on_delete_document_btn_click
|
|
)
|
|
self.documents_list.update()
|
|
|
|
async def on_download_document_btn_click(self, document):
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
# Deschidem link-ul de download în browser
|
|
# path în document este de forma "NumeCategorie/fisier.ext"
|
|
download_url = f"{base_url}/documents/download?path={document['path']}&token={token}"
|
|
await self.page.launch_url(download_url)
|
|
|
|
def on_delete_document_btn_click(self, doc_id):
|
|
self.document_id_to_delete = doc_id
|
|
self.page.show_dialog(self.delete_document_confirmation_dialog)
|
|
self.page.update()
|
|
|
|
def confirm_delete_document(self, e):
|
|
if self.document_id_to_delete:
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
|
|
response = requests.delete(
|
|
f'{base_url}/documents/standards/delete/{self.document_id_to_delete}',
|
|
headers={'Authorization': f'Bearer {token}'}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
if hasattr(self, 'current_category_id'):
|
|
self.list_all_category_documents(self.current_category_id)
|
|
|
|
self.document_id_to_delete = None
|
|
self.page.pop_dialog()
|
|
|
|
def close_delete_document_dialog(self, e):
|
|
self.document_id_to_delete = None
|
|
self.page.pop_dialog()
|
|
|
|
def get_all_documents(self, category_id):
|
|
base_url = self.page.session.store.get('api_base_url')
|
|
token = self.page.session.store.get('token')
|
|
try:
|
|
response = requests.get(
|
|
f'{base_url}/documents/standards/category/{category_id}',
|
|
headers={'Authorization': f'Bearer {token}'}
|
|
)
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
except Exception as e:
|
|
print(f"Error fetching documents: {e}")
|
|
return []
|
|
|
|
def create_documents_list(self, items, on_click_handler, on_click_handler2):
|
|
"""Helper to create list items for a column."""
|
|
return [
|
|
ft.Container(
|
|
content=ft.Row(
|
|
[
|
|
|
|
ft.Row(
|
|
[
|
|
ft.Icon(ft.Icons.ARROW_RIGHT, size=20),
|
|
ft.Text(value=item['name'])
|
|
]
|
|
),
|
|
|
|
ft.Row(
|
|
[
|
|
ft.IconButton(
|
|
icon=ft.Icons.DOWNLOAD,
|
|
on_click=lambda e, id=item: on_click_handler(id),
|
|
),
|
|
ft.IconButton(
|
|
icon=ft.Icons.DELETE,
|
|
on_click=lambda e, id=item['id']: on_click_handler2(id),
|
|
icon_color=ft.Colors.RED,
|
|
),
|
|
]
|
|
)
|
|
|
|
],
|
|
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
|
),
|
|
expand=True,
|
|
bgcolor=ft.Colors.BLUE_50,
|
|
border = ft.Border.all(1, ft.Colors.GREY),
|
|
padding=10,
|
|
border_radius=8
|
|
)
|
|
for item in items
|
|
]
|
|
|
|
def build(self):
|
|
return ft.Container(
|
|
content=ft.Row(
|
|
[
|
|
ft.Column(
|
|
[
|
|
ft.Row(
|
|
[
|
|
ft.Button(
|
|
"Adauga Categori",
|
|
icon=ft.Icons.ADD,
|
|
on_click=self.on_add_btn_click,
|
|
width=300
|
|
),
|
|
],
|
|
alignment=ft.MainAxisAlignment.CENTER
|
|
),
|
|
self.category_list
|
|
],
|
|
alignment=ft.MainAxisAlignment.START,
|
|
width = 350,
|
|
),
|
|
ft.VerticalDivider(width=1),
|
|
ft.Column(
|
|
[
|
|
ft.Row(
|
|
[
|
|
self.add_document
|
|
],
|
|
alignment=ft.MainAxisAlignment.END
|
|
),
|
|
ft.Row(
|
|
[
|
|
self.search_bar
|
|
]
|
|
),
|
|
self.documents_list
|
|
],
|
|
expand=True
|
|
)
|
|
],
|
|
),
|
|
expand=True
|
|
) |