from flask import Flask, request, redirect, url_for from flask_restful import Resource, Api from flask_cors import CORS from os import path, remove, listdir, walk import logging import re from config import CONTENT_DIR app = Flask(__name__) api = Api(app) CORS(app, resources={r"/api/*": {"origins": "*"}}) CURRENT_PATH = '/Users/weichen/choozmo/bhouse/bhouse' logger = logging.getLogger(__name__) DATA_FIELD = ['title:', 'url:'] def _get_data(file_dir): def load_data(): if 'title:' in line: data_field.remove('title:') s = line.split('"') result['title'] = s[1] elif 'url:' in line: data_field.remove('url:') s = line.split('"') result['url'] = s[1] data_field = list(DATA_FIELD) result = {} with open(file_dir, 'r', encoding="utf-8") as md: result['content'] = md.read() md.seek(0) md_line_data = md.readlines() for line in md_line_data: load_data() if not data_field: return result return result def _gen_content_files(): for root, dirs, files in walk(CONTENT_DIR): for f in files: if '.md' not in f: continue yield path.join(root, f) def _search_dir(url): def _get_file_front_matter_url(): with open(file_dir, 'r', encoding="utf-8") as md: md_line_data = md.readlines() for line in md_line_data: if 'url:' in line: return list(filter(None, re.split('"|\n', line)))[-1] for file_dir in _gen_content_files(): if url == _get_file_front_matter_url(): return path.dirname(file_dir) class Content(Resource): DATA_FIELD = ['title:', 'url:'] @property def url(self): return request.args.get('url', type=str) def _search_content(self): result = {} for file_dir in _gen_content_files(): data = _get_data(file_dir) if self.url in data.get('url', ''): result = data result['path'] = file_dir yield result def _get_contents(self): for file_dir in _gen_content_files(): yield _get_data(file_dir) def get(self): if self.url: return list(self._search_content()) else: return list(self._get_contents()) def post(self): try: file_dir = path.join( _search_dir(request.args.get('url', type=str)), 'index.md') md_content = request.json.get('content') with open(file_dir, 'w', encoding="utf-8") as md: md.write(md_content) return md_content except TypeError as err: logger.error('Content post failed with file_dir param contain None. error: {}'.format(err)) except OSError as err: logger.error('Content post failed with: {} is not exist{}'.format(file_dir, err)) except AttributeError as err: logger.error('Content post failed with AttributeError: {}'.format(err)) except Exception as err: logger.error('Content post failed with: {}'.format(err)) def delete(self): content_data = list(self._search_content()) file_dir = content_data[0].get('path') if path.exists(file_dir): remove(file_dir) logger.info('delete file: {}'.format(file_dir)) else: logger.warning('delete fail with {} not exist'.format(file_dir)) @app.route('/api/upload/img', methods=['POST']) def upload_img(): img_data = request.files['image'] file_dir = _search_dir(request.args.get('url', type=str)) img_dir = path.join(file_dir, 'img/{}'.format(img_data.filename)) img_data.save(img_dir) return {'filename': img_data.filename} @app.route('/api/delete/img', methods=['DELETE']) def delete_img(): try: file_dir = _search_dir(request.args.get('url', type=str)) img_dir = path.join(file_dir, 'img/{}'.format(request.args.get('filename', type=str))) remove(img_dir) logger.info('delete img: {}'.format(img_dir)) return {'filename': request.args.get('filename', type=str)} except TypeError as err: logger.error('delete img: {} failed with file_dir is None. error: {}'.format( request.args.get('filename', type=str), err)) return {'filename': request.args.get('filename', type=str)} except OSError as err: logger.error('delete img: {} failed with img_dir is not exist. error: {}'.format( request.args.get('filename', type=str), err)) return {'filename': request.args.get('filename', type=str)} except Exception as err: logger.error('delete img: {} failed with {}'.format( request.args.get('filename', type=str), err)) return {'filename': request.args.get('filename', type=str)} api.add_resource(Content, '/api/contents') if __name__ == '__main__': logging.basicConfig( level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s') app.run(debug=True)