managefile.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. from django.shortcuts import render
  2. from django.http import HttpResponse,HttpResponseRedirect,FileResponse
  3. from django.urls import reverse
  4. from django.db import IntegrityError
  5. from .models import *
  6. from config.views import *
  7. from att.views import *
  8. from django.conf import settings
  9. from django.conf.urls.static import static
  10. from django.contrib.auth import authenticate
  11. import mimetypes
  12. from random import randint
  13. import csv
  14. import time
  15. import datetime
  16. import zipfile
  17. import re
  18. #pip install python-codicefiscale
  19. from codicefiscale import codicefiscale
  20. import os
  21. # come sono gestiti i file nella configurazione:
  22. # MEDIA_ROOT=os.path.join(settings.BASE_DIR,'static/upload')
  23. # che diventa = os.path.join(settings.BASE_DIR,getConfig('DocPath'))
  24. # inoltre devo aver fatto qualche casino oggi 9.8.24 con i copia e incolla. ho dovuto rivedere tutto il file
  25. # il terrore si impossessa di me. sta storia del cvs non e' esattamente chiara
  26. # questo blocco rimuove fisicamente il file prima della sua rimozione logica nel db
  27. def delete_file(documento):
  28. file_path = os.path.join(settings.BASE_DIR,getConfig('DocPath'),documento.utente.azienda.partitaiva,documento.utente.codicefiscale,documento.storage)
  29. print('Path completa:',file_path)
  30. if os.path.isfile(file_path):
  31. print('rimozione fisica file:',file_path)
  32. try:
  33. os.remove(file_path)
  34. except OSError as ose:
  35. print('errore nella rimozione del file:',ose)
  36. # impacchetta il file e procede a fornire il file via web
  37. def download_file(request,uid):
  38. utente = Utenti.objects.get(pk=uid)
  39. file_path = os.path.join(settings.BASE_DIR,getConfig('DocPath'),documento.utente.azienda.partitaiva,documento.utente.codicefiscale,utente.storage)
  40. print('Path completa da Basedir:',file_path)
  41. if utente.storage and os.path.isfile(file_path):
  42. try:
  43. fl = open(file_path, 'rb')
  44. except Exception as er:
  45. print('errore',er)
  46. data=dict()
  47. data['errore']="File non esistente o non ancora disponibile"
  48. data['utente'] = utente
  49. return render(request,'documento.error.html',data)
  50. else:
  51. print('il file non esiste',file_path)
  52. data=dict()
  53. data['errore']='File non esistente o non ancora disponibile'
  54. data['utente'] = utente
  55. return render(request,'documento.error.html',data)
  56. mime_type, _ = mimetypes.guess_type(file_path)
  57. print('file',file_path,mime_type)
  58. response = FileResponse(open(file_path,'rb'),content_type='application/pdf',as_attachment=False)
  59. #response['Content-Disposition'] = "attachment; filename=%s" % u.documento
  60. return response
  61. # upload file
  62. # procedura singolo file per singolo utente
  63. def upload_file(uploaded_file,utente,originale=False):
  64. stored_file = ''.join((str(time.time()),'.saved'))
  65. fl_path = os.path.join(settings.BASE_DIR,getConfig('DocPath'))
  66. print('nome file',uploaded_file.name,stored_file)
  67. #modifico il file per dire alla funzione superiore se il file e' stato caricato o meno
  68. nomefile=None
  69. if originale:
  70. nomefile = uploaded_file.name
  71. else:
  72. nomefile = stored_file
  73. # vediamo se caricare o meno.
  74. # in questo caso, se il documento esiste gia', non lo carica.
  75. # come facciamo a stabilire se il documento esiste gia'?
  76. # fl_path = corrisponde a media.ROOT (che mi domando se non e' il caso di spostarlo nella configurazione)
  77. # azienda.partitaiva
  78. # utente.codicefiscale (prima era "record" e mi sono deciso a cambiarlo)
  79. try:
  80. print('posizione partitaiva',os.path.join(fl_path,utente.azienda.partitaiva))
  81. os.mkdir(os.path.join(fl_path,utente.azienda.partitaiva))
  82. except FileExistsError as fee:
  83. print('posizione partitaiva',os.path.join(fl_path,utente.azienda.partitaiva),"esistente")
  84. try:
  85. print("posizione partitaiva codicefiscale",os.path.join(fl_path,utente.azienda.partitaiva,utente.codicefiscale))
  86. os.mkdir(os.path.join(fl_path,utente.azienda.partitaiva,utente.codicefiscale))
  87. except FileExistsError as fee:
  88. print("posizione partitaiva codicefiscale",os.path.join(fl_path,utente.azienda.partitaiva,utente.codicefiscale),"esistente")
  89. with open(os.path.join(fl_path,utente.azienda.partitaiva,utente.codicefiscale,nomefile),'wb+') as d:
  90. for chunk in uploaded_file.chunks():
  91. d.write(chunk)
  92. if originale:
  93. # viene richiesto il file originale piuttosto cheil file codificato con il timing
  94. print("viene restituito il file originale",os.path.join(fl_path,utente.azienda.partitaiva,utente.codicefiscale,nomefile))
  95. return os.path.join(fl_path,utente.azienda.partitaiva,utente.codicefiscale,nomefile)
  96. print("viene restituito il file rinominato",os.path.join(fl_path,utente.azienda.partitaiva,utente.codicefiscale,nomefile))
  97. return stored_file
  98. # caricamento file indice (gestito in modo diverso)
  99. def upload_file_indice(uploaded_file):
  100. stored_file = ''.join((str(time.time()),'.saved'))
  101. fl_path = os.path.join(settings.BASE_DIR,getConfig('DocPath'),getConfig('DocPathIndex'))
  102. print('nome file',uploaded_file.name,stored_file)
  103. # verifica l'esistenza della directory
  104. try:
  105. os.mkdir(fl_path)
  106. except FileExistsError as fee:
  107. print(fl_path,"esistente")
  108. print('file_memorizzato',os.path.join(fl_path,stored_file))
  109. with open(os.path.join(fl_path,stored_file),'wb+') as d:
  110. for chunk in uploaded_file.chunks():
  111. d.write(chunk)
  112. return stored_file
  113. # sposta directory sulla base del codicefiscale aggiornato
  114. def rename_dir(utente,old,new):
  115. fl_path = os.path.join(settings.BASE_DIR,getConfig('DocPath'))
  116. try:
  117. print("posizione partitaiva codicefiscale",os.path.join(fl_path,utente.azienda.partitaiva,old))
  118. os.rename(os.path.join(fl_path,utente.azienda.partitaiva,old),os.path.join(fl_path,utente.azienda.partitaiva,new))
  119. except FileExistsError as fee:
  120. print("posizione partitaiva codicefiscale old",os.path.join(fl_path,utente.azienda.partitaiva,old))
  121. print("posizione partitaiva codicefiscale new",os.path.join(fl_path,utente.azienda.partitaiva,new),"esistente")
  122. return False
  123. except FileNotFoundError as fnfe:
  124. print('non trovo la directory da rinominare')
  125. return False
  126. except OSError as ose:
  127. print('errore generico')
  128. print(ose)
  129. return False
  130. return True
  131. # il file caricato viene associato a un utente specifico
  132. def associafile_a_utente(singolodocumento,request,utente,azienda=None,sede=None,descrizione=None,amministratore=None,pertutti=False):
  133. risultato = upload_file(singolodocumento,utente)
  134. documento = Documento()
  135. documento.dataupload = datetime.datetime.now()
  136. documento.utente = utente
  137. listaok = None
  138. listanotok = None
  139. if pertutti:
  140. documento.documento = "".join((utente.codicefiscale.strip(),"_",singolodocumento.name))
  141. else:
  142. documento.documento = singolodocumento.name
  143. print('documento.documento',documento.documento)
  144. documento.storage = risultato
  145. documento.descrizione = descrizione
  146. # verifica se il file è da considerarsi privato
  147. # 21.11.25: anziche' cercare la parola nella stringa, ho usato le regex... che mi sembrano decisamente meglio
  148. r = re.compile(r"^emo(_|-)",re.I)
  149. if r.match(documento.documento.lower()):
  150. print("Individuato elemento emo_ in:", documento.documento)
  151. documento.privato = True
  152. try:
  153. documento.save()
  154. setLog(8,azienda=azienda,sede=sede,utente=utente,documento=documento,amministratore=amministratore)
  155. listaok = {'n':documento.documento,'c':'documento assegnato regolarmente'}
  156. except IntegrityError as ie:
  157. print("problema di integrita', il file esiste",ie)
  158. listanotok = {'n':documento.documento,'c':'documento esistente'}
  159. return(listaok,listanotok)
  160. ##################################################################################
  161. # carica file multipli. Utilizzato prevalentemente dalla gestione documenti.
  162. def save_and_load_file_multiple(listadocumenti,request,utente,azienda=None,sede=None,descrizione=None,amministratore=None,pertutti=False,ignoraAzienda=False,ignoraSede=False,_privato=False):
  163. listaok = list()
  164. listanotok = list()
  165. listanotass = list()
  166. if azienda: print('Caricamento Multiplo,azienda',azienda.nome)
  167. if sede: print('Caricamento Multiplo,sede',sede.nome)
  168. print("Ignora le aziende",ignoraAzienda)
  169. print("Ignora le sedi",ignoraSede)
  170. print("Per tutti",pertutti)
  171. print("Privato",_privato)
  172. for singolodocumento in listadocumenti:
  173. print('singolodocumento:',singolodocumento)
  174. statusAss = False
  175. for ut in utente:
  176. print('utente:',ut.nome)
  177. lok = None
  178. nok = None
  179. # si deve individuare il codice fiscale dell'utente
  180. if not pertutti:
  181. if ut.codicefiscale.strip() in singolodocumento.name:
  182. statusAss = True
  183. print('associa documento CON riferimento a codice fiscale')
  184. if ignoraAzienda:
  185. print("Effettua ricerca in tutte le aziende")
  186. lok,nok = associafile_a_utente(singolodocumento,request,ut,ut.azienda,sede,descrizione,amministratore)
  187. elif ignoraSede:
  188. print("Effettua ricerca in tutte le Sedi dell'azienda")
  189. lok,nok = associafile_a_utente(singolodocumento,request,ut,ut.azienda,sede,descrizione,amministratore)
  190. else:
  191. print("Caricamento solo per l'azienda corrente")
  192. lok,nok = associafile_a_utente(singolodocumento,request,ut,azienda,sede,descrizione,amministratore)
  193. #else:
  194. # print('il codice fiscale',ut.codicefiscale.strip()," non si trova in ",singolodocumento.name)
  195. # statusAss = False
  196. else:
  197. print('associo documento SENZA riferimento a codice fiscale')
  198. lok,nok = associafile_a_utente(singolodocumento,request,ut,azienda,sede,descrizione,amministratore,pertutti)
  199. #lok: file associato in quanto nuovo
  200. #nok: file non associato perche' gia esistente
  201. if lok:
  202. listaok.append(lok)
  203. if nok:
  204. listanotok.append(nok)
  205. # se statusAss passa a False, significa che il codice fiscale non si trova.
  206. # pertanto lo inserisco tra quelli non associabili.
  207. if not statusAss:
  208. listanotass.append({'n':singolodocumento.name,'c':'non associabile - il codice fiscale non corrisponde'})
  209. print('lista',listaok,listanotok,listanotass)
  210. return (listaok,listanotok,listanotass)
  211. #carica un singolofile - utilizzato prevalentemente nella pagina utente
  212. def save_and_load_file_single(listadocumenti,request,utente,azienda=None,sede=None,descrizione=None,amministratore=None,_privato=False):
  213. """
  214. listadocumenti da caricare
  215. request: i documenti vengono caricati via web
  216. utente: utente a cui associare il documento
  217. azienda: (perche? se l'utente deve essere gia' associato a un'azienda?)
  218. sede: (lo stesso, perche' passare la sede, se l'utente stesso dovrebbe avere gia' l'indicazione della sede)
  219. e comunque questi parametri servono solo per i log, che insomma, posso aggirarli con semplicita'
  220. descrizione: descrizione assegnata al documento
  221. amministratore: caricamente a mezzo di un amministratore
  222. """
  223. listaok = list()
  224. listanotok = list()
  225. listanotass = list()
  226. associato=False
  227. for singolodocumento in listadocumenti:
  228. print('singolodocumento',singolodocumento,descrizione)
  229. #risultato = upload_file(singolodocumento,utente)
  230. documento = Documento()
  231. documento.dataupload = datetime.datetime.now()
  232. documento.utente = utente
  233. documento.documento = singolodocumento.name
  234. #documento.storage = risultato
  235. documento.descrizione = descrizione
  236. documento.privato = _privato
  237. # verifica se il documento debba essere inserito come privato o meno
  238. r = re.compile(r"^emo(_|-)",re.I)
  239. if r.match(documento.documento):
  240. print("Individuato elemento emo_ in:", documento.documento)
  241. documento.privato = True
  242. try:
  243. documento.save()
  244. setLog(8,azienda=azienda,sede=sede,utente=utente,documento=documento,amministratore=amministratore)
  245. #listaok.append(documento)
  246. print('record generato:',documento.id)
  247. associato=True
  248. except IntegrityError as ie:
  249. print("problema di integrita', il file esiste",ie)
  250. listanotok.append(documento)
  251. if associato:
  252. print("Il documento è correttamente associato",documento.documento,documento.utente.nome)
  253. # se il record e' stato correttamente salvato, procede al caricamento del file.
  254. risultato=upload_file(singolodocumento,utente)
  255. documento.storage = risultato
  256. documento.save()
  257. listaok.append(documento)
  258. else:
  259. listanotass.append(documento)
  260. return (listaok,listanotok,listanotass)
  261. #file_indice: contiene l'elenco dei nominativi da gestire.
  262. def save_and_load_file_indice(request,fileindice,azienda=None,sede=None):
  263. """
  264. qui, oltre alla request, viene chiesto il nome del file indice
  265. il nome dell'azienda a cui si fa riferimento e la sua sede
  266. """
  267. print('nome indice caricato',fileindice.name)
  268. if azienda: print('azienda',azienda.nome)
  269. if sede: print('sede',sede.nome)
  270. file_memorizzato = upload_file_indice(request.FILES['indice'])
  271. fl_path = os.path.join(getConfig('DocPath'),getConfig('DocPathIndex'))
  272. risultato = None
  273. listaOk=list()
  274. listaNotOk=list()
  275. listaNotAss=list()
  276. with open(os.path.join(fl_path,file_memorizzato),'rb') as ind:
  277. risultato = ind.read()
  278. risultato = risultato.decode('utf-8',errors='replace')
  279. if isinstance(risultato,str):
  280. risultato = risultato.encode('utf8')
  281. with open(os.path.join(fl_path,''.join((file_memorizzato,'.cvtd'))),'wb') as ind:
  282. ind.write(risultato)
  283. print('una volta convertito, passiamo oltre')
  284. with open(os.path.join(fl_path,''.join((file_memorizzato,'.cvtd'))),'rt') as ind:
  285. spamreader = csv.reader(ind,delimiter=';')
  286. next(spamreader,None) #salta l'intestazione
  287. count = 0
  288. for sr in spamreader:
  289. salvare = False
  290. count +=1 #il recordo parte gia' dalla riga 1
  291. # 30.10.25: Vale ha segnalato che il caricamente parte sempre dalla seconda riga utile.
  292. # if count==1: continue
  293. print(count,'sr',sr,len(sr))
  294. if len(sr) >= 1 and len("".join(sr)) > 0: # la lunghezza del record segnala qualcosa
  295. print('record sr',sr)
  296. utente = None
  297. codicefiscale = sr[1].strip()
  298. print('codice fiscale',sr[1].strip().upper())
  299. try:
  300. utente = Utente.objects.get(codicefiscale=sr[1].strip().upper())
  301. listaNotAss.append({"nome":utente.nome,"codicefiscale":utente.codicefiscale,"errore":"già presente"})
  302. print('Utente Trovato')
  303. except Utente.DoesNotExist as dne:
  304. print('Utente non trovato,lo aggiungo')
  305. utente = Utente()
  306. if azienda:
  307. utente.azienda = azienda
  308. print('Associata Azienda')
  309. if sede:
  310. utente.sede = sede
  311. print('Associata Sede')
  312. utente.nome = sr[0].strip().title()
  313. print("Utente:",utente.nome)
  314. utente.codicefiscale=sr[1].strip().upper()
  315. print("Codice Fiscale",utente.codicefiscale,len(utente.codicefiscale))
  316. for fmt in ('%d/%m/%y','%d/%m/%Y','%d-%m-%y','%d-%m-%Y'):
  317. try:
  318. data_convertita = datetime.datetime.strptime(sr[2],fmt)
  319. print('data convertita',data_convertita)
  320. utente.datanascita = data_convertita
  321. except ValueError as ve:
  322. print('errore con la data di nascita',ve)
  323. utente.luogonascita = sr[3].title()
  324. print("Luogo di nascita",utente.luogonascita)
  325. utente.mail = sr[4].strip().lower()
  326. print("Mail",utente.mail)
  327. # ricerca sede: se il codice estratto nella colonna corrisponde...
  328. tmp_sede = sr[5]
  329. lista_sede = azienda.sede_set.all()
  330. for ls in lista_sede:
  331. if tmp_sede == ls.identificativo:
  332. utente.sede = ls
  333. utente.cabiopassword = ls.cambiopassword
  334. utente.forzanuovapassword = ls.forzanuovapassword
  335. utente.otppassword = ls.otppassword
  336. else:
  337. utente.cabiopassword = azienda.cambiopassword
  338. utente.forzanuovapassword = azienda.forzanuovapassword
  339. utente.otppassword = azienda.otppassword
  340. utente.inserimento = datetime.datetime.today().strftime("%Y-%m-%d")
  341. utente.pin = str(randint(100000,999999))
  342. if len(utente.codicefiscale) == 16:
  343. utente.save()
  344. listaOk.append({"nome":utente.nome,"codicefiscale":utente.codicefiscale})
  345. else:
  346. print("Codice Fiscale NON valido o mancante")
  347. listaNotOk.append({"nome":utente.nome,"codicefiscale":utente.codicefiscale,"errore":"Codice Fiscale"})
  348. return (listaOk,listaNotOk,listaNotAss,count)
  349. def PrepareZipFile(listafile=[]):
  350. zip_path = os.path.join(settings.BASE_DIR,getConfig('DocZipFile'))
  351. print("zip_path:",zip_path)
  352. # verifica l'esistenza della directory
  353. try:
  354. os.mkdir(zip_path)
  355. except FileExistsError as fee:
  356. print(zip_path,"esistente")
  357. filename = ''.join((str(time.time()),'.zip'))
  358. with zipfile.ZipFile(os.path.join(zip_path,filename),'w') as zip:
  359. for lf in listafile:
  360. d = Documento.objects.get(pk=lf)
  361. file2zip = os.path.join(settings.BASE_DIR,getConfig('DocPath'),d.utente.azienda.partitaiva,d.utente.codicefiscale,d.storage)
  362. print('path completa',file2zip)
  363. print('file completo',os.path.join(zip_path,filename))
  364. if os.path.exists(file2zip):
  365. zip.write(file2zip,arcname=d.documento)
  366. else:
  367. print('il file non esiste:',file2zip)
  368. return (zip_path,filename)