controller.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. '''
  2. this file is part of "El Botadero"
  3. copyright 2018 Rodrigo Garcia <strysg@riseup.net>
  4. AGPL liberated.
  5. '''
  6. # El objetivo de este archivo es albergar la logica de gestion de archivos y comportamiento general de la aplicacion
  7. import os
  8. from datetime import datetime as dt
  9. from werkzeug.utils import secure_filename
  10. from .shared import globalParams, gr
  11. from . import utils as u
  12. from .database.models import Archivo, HtmlPage
  13. def descargaPermitida(cat, nombreArchivo):
  14. if '..' in nombreArchivo or nombreArchivo.startswith(os.path.sep):
  15. return False
  16. if cat not in u.categorias() and cat != 'Misc':
  17. return False
  18. return True
  19. def descargarArchivo(cat, nombreArchivo):
  20. # agregar descargar de utils
  21. pathf = u.descargarArchivo(cat, nombreArchivo)
  22. return pathf
  23. def subirArchivo(cat, file, hashedPassword=''):
  24. ''' Verifica el archivo siendo subido, lo guarda en el directorio de
  25. almacenamiento y lo registra en la BD. Tambien marca la categoria a la
  26. que pertenece el archivo para que se renderize el html de listado.
  27. :param cat: Categoria o subcarpeta donde se guarda el archivo
  28. :param file: objeto instancia de 'FileStorage' (werkzeug) del archivo
  29. :return: Si la subida es exitosa, retorna el registro en la base de
  30. datos recien creado. Si no, retorna un diccionario de la forma:
  31. { tipoError: (entero),
  32. mensaje: 'mensaje de error',
  33. redirect: 'link redireccion en caso de ya existir un archivo'
  34. }
  35. NOTA: En caso de subir exitosamente, la funcion que lo llama deberia
  36. llamar a sincronizarArchivo() para actualizar los registros.
  37. '''
  38. print('subirArchivo(cat="%r", file="%r", hashedPassword="%r"' % (cat, file, hashedPassword))
  39. filename = secure_filename(file.filename)
  40. categoria = ''
  41. if cat != 'Misc':
  42. categoria = cat
  43. # comprobando existencia
  44. filepath = os.path.join(globalParams.uploadDirectory, categoria, filename)
  45. try:
  46. f = open(filepath, 'r')
  47. f.close()
  48. print('Archivo siendo subido ya existe:', filepath)
  49. return {
  50. 'tipoError': 1,
  51. 'mensaje': 'El archivo "' + filename + '" ya existen en ' + filepath,
  52. 'redirect': categoria
  53. }
  54. except IOError as E:
  55. pass
  56. # comprobando hash
  57. digestCheck = ''
  58. if globalParams.digestCheck:
  59. digestCheck = u.hashFileStorage(file,
  60. accelerateHash=globalParams.digestAccelerated)
  61. regDb = Archivo.query.filter_by(digestCheck=digestCheck).first()
  62. if regDb is not None:
  63. # existe un registro con el mismo digestCheck
  64. file.close()
  65. cat = u.categoriaArchivo(regDb.path)
  66. if cat == globalParams.uploadDirectory:
  67. cat = ''
  68. cat += '/'
  69. print ('Ya existe un archivo con el mismo digestCheck ', digestCheck, 'encontrado', str(regDb))
  70. return {
  71. 'tipoError': 2,
  72. 'mensaje': 'Ya existe un archivo con el mismo digestCheck ' + digestCheck + ' con nombre ' + regDb.name,
  73. 'redirect': categoria + regDb.name
  74. }
  75. # procediendo a registrar el archivo en BD
  76. file.seek(0, os.SEEK_END)
  77. fsize = file.tell()
  78. file.seek(0)
  79. remainingTime = u.tiempoBorradoArchivo(fsize)
  80. uploadedAtTime = dt.now()
  81. # comprobando espacio de almacenamiento disponible
  82. if gr['storageUsed'] == 0:
  83. u.actualizarEstadisticasGenerales()
  84. if gr['storageUsed'] + fsize > gr['storageTotal']:
  85. print('No se cuenta con espacio de almacenamiento suficiente, requiere', str(fsize), 'se cuenta', str(gr['storageTotal'] - gr['storageUsed']))
  86. return {
  87. 'tipoError': 3,
  88. 'mensaje': 'No se cuenta con espacio suficiente',
  89. 'redirect': categoria
  90. }
  91. # guardando en el sistema de archivos
  92. try:
  93. file.save(os.path.join(globalParams.uploadDirectory, categoria, filename))
  94. print('✓ Archivo guardado en sistema de archivos: %r' % os.path.join(globalParams.uploadDirectory, categoria, filename))
  95. except Exception as E:
  96. print('✕ Excepcion al guardar archivo %r en el sistema de archivos:\n%r' % (filename, str(E)))
  97. return {
  98. 'tipoError': 4,
  99. 'mensaje': 'Error interno al guardar el archivo ' + filename,
  100. 'redirect': categoria
  101. }
  102. # creando registro en la BD
  103. arch = Archivo.create(name=filename,
  104. path=filepath, size=fsize,
  105. extension=u.extensionArchivo(filename),
  106. digestCheck=digestCheck,
  107. digestAlgorithm=globalParams.digestAlgorithm,
  108. uploadedAtTime=uploadedAtTime,
  109. remainingTime=remainingTime,
  110. hashedPassword=hashedPassword)
  111. print('✓ Archivo registrado en BD', arch)
  112. return arch
  113. # definir una funcion para comprobar la lista de archivos y su tiempo de
  114. # borrado
  115. def comprobarTiempoBorradoListaArchivos(categoria, hdd=False):
  116. ''' Verifica si es necesario borrar archivos en los archivos dados en
  117. la carpeta (categoria) guradada en el almacen
  118. :param categoria: La carpeta (categoria) dentro el almacen donde se hace
  119. la busqueda.
  120. :param hdd: Hace que la busqueda se haga en el almacenamiento fisico (HDD tipicamente).
  121. :return borrados: Lista de archivos que se han borrado (directorios)
  122. '''
  123. # ajuste
  124. if categoria == 'Misc':
  125. categoria = globalParams.uploadDirectory
  126. lista = None
  127. if hdd:
  128. lista = u.listaDeArchivos(categoria)
  129. else:
  130. lista = u.listaDeArchivosEnBd(categoria)
  131. # print ('LISTA de archivos:::::::::::', str(lista))
  132. borrados = []
  133. for archivo in lista:
  134. tiempoBorrado = u.tiempoBorradoArchivo(archivo.size)
  135. edad = u.edadArchivo(archivo.path, archivo)
  136. print ('archivo:', archivo.name, ' edad:', str(edad), 'borrado max', str(tiempoBorrado))
  137. if (tiempoBorrado < edad):
  138. r = u.borrarArchivo(archivo.path)
  139. print (' xx Borrando archivo', archivo.name, ' = ', r)
  140. borrados.append(archivo.path)
  141. return borrados
  142. def marcarPaginaListaParaRenderizar(categoria='Misc'):
  143. ''' Marca la pagina de la lista para renderizar de la categoria dada
  144. para que se vuelva a renderizar el template usando jinja2
  145. :param: True si se ha marcado correctamente, False en otro caso
  146. '''
  147. if categoria == globalParams.uploadDirectory or categoria == '':
  148. categoria = 'Misc' # ajuste por conveniencia
  149. # buscando el registro
  150. name = 'lista_archivos_' + categoria
  151. html_page = HtmlPage.query.filter_by(name=name).first()
  152. if html_page is not None:
  153. # modificando
  154. try:
  155. html_page.save(renderHtml=True)
  156. print('marcado para generar html:', html_page.name, str(html_page.renderHtml))
  157. return True
  158. except Exception as E:
  159. print ('Excepcion modificando html_page %r', (name))
  160. return False
  161. return False
  162. def sincronizarArchivos(ignorar=[]):
  163. ''' Funcion encargada sincronizar y actualizar la BD segun los archivos
  164. que se encuentran en el directorio de subidas en el sistema de archivos.
  165. Lista los archivos en el directorio de subidas y los introduce en
  166. la base de datos si estos no estan registrados. Tambien borra los
  167. registros de archivos que se encuentran en la BD pero no en el sistema
  168. de archivos. Cuando detecta un cambio marca la pagina web necesaria para
  169. que se renderize.
  170. :param ignorar: Una lista con nombres de archivos a ignorar
  171. :return ([registrados],[borrados],[actualizados]): Retorna tres listas, segun registra nuevos archivos en BD, los borra o actualiza su tiempo restante.
  172. '''
  173. print ('** Sincronizando archivos **')
  174. print ('\nParametros', str(globalParams))
  175. listaEnBd = u.listaDeArchivosEnBd()
  176. archivosEnBd = []
  177. for reg in listaEnBd:
  178. archivosEnBd.append(reg.path)
  179. archivos = []
  180. listaLsArchivos = []
  181. registrados = []
  182. borrados = []
  183. actualizados = []
  184. # obteniendo lista de archivos en el sistema de archivos
  185. print('#' + 'Misc')
  186. lista = u.listaDeArchivos()
  187. for archivo in lista:
  188. if u.nombreArchivo(archivo) not in ignorar:
  189. # estandarizando nombre
  190. print(os.path.join(os.path.curdir + os.path.sep, archivo))
  191. archivos.append(os.path.join(os.path.curdir + os.path.sep, archivo))
  192. for cat in u.categorias():
  193. print('#' + cat)
  194. lista = u.listaDeArchivos(categoria=cat)
  195. for archivo in lista:
  196. if u.nombreArchivo(archivo) not in ignorar:
  197. # estandarizando nombre
  198. print(os.path.join(os.path.curdir + os.path.sep, archivo))
  199. archivos.append(os.path.join(os.path.curdir + os.path.sep, archivo))
  200. # actualizando BD
  201. for archivo in archivos:
  202. if archivo in ignorar:
  203. continue
  204. if archivo not in archivosEnBd:
  205. print ('(+)', str(archivo), u.categoriaArchivo(archivo))
  206. arch = u.registrarArchivo(archivo)
  207. marcarPaginaListaParaRenderizar(categoria=u.categoriaArchivo(archivo))
  208. registrados.append(arch)
  209. else:
  210. if u.archivoDebeBorrarsePorTiempo(archivo):
  211. print ('(-)', str(archivo), u.categoriaArchivo(archivo))
  212. r = u.borrarArchivo(archivo) # del sistema de archivos y BD
  213. borrados.append(archivo)
  214. print (' ✗ Registro de archivo borrado', archivo, ' = ', r)
  215. marcarPaginaListaParaRenderizar(categoria=u.categoriaArchivo(archivo))
  216. else:
  217. if u.actualizarTiempoRestanteArchivo(archivo):
  218. print ('(+-)', str(archivo), u.categoriaArchivo(archivo))
  219. actualizados.append(archivo)
  220. marcarPaginaListaParaRenderizar(categoria=u.categoriaArchivo(archivo))
  221. for reg in archivosEnBd:
  222. # caso de que un archivo se borro del sistema de archivos
  223. if reg not in archivos:
  224. print('(bd -)', str(reg), u.categoriaArchivo(reg))
  225. r = u.borrarRegistroArchivoEnBd(u.nombreArchivo(reg))
  226. borrados.append(reg)
  227. marcarPaginaListaParaRenderizar(categoria=u.categoriaArchivo(reg))
  228. print ('\nsincronización completa')
  229. return registrados, borrados, actualizados