views.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. # this file is part of "El Botadero"
  2. # copyright Rodrigo Garcia 2018 <strysg@riseup.net>
  3. # AGPL liberated.
  4. import functools
  5. from . import controller as co
  6. from . import utils as u
  7. from flask import (
  8. Blueprint, flash, g, redirect, render_template, request, url_for,
  9. send_file, jsonify, make_response
  10. )
  11. log = g.log
  12. botaderoBp = Blueprint('botadero', __name__, url_prefix='')
  13. @botaderoBp.route('/')
  14. @botaderoBp.route('/<string:cat>/')
  15. def categoriaView(cat='Misc'):
  16. html_page = u.obtenerHtmlListado(categoria=cat)
  17. return html_page.html
  18. # endpoint descarga
  19. @botaderoBp.route('/almacen/<string:cat>/<string:nombreArchivo>')
  20. def descargaDesdeIndexView(cat, nombreArchivo):
  21. log.info('⏬ file: {0} {1}'.format(cat, nombreArchivo))
  22. if not co.descargaPermitida(cat, nombreArchivo):
  23. return ('No permitido: '+cat+'/'+nombreArchivo), 404
  24. if co.tienePassword(nombreArchivo):
  25. # TODO: redirect a descarga con password
  26. return ('No permitido tiene password: '+cat+'/'+nombreArchivo), 404
  27. pathf = co.descargarArchivo(cat, nombreArchivo)
  28. if pathf is None:
  29. return render_template("noExiste.html",
  30. nombre=nombreArchivo,
  31. esquemaColores=u.esquemaColoresRandom()), 404
  32. return send_file(pathf, as_attachment=True)
  33. # endpoint descarga protegida (ajax)
  34. @botaderoBp.route('/<string:cat>/download_protected', methods=['GET', 'POST'])
  35. def descargarArchivoProtegidoAjax(cat):
  36. nombreArchivo = request.form.get('nombre_archivo_protegido')
  37. log.info('⏬ ⚿ file {0}: {1}'.format(cat, nombreArchivo))
  38. if cat == '':
  39. cat = 'Misc'
  40. resultados = {}
  41. if 'pwd_archivo' not in request.form or \
  42. 'nombre_archivo_protegido' not in request.form:
  43. resultados = {
  44. 'error': {
  45. 'msj': 'No se han proporcionado datos completos',
  46. 'code': 1
  47. }
  48. }
  49. return make_response(jsonify(resultados), 400)
  50. password = request.form.get('pwd_archivo')
  51. if not co.descargaPermitida(cat, nombreArchivo):
  52. resultados = {
  53. 'error': {
  54. 'msj': 'Descarga no permitida',
  55. 'code': 3
  56. }
  57. }
  58. return make_response(jsonify(resultados), 401)
  59. if not co.tienePassword(nombreArchivo):
  60. resultados = {
  61. 'error': {
  62. 'msj': 'Este archivo no requiere contraseña',
  63. 'code': 4
  64. }
  65. }
  66. return make_response(jsonify(resultados), 401)
  67. if len(password) < 2:
  68. resultados = {
  69. 'error': {
  70. 'msj': 'Contraseña incorrecta',
  71. 'code': 2
  72. }
  73. }
  74. return make_response(jsonify(resultados), 401)
  75. pathf = co.descargarArchivo(cat, nombreArchivo, password=password)
  76. if isinstance(pathf, dict):
  77. resultados = {
  78. 'error': {
  79. 'msj': pathf['mensaje'],
  80. 'code': pathf['tipoError']
  81. }
  82. }
  83. return make_response(jsonify(resultados), 403)
  84. return send_file(pathf, as_attachment=True)
  85. # formulario de descarga para archivos protegidos
  86. @botaderoBp.route('/almacen/<string:cat>/<string:nombreArchivo>/descargar_protegido', methods=['GET'])
  87. def descargarArchivoProtegidoForm(cat, nombreArchivo):
  88. log.info('☱ download file protected (form): categoria={0}, nombre={1}'
  89. , cat, nombreArchivo)
  90. if cat == '':
  91. cat = 'Misc'
  92. if not co.descargaPermitida(cat, nombreArchivo):
  93. return ('No permitido: '+cat+'/'+nombreArchivo), 404
  94. pathf = co.descargarArchivo(cat, nombreArchivo)
  95. if pathf is None:
  96. return render_template("noExiste.html",
  97. nombre=nombreArchivo,
  98. esquemaColores=u.esquemaColoresRandom()), 404
  99. if not co.tienePassword(nombreArchivo):
  100. return render_template("noExiste.html",
  101. nombre=nombreArchivo,
  102. esquemaColores=u.esquemaColoresRandom()), 404
  103. return u.renderizarHtmlArchivoProtegido(cat, nombreArchivo)
  104. # vista de subida de archivo (individual) este caso se asume que no se usa javascript.
  105. @botaderoBp.route('/<string:cat>/upload_file', methods=['GET', 'POST'])
  106. def subidaArchivo(cat):
  107. # La siguiente línea es para evitar el error con uwsgi
  108. # *4719 readv() failed (104: Connection reset by peer) while reading upstream
  109. # Ref: https://uwsgi.readthedocs.io/en/latest/ThingsToKnow.html?highlight=clobbered
  110. rdata = request.get_data(cache=True)
  111. log.info('⮉ request (individual): name={0}, method={1}, categoria={2}'
  112. .format(
  113. request.files.get('file', 'No se ha proporcionado archivo'), \
  114. request.method, cat))
  115. if cat == '':
  116. cat = 'Misc'
  117. if 'file' not in request.files:
  118. return 'Debe subir un archivo'
  119. file = request.files['file']
  120. if file.filename == '':
  121. html_page = u.obtenerHtmlListado(categoria=cat)
  122. return html_page.html
  123. resultado = {}
  124. if request.form.get('password') is not None:
  125. resultado = co.subirArchivo(cat, file, request.form.get('password'))
  126. else:
  127. resultado = co.subirArchivo(cat, file)
  128. if not isinstance(resultado, dict):
  129. # caso exitoso, se debe actualizar
  130. co.sincronizarArchivos("['.gitkeep', '.gitkeep~', '#.gitkeep', '#.gitkeep#']")
  131. co.marcarTodasLasPaginasParaRenderizar()
  132. html_page = u.obtenerHtmlListado(categoria=cat)
  133. return redirect("/"+cat, code=302)
  134. else:
  135. html_page = u.obtenerHtmlListado(categoria=cat)
  136. return redirect("/"+cat, code=302)
  137. # vista de subida de varios archivos
  138. @botaderoBp.route('/<string:cat>/upload_file_a', methods=['GET', 'POST'])
  139. def subidaArchivos(cat):
  140. # La siguiente línea es para evitar el error con uwsgi
  141. # *4719 readv() failed (104: Connection reset by peer) while reading upstream
  142. # Ref: https://uwsgi.readthedocs.io/en/latest/ThingsToKnow.html?highlight=clobbered
  143. rdata = request.get_data(cache=True)
  144. # log.warning('request.data?::::\n{0}\n::::::::'.format(len(rdata)))
  145. log.info('⮉ request (multiple): files={0}'.format(request.files.getlist("file")))
  146. if cat == '':
  147. cat = 'Misc'
  148. password = ''
  149. if request.form.get('password') is not None:
  150. password = request.form.get('password')
  151. exitosos = []
  152. erroneos = []
  153. # TODO: controlar suma de peticion y tamaño máximo
  154. # ...
  155. for upload in request.files.getlist("file"):
  156. log.debug('* filename {0}'.format(upload.filename))
  157. resultado = None
  158. if password != '':
  159. resultado = co.subirArchivo(cat, upload, password)
  160. else:
  161. resultado = co.subirArchivo(cat, upload)
  162. if not isinstance(resultado, dict):
  163. log.debug('exitoso: {0}'.format(resultado.name))
  164. exitosos.append(resultado.name)
  165. else:
  166. log.debug('errorneo: {0}'.format(str(resultado)))
  167. erroneos.append(resultado)
  168. # actualizando
  169. if len(exitosos) > 0:
  170. co.sincronizarArchivos("['.gitkeep', '.gitkeep~', '#.gitkeep', '#.gitkeep#']")
  171. co.marcarTodasLasPaginasParaRenderizar()
  172. # retornando respuesta
  173. log.debug('exitosos:\n {0}'.format(str(exitosos)))
  174. log.debug('erroneos:\n {0}'.format(str(erroneos)))
  175. return jsonify(exitosos=exitosos, erroneos=erroneos)
  176. ####### vistas informativas ######
  177. @botaderoBp.route('/info', methods=['GET'])
  178. def info_page():
  179. html_page = u.obtener_pag_info()
  180. return html_page.html