def render_template_for_farbox_bucket(**kwargs): #import time; time.sleep(5) # test timeout request_path = get_request_path() template_name = request_path.strip('/') if not template_name: template_name = 'index' try: template = farbox_bucket_env.get_template(template_name) html = template.render(**kwargs) return after_render_template_for_farbox_bucket(html) except TemplateNotFound as e: # 尝试走一些 builtin themes sub_site_html = show_builtin_theme_as_sub_site() if sub_site_html: return after_render_template_for_farbox_bucket(sub_site_html) bucket = get_bucket_in_request_context() hide_post_prefix = get_site_config('hide_post_prefix', default_value=False) if bucket and hide_post_prefix: # 不带 /post 前缀的 post_doc = get_record_by_url(bucket, template_name) if post_doc: try: post_template = farbox_bucket_env.get_template("post") except: post_template = None if post_template: html = post_template.render(**kwargs) return after_render_template_for_farbox_bucket(html) if e.name == "index": abort(404, Html.i18n("please custom your template or choose a theme for site first, no homepage found.")) else: if request_path.strip("/") == "feed" and not has_template_by_name("feed"): # 如果没有自定义 feed 页面,系统默认配置的 return render_api_template_as_response("feed.jade") else: abort(404, 'not found for %s' % e.name) except Exception as e: raise e
def get_site_config(fields, type_required=None, default_value=None): if isinstance(type_required, list): type_required = tuple(type_required) bucket = get_bucket_in_request_context() if not bucket: if default_value is not None: return default_value else: return None site_configs = get_bucket_site_configs(bucket) if not isinstance(fields, (list, tuple)): fields = [fields] for field in fields: if not isinstance(field, string_types): continue field_value = get_value_from_data(site_configs, field) if field_value is not None: if type_required: if isinstance(field_value, type_required): return field_value else: return auto_type(field_value) if default_value is not None: return default_value else: return None
def render_as_static_resource_in_pages_for_farbox_bucket(template_filename): ext = os.path.splitext(template_filename)[-1].lower() if ext not in [ '.html', '.htm', '.js', '.css', '.json', '.jpg', '.png', '.scss', '.less', '.coffee' ]: return mime_type = '' raw_content = '' pages_configs = get_pages_configs() if not is_doc_modified(doc=pages_configs, date_field='mtime'): return get_304_response() if ext in ['.scss', '.less']: raw_content = get_template_static_resource_content('.'.join( [template_filename.rsplit('.')[0], 'css'])) mime_type = 'text/css' elif ext in ['.coffee']: raw_content = get_template_static_resource_content('.'.join( [template_filename.rsplit('.')[0], 'js'])) mime_type = 'application/javascript' if not raw_content: raw_content = get_template_static_resource_content(template_filename) if raw_content: raw_content = to_bytes(raw_content) mime_type = mime_type or guess_type( template_filename) or 'application/octet-stream' set_context_value_from_request("is_template_resource", True) file_response = send_file(io.BytesIO(raw_content), mimetype=mime_type) bucket = get_bucket_in_request_context() if bucket: set_304_response_for_doc(response=file_response, doc=pages_configs, date_field='mtime') return file_response
def cache_response_into_memcache(response): from farbox_bucket.server.web_app import sentry_client cache_client = get_cache_client() if not cache_client: return response bucket = get_bucket_in_request_context() if not bucket: return response render_data = response_to_render_data(response) if render_data: # 尝试缓存到 memcache 里 cache_expiration_time = 2 * 3600 # 2小时的缓存期 cache_key = get_cache_key_for_page() # 得到缓存的 key 值 if not cache_key: return response to_cache = pickle.dumps(render_data) cache_client.set(cache_key, to_cache, zipped=True, expiration=cache_expiration_time) if sentry_client: # for debug cached_data = cache_client.get(cache_key, zipped=True) try: if cached_data and isinstance(cached_data, (str, unicode)) and re.match( r'^\d$', cached_data): raise TypeError("meme cache error?") except: sentry_client.captureException() return response
def get_post_with_greed(url_body, parent_doc=None): pure_url_body = re.split("[?#]", url_body)[0] post_url = pure_url_body d = get_data_namespace() post_doc = d.get_doc(post_url) current_data_root = get_current_data_root() parent_doc = parent_doc or get_doc_in_request() if not post_doc and is_a_markdown_file(post_url) and parent_doc and isinstance(parent_doc, dict): filename = post_url if "/post/" in filename: filename = filename.split("/post/", 1)[-1] parent_post_doc_path = get_path_from_record(parent_doc) if parent_post_doc_path: post_doc_parent = os.path.split(parent_post_doc_path)[0] if post_doc_parent: abs_path = "%s/%s" % (post_doc_parent.strip("/"), filename.strip("/")) post_doc = d.get_doc_by_path(abs_path) if current_data_root and not post_doc: # 增加 wiki_root 作为前缀,再尝试匹配 abs_path = "%s/%s" % (current_data_root, filename.strip("/")) post_doc = d.get_doc_by_path(abs_path) if not post_doc: # 尝试 hit keyword 的方式进行搜索匹配 bucket = get_bucket_in_request_context() post_name = (get_get_var(url_body, "name") or "").strip() if post_name: if "." in post_name: post_name = os.path.splitext(post_name)[0] post_doc = get_one_post_by_es(bucket, keywords=post_name, under=current_data_root) if not post_doc and is_a_markdown_file(post_url): # 直接搜索 filename just_post_file_name = get_just_name(post_url) if just_post_file_name != post_name: post_doc = get_one_post_by_es(bucket, keywords=just_post_file_name, under=current_data_root) return post_doc
def posts_count(obj): if get_type_from_record(obj) == "folder": bucket = get_bucket_in_request_context() return get_folder_children_count(bucket, obj.get("path"), field="posts") return 0
def get_site_configs(): bucket = get_bucket_in_request_context() if not bucket: return {} site_configs = get_bucket_site_configs(bucket) if not isinstance(site_configs, dict): site_configs = {} return site_configs
def get_bucket_for_file_manager(): bucket = get_bucket_in_request_context() or request.values.get('bucket') if not bucket: bucket = get_bucket_from_request() if not is_bucket_login(bucket=bucket): abort(401) if not bucket: abort(404) return bucket
def get_records_for_request_resolver(key): if not hasattr(request, 'cached_records_for_resolver'): request.cached_records_for_resolver = {} key = key.lower().strip() if key in request.cached_records_for_resolver: # cached value return request.cached_records_for_resolver[key] if not re.match('r?records(_\d+)?$', key): return None bucket = get_bucket_in_request_context() if not bucket: return [] if key.startswith('rrecords'): reverse_scan = True else: reverse_scan = False if '_' in key: per_page = key.split('_')[-1] if not per_page: per_page = 100 # default value else: per_page = int(per_page) else: per_page = 100 if per_page < 1: per_page = 1 if per_page > 1000: # max_value per_page = 1000 icursor = request.values.get('icursor') cursor = request.values.get('cursor') or icursor if not reverse_scan: start_record_id = cursor or zero_id_for_finder end_record_id = '' else: start_record_id = cursor or '' end_record_id = zero_id_for_finder includes_start_record_id = bool(icursor) records = get_records_for_bucket( bucket, start_record_id=start_record_id, end_record_id=end_record_id, limit=per_page, reverse_scan=reverse_scan, includes_start_record_id=includes_start_record_id, ) request.cached_records_for_resolver[key] = records return records
def debug(self): bucket = get_bucket_in_request_context() if not bucket: return '' js_script_content = self.load('/__realtime.js') + self.load( '/__debug_template.js') js_script_content += '<script>connect_to_ws_by_listen_files("%s")</script>' % get_bucket_ws_url( bucket) return js_script_content
def just_get_site_config(config_key, default_value=None): bucket = get_bucket_in_request_context() if not bucket: if default_value is not None: return default_value else: return None site_configs = get_bucket_site_configs(bucket) or {} value = site_configs.get(config_key, default_value) return value
def render_404_for_farbox_bucket(): bucket = get_bucket_in_request_context() if not bucket: return try: reset_loads_in_page_in_request() template = farbox_bucket_env.get_template("404") html = template.render() return html except: return
def do_get_smart_scss_url(scss_filepath, **kwargs): # 根据其内容内的变量名,进行替换处理; # 总是要读取源文件的,不然不知道是否要重新编译; 由于页面本身的缓存逻辑,性能影响有限 # filename.scss -> filename-xxxxxxxxxxxx.css ext = os.path.splitext(scss_filepath)[-1] if ext not in [".less", ".scss"]: return scss_filepath #ignore prefix_name = get_prefix_name_from_source_filepath(scss_filepath) filename = get_md5(get_md5(kwargs.keys()) + get_md5(kwargs.values())) + '.css' filepath = '/_cache/scss/%s-%s' % (prefix_name, filename) bucket = get_bucket_in_request_context() or get_bucket_from_request() if not bucket: return scss_filepath # ignore if has_record_by_path(bucket, path=filepath): # 缓存的文件已经存在了 return filepath raw_content = "" if scss_filepath.startswith("/fb_static/"): raw_content = get_static_raw_content(scss_filepath) else: bucket = get_bucket_in_request_context() if bucket: raw_content = get_raw_content_by_path(bucket=bucket, path=scss_filepath) if not raw_content: return scss_filepath #ignore css_content = replace_vars_in_scss(raw_content=raw_content, new_vars=kwargs, compile_scss=True) sync_file_by_server_side(bucket=bucket, relative_path=filepath, content=css_content) return filepath
def get_request_path_for_bucket(path=None): if path is None: request_path = request.path else: request_path = path bucket = get_bucket_in_request_context() if bucket and bucket in request_path: try: request_path = re.search('/%s/\w+(/.*|$)' % bucket, request_path).group(1) except: pass return request_path
def cover(obj): if get_type_from_record(obj) == "folder": bucket = get_bucket_in_request_context() path = obj.get("path") if bucket and path: result = get_data(type="image", path=path, level=1, limit=1, sort="-date") if result: return get_doc_url(result[0]) return ""
def get_post_visits_count(doc, field='visits'): # field is in ['visits', 'visitors'] bucket = get_bucket_in_request_context() if not bucket: return 0 visits_db_name = get_visits_db_name_for_bucket(bucket) doc_path = doc.get('path') if not doc_path: return 0 key = get_visits_key(doc_path, field=field) count = hget(visits_db_name, key) or 0 count = to_int(count, default_if_fail=0) return count
def is_trade_under_this_site(self): # 校验当前回调的交易,是不是从当前网站发出去的 out_trade_no = request.values.get('out_trade_no') or '' if '-' not in out_trade_no: # 没有在trade_no 中增加site的信息,ignore掉, return True return True bucket = get_bucket_in_request_context() if bucket: # site_id hashed 长度为 32, 总长度为 14+8+1+32=55 < 64 hashed_bucket_id = get_md5(bucket) # 主要用作校验,避免跨站的交易被验证成功 if out_trade_no and out_trade_no.endswith( '-%s' % hashed_bucket_id): return True return False
def get_current_data_root(): bucket = get_bucket_in_request_context() if not bucket: return "" data_root = get_data_root_in_request() if data_root: return data_root site_configs = get_bucket_site_configs(bucket) if site_configs: data_root = smart_unicode(site_configs.get("posts_root") or "").strip().strip("/") return data_root else: return ""
def get_cache_key_for_page(): bucket = get_bucket_in_request_context() if not bucket: return bucket_last_updated_at = get_bucket_last_updated_at(bucket) if not bucket_last_updated_at: return url = request.url raw_cache_key = '%s-%s-%s-%s' % (bucket, bucket_last_updated_at, url, PAGE_CACHE_VERSION) lang = get_language() if lang: raw_cache_key += "-%s" % lang cache_key = "page-%s" % get_md5(raw_cache_key) return cache_key
def get_out_trade_no(self, prefix=''): # 64位最长 # 商户网站唯一订单号 prefix = smart_unicode(prefix)[:10] # 最多10位 now = get_cn_timestamp('%Y%m%d%H%M%S') # 14位了已经 uid = uuid.uuid1().hex[:8] no = '%s%s%s' % (prefix, now, uid) try: bucket = get_bucket_in_request_context() if bucket: # site_id hashed 长度为 32, 总长度为 14+8+1+32=55 < 64 hashed_bucket_id = get_md5(bucket) # 主要用作校验,避免跨站的交易被验证成功 no = '%s-%s' % (no, hashed_bucket_id) except: pass return no
def auto_bucket_url_path(url_path): if not url_path.startswith('/'): return url_path if url_path.startswith('/__'): return url_path if url_path.startswith('#'): return url_path request_path = request.path bucket = get_bucket_in_request_context() if bucket and bucket in request_path: p1, p2 = request_path.split(bucket, 1) prefix = p1 + bucket + '/' + p2.strip('/').split('/')[0] if url_path.lstrip('/').startswith(prefix.lstrip('/')): return url_path url_path = prefix + '/' + url_path.lstrip('/') return url_path
def __init__(self, path_or_record): # the record is folder self.bucket = get_bucket_in_request_context() if isinstance(path_or_record, dict): self.raw = path_or_record self.path = self.raw.get('path') else: path = path_or_record path = smart_unicode(path).strip() self.path = path record = get_record_by_path(bucket=self.bucket, path=path) or {} self.raw = record self.path = self.path.lower() if self.raw and self.raw.get('_type') != 'folder': # must be folder self.raw = {}
def update_usage_statistics(response): bucket = get_bucket_in_request_context() if not bucket: return if not isinstance(response, Response): return # requests + 1 spawn(increase_request_for_bucket, bucket) if response.status_code not in [ 301, 302, ]: bandwidth = response.content_length if bandwidth: spawn(increase_bandwidth_for_bucket, bucket, bandwidth)
def render_as_static_file_for_farbox_bucket(path): if not path or path == "/": path = "index.html" bucket = get_bucket_in_request_context() if not bucket: return record = get_record_by_path(bucket, path) if path == "favicon.ico" and not record: record = get_record_by_path(bucket, "_direct/favicon.ico") # 兼容 Bitcron if not record: return record_path = get_path_from_record(record) if record_path and record_path.startswith("/_data/"): ext = os.path.splitext(record_path)[-1].strip(".").lower() if ext in ["csv"] and not is_bucket_login(bucket): return abort( 404, "csv under /_data is not allowed to download directly") set_context_value_from_request("is_static_file", True) if record.get('compiled_type') and record.get('compiled_content'): raw_content = record.get('compiled_content') content_type = record.get('compiled_type') raw_content = to_bytes(raw_content) mimetype = content_type or guess_type( path) or 'application/octet-stream' compiled_file_response = send_file(io.BytesIO(to_bytes(raw_content)), mimetype=mimetype) return compiled_file_response else: # 先对应是否防盗链的逻辑 site_configs = get_bucket_site_configs(bucket) anti_theft_chain = site_configs.get("anti_theft_chain", True) if anti_theft_chain and request.path.strip('/') in ['favicon.ico']: anti_theft_chain = False if anti_theft_chain and request.referrer: refer_host = get_host_from_url(request.referrer) if refer_host != request.host and "." in request.path: return abort(404, "this url is not allowed for outside") return storage.get_download_response_for_record(bucket=bucket, record_data=record, try_resized_image=True)
def get_template_source(template_name): bucket = get_bucket_in_request_context() pages_configs = get_bucket_pages_configs(bucket) template_source = get_template_content_from_name(template_name, pages_configs) just_template_name = re.sub(r'\.(jade|html|htm)$', '', template_name) template_name_without_dot = just_template_name.replace('.', '_') template_name_without_dot2 = just_template_name.replace('.', '/') template_source = template_source or get_template_content_from_name(just_template_name, pages_configs) template_source = template_source or get_template_content_from_name(template_name_without_dot, pages_configs) if '.' in template_name: template_source = template_source or get_template_content_from_name(template_name_without_dot2, pages_configs) if not template_source: if template_name.startswith("builtin_theme_"): # 一些内置模板的匹配,这样可以使用 extends mixin 之类的逻辑 builtin_template_source = system_builtin_templates.get(just_template_name) if builtin_template_source: template_source = builtin_template_source if template_source: return smart_unicode(template_source) else: 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 get_comments(parent_doc, bucket=None, as_tree=None): bucket = bucket or get_bucket_in_request_context() or request.values.get('bucket') if not bucket: return [] path = to_doc_path(parent_doc) comments_doc = get_comments_record(bucket, path) site_configs = get_bucket_site_configs(bucket) if not get_value_from_data(site_configs, "comments", default=True): return [] if as_tree is None: # 自动匹配, 网站设置中对应 comments_type = get_value_from_data(site_configs, 'comments_type') or 'tree' if comments_type in ['tree']: as_tree = True else: as_tree = False utc_offset = to_float(parent_doc.get('_utc_offset'), 8) return get_comments_by_comments_doc(comments_doc, as_tree=as_tree, utc_offset=utc_offset)
def update_post_visits_for_response(response): doc = get_doc_in_request() if doc: doc_type = doc.get('_type') doc_path = doc.get('path') else: doc_type = get_doc_type_in_request() doc_path = get_doc_path_in_request() bucket = get_bucket_in_request_context() if bucket and doc_type == 'post' and doc_path: pass else: return visits_key = get_visits_key(doc_path, field='visits') visitors_key = get_visits_key(doc_path, field='visitors') now = time.time() # 直接在这里处理cookie # set cookie to know it's not a new visitor response.set_cookie('last_visited_at', str(now), max_age=one_year_seconds) last_visited_at = to_float(request.cookies.get('last_visited_at', 0)) or 0 diff = now - last_visited_at if diff > 24 * 60 * 60: # 24小时内的,认为是同一个visitor is_visitor = True else: is_visitor = False # 异步更新到数据库 spawn(async_update_visits, bucket, visits_key, visitors_key, is_visitor=is_visitor)
def current_bucket(self): return get_bucket_in_request_context() or ""
def bucket(self): return get_bucket_in_request_context()