from flask import request, Blueprint from flask_restful import Resource, Api from os import path, remove, walk, mkdir import logging import re from models.config import CONTENT_DIR, STATIC_DIR contents_app = Blueprint('contents', __name__) api = Api(contents_app) 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) def _search_content_dir(type_, categories=None): target = categories or type_ def _get_file_front_matter_type(): with open(file_dir, 'r', encoding="utf-8") as md: md_line_data = md.readlines() for line in md_line_data: if categories: if 'categories' in line: return list(filter(None, re.split('"|\n|]', line)))[-1] else: if 'type:' in line: return list(filter(None, re.split('"|\n', line)))[-1] for file_dir in _gen_content_files(): if target == _get_file_front_matter_type(): 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)) @contents_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} @contents_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)} @contents_app.route('/api/upload/static/img', methods=['POST']) def upload_static_img(): img_data = request.files['image'] img_dir = path.join(STATIC_DIR, 'img', request.args.get('type', type=str), request.args.get('filename', type=str)) img_data.save(img_dir) return {'filename': request.args.get('filename', type=str)} @contents_app.route('/api/new_content', methods=['POST']) def gen_content(): front_matter = request.json.get('frontMatter', '---\n---') name = request.json.get('name', 'Undefind') dir_ = path.join(_search_content_dir( request.json.get('type'), request.json.get('categories')), name) if dir_: mkdir(dir_) mkdir(path.join(dir_, 'img')) with open(path.join(dir_, 'index.md'), 'w') as md: md.write(front_matter) return {'new_content': name} api.add_resource(Content, '/api/contents')