""" Excel 2007 / JSON microservice Flask Route Handlers ================== This file provides flask route handlers as lightweight wrappers around the conversion library functions """ from flask import request, abort, render_template from flask import jsonify from app import config from app.app import application from app.logic import async from app.logic import converter @application.route('/') def index(): """ Handles the index route, which provides a human readable listing of the available microservice methods """ methods = ['xlsxtojson', 'jsontoxlsx', 'status'] return render_template('index.html', methods=methods) @application.route('/xlsxtojson', methods=['POST']) def xlsxtojson(): """ This route provides an http endpoint for consumption of the library function to convert an Excel 2007 to line-delimited json. """ owner_type = request.form['owner_type'] owner_id = request.form['owner_id'] if 'filename' not in request.form: abort(400, 'Excel 2007 filename must be provided') filename = request.form['filename'] row_offset = int(request.form.get('row_offset', 0)) json_filename = filename.replace('.xlsx', '.json') # TODO: move this function into the async module: # async.convert_xlsx_to_json(owner_type, owner_id, filename) bucket = config.bucket_name # since the files can be very large, store them on the filesystem # instead of in memory # build the temp filesystem paths xlsx_fs_folder = converter.build_fs_path(config.temp_dir, 'xlsx', owner_type, owner_id) json_fs_folder = converter.build_fs_path(config.temp_dir, 'json', owner_type, owner_id) # make sure the temp directories for this owner are created converter.makedirs(xlsx_fs_folder, exist_ok=True) converter.makedirs(json_fs_folder, exist_ok=True) xlsx_fp = converter.open_fp(config.temp_dir, 'xlsx', owner_type, owner_id, filename, 'wb') # build the folder xlsx_s3_folder = converter.build_s3_path(config.prefix, 'xlsx', owner_type, owner_id) json_s3_folder = converter.build_s3_path(config.prefix, 'json', owner_type, owner_id) # get a connection to s3 s3 = converter.get_s3() # get the Excel 2007 file from s3 converter.get_file_from_s3(s3, bucket, xlsx_s3_folder, filename, xlsx_fp) # reopen it as read xlsx_fp = converter.reopen_fp(config.temp_dir, 'xlsx', owner_type, owner_id, filename, 'rb', xlsx_fp) # create the json file to be populated json_fp = converter.open_fp(config.temp_dir, 'json', owner_type, owner_id, json_filename, 'wb') # process its contents to json converter.convert_xlsx_to_json(xlsx_fp, json_fp, filename, row_offset) # reopen the json file as read json_fp = converter.reopen_fp(config.temp_dir, 'json', owner_type, owner_id, json_filename, 'rb', json_fp) # upload the json back to s3 converter.put_file_to_s3(s3, bucket, json_s3_folder, json_filename, json_fp) return json_s3_folder + '/' + json_filename @application.route('/jsontoxlsx', methods=['POST']) def jsontoxlsx(): """ This route provides an http endpoint for consumption of the library function to convert line-delimited json to Excel 2007. """ owner_type = request.form['owner_type'] owner_id = request.form['owner_id'] if 'filename' not in request.form: abort(400, 'JSON filename must be provided') filename = request.form['filename'] xlsx_filename = filename.replace('.json', '.xlsx') template = request.form['template'] task_id = 'jsontoxlsx_{}_{}'.format(owner_type, owner_id) existing_job = async.celery.AsyncResult(task_id) existing_job.revoke(terminate=True) existing_job.forget() async_result = async.convert_json_to_xlsx.apply_async(args=[owner_type, owner_id, filename, xlsx_filename, template], task_id=task_id) # TODO (OrCharles): more deterministic way of revoking a task response = jsonify({'job_id': async_result.id, 'job_status': 'PENDING'}) response.status_code = 200 return response @application.route('/jsontoxlsx/status//', methods=['GET']) def jsontoxlsxstatus(user_type, user_id): job_id = 'jsontoxlsx_{}_{}'.format(user_type, user_id) job = async.celery.AsyncResult(job_id) if job.state == 'SUCCESS': response_dict = {'job_status': job.state, 'xlsx_path': job.result} else: response_dict = {'job_status': job.state} response = jsonify(response_dict) response.status_code = 200 return response