| 
					
				 | 
			
			
				@@ -0,0 +1,153 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+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 = '{}/img/{}'.format(request.args.get('url', type=str), img_data.filename)
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    img_dir = CONTENT_DIR + file_dir
 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    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)
 
			 |