def get_settings_keys_config(self, keys_config_path): if not isinstance(keys_config_path, string_types): return {} keys_config = get_json_content_by_path( self.bucket, keys_config_path ) or builtin_site_settings_keys_config_info.get(keys_config_path) if not isinstance(keys_config, dict): keys_config = {} return keys_config
def get_settings_from_json(self, config_path): if not isinstance(config_path, string_types): return {} if not re.match("__\w+\.json", config_path): return {} if not self.bucket: return {} settings_from_json = get_json_content_by_path(self.bucket, config_path) if not isinstance(settings_from_json, dict): settings_from_json = {} return settings_from_json
def setting_settings_view(): bucket = get_logined_bucket(check=True) if not bucket: return abort(410) data_obj = get_json_content_by_path(bucket, 'settings.json') or {} if request.method == "POST": keys = request.values.keys() data_obj = get_data_obj_from_POST(keys) sync_file_by_server_side(bucket, "settings.json", content=json_dumps(data_obj, indent=4)) return render_api_template_as_response("page_user_site_settings.jade", data_obj=data_obj)
def get_nav_items_from_site_configs(bucket): # nav_configs & user_nav_disabled 两个属性,是在线编辑 nav 时写入 configs/nav_config.json 中的 if not bucket: return [] nav_config = get_json_content_by_path(bucket, 'nav.json') or {} if not nav_config: return [] site_nav_configs = nav_config.get('nav_configs') or [] if nav_config.get('user_nav_disabled', False): # 用户(拖拽)自定义的导航被禁用了 site_nav_configs = [] if not isinstance(site_nav_configs, (list, tuple)): return [] nav_items = [] for nav_item in site_nav_configs: if isinstance(nav_item, dict) and 'name' in nav_item and 'url' in nav_item: nav_items.append(nav_item) return nav_items
def get_auto_nav_items(bucket): # 自动生成的 pages_configs = get_bucket_pages_configs(bucket) nav_items = [] homepage_url = '/' if request.args.get('status') == 'loaded': homepage_url = '/?status=loaded' homepage_nav_item = dict(name='Home', url=homepage_url) nav_items.append(homepage_nav_item) site_configs = get_bucket_site_configs(bucket) albums_root = smart_unicode(site_configs.get("albums_root", "")).strip() if albums_root: nav_items.append(dict(name="Album", url="/album")) wiki_configs = get_json_content_by_path(bucket, "__wiki.json", force_dict=True) wiki_root = wiki_configs.get("wiki_root") enable_wiki_nodes = auto_type(wiki_configs.get("enable_wiki_nodes", True)) if wiki_root: nav_items.append(dict(name="Wiki", url="/wiki")) if enable_wiki_nodes: nav_items.append(dict(name="Wiki Nodes", url="/wiki_nodes")) if 'categories.jade' in pages_configs: # 有 categories.jade 的呈现 nav_items.append(dict(name='Categories', url='/categories')) if 'archive.jade' in pages_configs: # archive 页面 nav_items.append(dict(name='Archive', url='/archive')) if has_markdown_record_by_path_prefix(bucket, "links"): nav_items.append(dict(name='Links', url='/__page/links')) if has_markdown_record_by_path_prefix(bucket, "about"): nav_items.append(dict(name='About', url='/__page/about')) if has_markdown_record_by_path_prefix(bucket, "contact"): nav_items.append(dict(name='Contact', url='/__page/contact')) if 'feed.jade' in pages_configs: nav_items.append(dict(name='Feed', url='/feed')) return nav_items
def update_json(self, path, **kwargs): # 更新一个 json 文件,用 simple_sync 的调用 # 注意,调用这个函数的时候,并不需要管理员权限,所以,要慎重处理!!!! if not path.lower().endswith('.json'): return 'must be a json file' json_data = get_json_content_by_path(self.bucket, path) if not isinstance(json_data, dict): return 'update_json failed, not a dict obj' to_update = False for key, value in kwargs.items(): old_value = json_data.get(key) if value != old_value: to_update = True break if to_update: json_data.update(kwargs) new_content = json.dumps(json_data, indent=4) sync_file_by_server_side(bucket=self.bucket, relative_path=path, content=new_content, is_dir=False, is_deleted=False) return ''
def show_wiki_nodes_as_sub_site(): bucket = get_bucket_in_request_context() if not bucket: return request_path = get_request_path().strip("/") if not re.match("wiki_nodes(/|$)", request_path): return wiki_configs = get_json_content_by_path(bucket, "__wiki.json", force_dict=True) enable_wiki_nodes = auto_type(wiki_configs.get("enable_wiki_nodes", True)) if not enable_wiki_nodes: return wiki_root = smart_unicode(wiki_configs.get("wiki_root", "")) if not wiki_root: return wiki_root = wiki_root.strip("/") wiki_title = wiki_configs.get("wiki_title") or get_just_name(wiki_root, for_folder=True) path = request.values.get("path", "").strip("/") if request.values.get("type") == "data": # return json data wiki_root = wiki_root.lower() under = "%s/%s" % (wiki_root, path) posts_info = get_bucket_posts_info(bucket) data = filter_and_get_posts_link_points_info(posts_info, under=under) nodes = data.get("nodes") if nodes: for node in nodes: node_id = node.get("id") if node_id and isinstance(node_id, string_types): if node_id.startswith("#"): tag = node_id.lstrip("#") url = "/wiki/tag/%s" % tag node["url"] = url else: relative_path = get_relative_path(node_id.strip("/"), wiki_root, return_name_if_fail=False) if relative_path: url = "/wiki/post/%s" % relative_path node["url"] = url return force_response(data) else: return render_api_template("builtin_theme_wiki_nodes.jade", wiki_title=wiki_title)
def wechat_text_image_handler(wechat_user_id, bucket, xml_data): msg_id = xml_data.get("MsgId") create_time = xml_data.get("CreateTime") msg_type = xml_data.get("MsgType") # post_root, auto_add_date(bool), silent_reply(bool), image_folder, image_insert_type(image/markdown_syntax) wechat_configs = get_json_content_by_path(bucket, "__wechat.json", force_dict=True) today = get_now_from_bucket(bucket, "%Y-%m-%d") silent_reply = wechat_configs.get("silent_reply") or False post_root = (wechat_configs.get("post_folder") or "").strip("/") auto_add_date = wechat_configs.get("auto_add_date", False) add_nickname = wechat_configs.get("add_nickname", False) draft_by_default = wechat_configs.get("draft_by_default", False) one_user_one_post = wechat_configs.get("one_user_one_post", False) user_post_per_day = wechat_configs.get("user_post_per_day", False) if msg_type == "image": # 纯图片 pic_url = xml_data.get("PicUrl") if not pic_url: return "error: PicUrl is blank" filename = "%s.jpg" % (msg_id or create_time) image_insert_type = wechat_configs.get("image_insert_type") raw_image_folder = smart_unicode( wechat_configs.get("image_folder") or "").strip("/") image_folder = smart_unicode(raw_image_folder) or today if image_insert_type == "image": # 直接保存图片 path = "%s/%s" % (image_folder, filename) download_from_internet_and_sync(bucket=bucket, url=pic_url, path=path, timeout=60) # 下载图片并进行保存 if silent_reply: return "" else: return u"将保存到 %s" % path else: if raw_image_folder: # 还是按照 day 增加一层子目录,避免多了找不到的情况 path = "/%s/%s/%s" % (raw_image_folder, today, filename) else: path = "/_image/%s/%s" % (today, filename) text_to_append = "![](%s)" % path # 插入图片的语法 download_from_internet_and_sync(bucket=bucket, url=pic_url, path=path, timeout=60) else: text_to_append = xml_data.get("Content") or xml_data.get( "Recognition") or xml_data.get("EventKey") or "" text_to_append = text_to_append.strip() if "\n" not in text_to_append and re.match(u"name ", text_to_append): name = text_to_append[5:].strip() if name: set_name_by_wechat_user_id(wechat_user_id, name) return u"昵称已设定为 %s" % name if one_user_one_post: if user_post_per_day: today_string = get_now_from_bucket(bucket, "%Y-%m-%d") else: today_string = "" if post_root: if today_string: post_path = "%s/%s/%s.txt" % (post_root, wechat_user_id, today_string) else: post_path = "%s/%s.txt" % (post_root, wechat_user_id) else: if today_string: post_path = "%s/%s.txt" % (wechat_user_id, today_string) else: post_path = "%s.txt" % wechat_user_id else: if post_root: post_path = post_root + "/" + get_now_from_bucket( bucket, "%Y-%m-%d.txt") else: post_path = get_now_from_bucket(bucket, "%Y/%Y-%m-%d.txt") if text_to_append.strip() == "reset": if one_user_one_post: sync_file_by_server_side(bucket=bucket, relative_path=post_path, content=" ") return u"%s 已重置" % post_path else: return u"只有 `One User One Post` 的时候才能使用 reset 命令。" if text_to_append: if add_nickname: nickname = get_name_by_wechat_user_id(wechat_user_id) if nickname: text_to_append = "%s: %s" % (nickname, text_to_append) if auto_add_date and "\n" not in text_to_append: if text_to_append.startswith("---") or re.match( u"\w+[:\uff1a]", text_to_append): auto_add_date = False if auto_add_date: # 添加时间戳 bucket_now = get_now_from_bucket(bucket, "%Y-%m-%d %H:%M:%S") text_to_append = "%s %s" % (bucket_now, text_to_append) is_voice = True if xml_data.get("Recognition") else False text_to_append = compile_tag_to_wiki_link_syntax(text_to_append, is_voice=is_voice) # 保存文章, 5 分钟的间隔自动多一个空line append_to_markdown_doc_and_sync(bucket=bucket, path=post_path, content=text_to_append, lines_more_diff=5 * 60, draft_by_default=draft_by_default) if silent_reply: return "" else: return u"已保存至 %s" % post_path
def settings_json_editor(self, keys_config_path, private_config_keys=None, formats=None, **kwargs): # 对站点的 config 文件的编辑 # 如果指定了 private_config_keys, 则只是更新到非公开的 update_bucket_private_configs if not self.bucket: return "" logined = need_login(bucket=self.bucket) if not logined: return "" if private_config_keys and not isinstance(private_config_keys, (list, tuple)): private_config_keys = None keys_config = self.get_settings_keys_config(keys_config_path) if keys_config_path in builtin_site_settings_keys_config_info: private_config_keys_for_builtin = keys_config.get("private_keys") if private_config_keys_for_builtin: private_config_keys = private_config_keys_for_builtin hide_submit_button = False config_store_path = None config_keys = None if keys_config and isinstance(keys_config, dict): config_store_path = keys_config.get("path") config_keys = keys_config.get("keys") hide_submit_button = keys_config.get("hide_submit_button", False) if not private_config_keys: if not isinstance(config_store_path, string_types) or not isinstance( config_keys, (list, tuple)): return "config_keys format error, not allowed" if not config_store_path or not config_keys: return "config_store_path is invalid or config_keys is invalid, not allowed" if not re.match("__\w+\.json", config_store_path): return "path should be __xxxx.json, not allowed" def settings_json_editor_callback(new_data_obj): for key, value in new_data_obj.items(): if value and isinstance(value, (str, unicode)) and len(value) > 20000: return 'error: the length of value is too long' if private_config_keys: private_configs_to_update = { key: new_data_obj.get(key) for key in private_config_keys } update_bucket_private_configs(self.bucket, **private_configs_to_update) else: content = json.dumps(new_data_obj, indent=4) sync_file_by_server_side(bucket=self.bucket, relative_path=config_store_path, content=content) if request.method != "POST": # 处理 data if private_config_keys: data_obj = get_bucket_private_configs_by_keys( self.bucket, private_config_keys) else: data_obj = get_json_content_by_path(self.bucket, config_store_path) or {} if not isinstance(data_obj, dict): # 必须是 dict 类型,否则数据会被重置 data_obj = {} else: data_obj = None # will get from request.form automatic formats = formats or {} return Html.grid_form(data_obj, config_keys, formats=formats, callback_func=settings_json_editor_callback, hide_submit_button=hide_submit_button, **kwargs)
def nav_disabled(self): nav_config = get_json_content_by_path(self.bucket, 'nav.json') or {} return nav_config.get('user_nav_disabled', False)
def nav_configs(self): nav_config = get_json_content_by_path(self.bucket, 'nav.json') or {} nav_configs = nav_config.get('nav_configs') or [] return nav_configs
def show_wiki_as_sub_site(): bucket = get_bucket_in_request_context() if not bucket: return request_path = get_request_path().strip("/") if not re.match("wiki(/|$)", request_path): return wiki_configs = get_json_content_by_path(bucket, "__wiki.json", force_dict=True) wiki_root = smart_unicode(wiki_configs.get("wiki_root", "")) if not wiki_root: return set_data_root_in_request(wiki_root) # set data_root to request wiki_root = wiki_root.strip("/") wiki_title = wiki_configs.get("wiki_title") or get_just_name(wiki_root, for_folder=True) wiki_root = wiki_root.lower() kwargs = dict(wiki_root=wiki_root, wiki_title=wiki_title, wiki_configs=wiki_configs) if re.match("wiki/?$", request_path): # index docs = [] user_categories = wiki_configs.get("categories") if not isinstance(user_categories, (list, tuple)): user_categories = [] for user_category in user_categories: if not isinstance(user_category, dict): continue category_path = user_category.get("path") summary = smart_unicode(user_category.get("summary") or "") icon = smart_unicode(user_category.get("icon") or "") doc = get_record_by_path(bucket=bucket, path=category_path) if not doc: category_path = "%s/%s" % (wiki_root, category_path.strip("/")) doc = get_record_by_path(bucket=bucket, path=category_path) if not doc: continue doc_type = get_type_from_record(doc) if doc_type not in ["post", "folder"]: continue doc["icon"] = icon or get_value_from_data(doc, "metadata.icon") doc["summary"] = summary or get_value_from_data(doc, "metadata.summary") docs.append(doc) if not docs: # by default docs = Data.get_data(type='folder', level=1, limit=50, with_page=False, path=wiki_root) # 处理 url, 取 relative index_docs = [] for doc in docs: wiki_url = get_wiki_url_for_doc(wiki_root, doc) if not wiki_url: continue doc["wiki_url"] = wiki_url index_docs.append(doc) return render_api_template("builtin_theme_knowbase_index.jade", docs=index_docs, **kwargs) elif re.match("wiki/tag/", request_path): current_tag = get_offset_path(request_path, 2) if not current_tag: abort(404, "no tag?") docs = get_records_by_tag(bucket, current_tag, sort_by="-date") for doc in docs: doc["wiki_url"] = get_wiki_url_for_doc(wiki_root, doc) return render_api_template("builtin_theme_knowbase_tag.jade", current_tag=current_tag, docs=docs, **kwargs) elif re.search("wiki/search(/|$)", request_path): keywords = request.values.get("s") data_namespace = get_data_namespace() docs = data_namespace.get_data(bucket=bucket, keywords=keywords, pager_name="wiki", path=wiki_root, sort_by='-date', min_limit=8) for doc in docs: doc["wiki_url"] = get_wiki_url_for_doc(wiki_root, doc) return render_api_template("builtin_theme_knowbase_search.jade", docs=docs, **kwargs) elif re.match("wiki/category/", request_path): # category category_path = get_offset_path(request_path, 2).lower() wiki_nodes_url = "/wiki_nodes?path=%s" % category_path category_path = "%s/%s" % (wiki_root, category_path) folder_doc = get_record_by_path(bucket, category_path) enable_wiki_nodes = auto_type(wiki_configs.get("enable_wiki_nodes", True)) if not enable_wiki_nodes: wiki_nodes_url = "" if not folder_doc or get_type_from_record(folder_doc) != "folder": abort(404, "no category found") else: category = Category(folder_doc) docs = auto_pg(bucket=bucket, data_type="post", pager_name="wiki", path=category.path, ignore_marked_id=True, prefix_to_ignore='_', sort_by='-date', min_limit=8) for doc in docs: doc["wiki_url"] = get_wiki_url_for_doc(wiki_root, doc) return render_api_template("builtin_theme_knowbase_category.jade", category=category, docs=docs, wiki_nodes_url=wiki_nodes_url, **kwargs) elif re.match("wiki/post/", request_path): # detail doc_path = get_offset_path(request_path, 2) doc_path = "%s/%s" % (wiki_root, doc_path) doc = get_record_by_path(bucket, doc_path) if not doc: abort(404, "no doc found") else: return render_api_template("builtin_theme_knowbase_post.jade", doc=doc, **kwargs)
def get_wiki_root(bucket): wiki_configs = get_json_content_by_path(bucket, "__wiki.json", force_dict=True) wiki_root = smart_unicode(wiki_configs.get("wiki_root", "")) return wiki_root