Example #1
0
def bucket_web_for_independent_domain(web_path=''):
    # 跟 bucket web 一样, 但是呈现的是独立域名, 放到最后被 app.route 添加,以避免影响其它 view 的逻辑
    # 系统自带的前端资源
    if re.match("/(_system|admin|service|bucket)/", request.path):
        abort(
            404,
            "custom url is not allowed to startswith (_system|admin|service|bucket)"
        )
    frontend_response = send_static_frontend_resource()
    if frontend_response:
        return frontend_response
    if not web_path and not get_buckets_size():
        # 还没有 bucket 的时候,允许用户进行安装的操作
        return p_redirect("/__create_bucket?code=admin")
    bucket = get_bucket_from_request()
    if bucket:
        if request.path in ['/robot.txt', '/robots.txt']:
            if not get_bucket_private_config(
                    bucket, "enable_web_robots", default=True):
                # 禁用爬虫
                robot_content = 'User-agent: *\nDisallow: /'
                return Response(robot_content, mimetype='text/plain')
        if request.url.startswith("http://") and get_bucket_private_config(
                bucket, "enable_https_force_redirect", default=False):
            # 强制跳转 https, 不用永久 301 code,避免用户自己切换后不成功
            return redirect(request.url.replace('http://', 'https://', 1),
                            code=302)
        set_site_in_request(get_bucket_site_configs(bucket))
        return render_bucket(bucket, web_path)
    else:
        abort(404, 'no bucket found')


################# for web pages ends ##########
Example #2
0
    def get_doc(self, path, **kwargs):
        path = path.lower().strip('/').strip()
        if "?" in path:
            path = path.split("?")[0]
        if "#" in path:
            path = path.split("#")[0]
        doc = self.get_doc_by_url(path) or self.get_doc_by_path(path) or {}
        if path == 'settings.json':
            doc['raw_content'] = json.dumps(get_bucket_site_configs(
                self.bucket),
                                            indent=4,
                                            ensure_ascii=False)  #ensure_ascii
        if not doc:
            return

        if doc.get("_zipped"):
            doc["raw_content"] = get_raw_content_by_record(doc)

        doc_type = doc.get('_type') or doc.get('type')
        if kwargs.get('type') and kwargs.get('type') != doc_type:
            return None
        as_context_doc = kwargs.get('as_context_doc')
        if as_context_doc and doc:
            set_doc_in_request(doc)
        return doc
Example #3
0
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 ""
Example #4
0
def add_new_comment_web_view():
    bucket = request.values.get("bucket")
    site_configs = get_bucket_site_configs(bucket)
    if not site_configs:
        comments_allowed = False
    else:
        comments_allowed = site_configs.get("comments")
    if not comments_allowed:
        abort(404, 'comment is not allowed in this site')
    new_comment_doc = add_comment()
    if new_comment_doc.get('error'):  # 错误信息
        return jsonify(new_comment_doc)
    if request.values.get('format') in ['json', 'JSON']:
        return jsonify(new_comment_doc)
    else:
        return render_api_template('comment.jade', comment=new_comment_doc)
Example #5
0
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
Example #6
0
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)
Example #7
0
def comments_as_html(obj):
    doc = obj
    site_configs = get_bucket_site_configs()
    should_hide_comments = not get_value_from_data(site_configs, 'comments',
                                                   True)
    third_party_comments_script = get_value_from_data(
        site_configs, 'third_party_comments_script') or ''
    third_party_comments_script = smart_unicode(
        third_party_comments_script.strip())
    if third_party_comments_script:  # 有第三方评论脚本,直接进行替换
        should_hide_comments = True

    if not should_hide_comments and get_value_from_data(
            doc, 'metadata.comment') in [False, 'no', 'No']:
        # doc 本身不允许显示
        should_hide_comments = True

    if should_hide_comments:  # 不显示评论系统
        return third_party_comments_script

    html = render_api_template('comments.jade', doc=doc)
    return html
Example #8
0
 def posts_root(self):
     if not self.bucket:
         return ""
     site_configs = get_bucket_site_configs(self.bucket)
     root = smart_unicode(site_configs.get("posts_root", "")).strip()
     return root
Example #9
0
 def site_configs(self):
     return get_bucket_site_configs()
Example #10
0
    def get_data(type='post',
                 limit=None,
                 page=None,
                 path=None,
                 level=None,
                 level_start=None,
                 level_end=None,
                 excludes=None,
                 status=None,
                 with_page=True,
                 pager_name=None,
                 sort='desc',
                 return_count=False,
                 date_start=None,
                 date_end=None,
                 ignore_marked_id=None,
                 prefix_to_ignore=None,
                 keywords=None,
                 min_limit=0,
                 **kwargs):

        # 对 Bitcron 的兼容, tag for get_data
        tag_to_match = kwargs.get("tags") or kwargs.get("tag")
        if tag_to_match:
            if isinstance(tag_to_match, (list, tuple)):
                tag_to_match = tag_to_match[0]
        if tag_to_match:
            tag_match_records = get_records_by_tag(
                get_bucket_in_request_context(),
                tag=tag_to_match,
                sort_by="-date" if sort == "desc" else "date")
            if return_count:
                return len(tag_match_records)
            return tag_match_records

        if isinstance(type, (list, tuple)) and type:
            type = type[0]

        if isinstance(type, string_types
                      ) and "+" in type:  # 兼容旧的 Bitcron, 查询索引所限,只能单一 post
            type = type.split("+")[0].strip()

        if type == "all":
            type = None

        if level is not None and level_start is None and level_end is None:
            # 重新计算 level,如果给 level,是相当于 path 的相对路径
            level_start, level_end = level_to_level_start_and_end(level=level,
                                                                  path=path)

        if prefix_to_ignore is None:
            if type in ['post']:
                prefix_to_ignore = '_'

        if ignore_marked_id is None:
            if type in ['post']:
                ignore_marked_id = True
                if status == "all":
                    ignore_marked_id = False
            else:
                ignore_marked_id = False

        bucket = get_bucket_in_request_context()

        if type == "post" and path is None and bucket:
            # 尝试取得 posts_root,可以分离数据, 这是默认的情况, 即使指定了 path = "", 也不走这个逻辑
            site_configs = get_bucket_site_configs(bucket)
            posts_root = smart_unicode(site_configs.get("posts_root",
                                                        "")).strip()
            if posts_root:
                path = posts_root

        if keywords:
            obj_list = pg_with_keywords_search(
                bucket=bucket,
                keywords=keywords,
                limit=limit,
                with_page=with_page,
                page=page,
                pager_name=pager_name,
                path=path,
                excludes=excludes,
                status=status,
                sort_by=sort,
                return_total_count=return_count,
                date_start=date_start,
                date_end=date_end,
                min_limit=min_limit,
            )

        else:
            obj_list = auto_pg(
                bucket=bucket,
                data_type=type,
                limit=limit,
                with_page=with_page,
                page=page,
                pager_name=pager_name,
                path=path,
                level_start=level_start,
                level_end=level_end,
                excludes=excludes,
                status=status,
                sort_by=sort,  # for position 才特殊处理
                return_total_count=return_count,
                date_start=date_start,
                date_end=date_end,
                ignore_marked_id=ignore_marked_id,
                prefix_to_ignore=prefix_to_ignore,
                min_limit=min_limit,
            )

        fields = kwargs.get('fields')
        if fields and isinstance(fields,
                                 (list, tuple)) and obj_list and isinstance(
                                     obj_list, (list, tuple)):
            obj_list = [{
                key: value
                for key, value in obj.items() if key in fields
            } for obj in obj_list if isinstance(obj, dict)]
        return obj_list
Example #11
0
def show_albums_as_sub_site():
    bucket = get_bucket_in_request_context()
    if not bucket:
        return
    request_path = get_request_path().strip("/")
    if not re.match("album(/|$)", request_path):
        return
    if "." in request_path and guess_type(
            request_path, default_type="").startswith("image/"):
        # 可能是直接的图片地址,避免被整个 album 给拦截了
        return
    site_configs = get_bucket_site_configs(bucket)
    albums_root = smart_unicode(site_configs.get("albums_root", ""))
    if not albums_root:
        return
    albums_root = albums_root.strip("/")  #todo 允许直接设定 / ?
    albums_home_sort = site_configs.get("albums_home_sort", "-date")
    album_items_sort = site_configs.get("album_items_sort", "-date")

    page_title = site_configs.get("albums_title") or get_just_name(
        albums_root, for_folder=True)

    if re.match("album/?$", request_path):
        # folders
        doc_type = "folder"
        doc_sort = albums_home_sort
        under = albums_root
    else:
        doc_type = "image"
        doc_sort = album_items_sort
        under = "%s/%s" % (albums_root, request_path.split("/",
                                                           1)[-1].strip("/"))
        folder_doc = get_record_by_path(bucket=bucket, path=under)
        if folder_doc:
            page_title = folder_doc.get("title") or get_just_name(
                folder_doc.get("path"), for_folder=True)
        else:
            page_title = get_just_name(under, for_folder=True)

    if doc_sort not in ["date", "-date"]:
        doc_sort = "-date"

    limit = 15  # todo 可以设定?
    doc_level = 1

    # min_images_count = 1
    docs = Data.get_data(path=under,
                         type=doc_type,
                         limit=limit,
                         level=doc_level,
                         sort=doc_sort,
                         pager_name='album_docs_pager',
                         exclude='default')

    if doc_type == "folder":
        for doc in docs:
            doc_path = get_path_from_record(doc, is_lower=True)
            relative_path = doc_path.replace(albums_root.lower(), "",
                                             1).strip("/")
            doc["album_url"] = "/album/%s" % relative_path

    return render_api_template(
        "builtin_theme_album_waterfall.jade",
        docs=docs,
        page_title=page_title,
    )
Example #12
0
 def update_site_obj_first(self):
     site_obj = get_bucket_site_configs(self.bucket)
     if isinstance(site_obj, dict):
         self.update(site_obj)
Example #13
0
def get_response_for_resized_image(bucket, record, storage):
    from farbox_bucket.server.helpers.file_manager import sync_file_by_server_side
    if not record or not isinstance(record, dict):
        return

    if record.get("_get_im_failed"):
        return
    #if not is_doc_modified(record, date_field='mtime'): #todo ????
    #   return get_304_response()

    if request.args.get('origin') in ['true']:
        return  # ignore
    relative_path = record.get('path')
    if not relative_path:
        return
    file_id = get_file_id_from_record(record)
    if not file_id:
        return
    ext = os.path.splitext(relative_path)[-1].strip('.').lower()
    if ext not in ['png', 'jpg', 'jpeg', 'bmp', 'png']:
        return
    if not can_resize_by_system():
        return
    site_settings = get_bucket_site_configs(bucket)
    image_max_width = to_int(site_settings.get('image_max_width'),
                             default_if_fail=None)

    size_from_request = request.values.get("size")
    if size_from_request == "m":
        image_max_width = 600

    if not isinstance(image_max_width, int) or image_max_width < 100:
        image_max_width = None
    image_max_height = to_int(site_settings.get('image_max_height'),
                              default_if_fail=None)
    if not isinstance(image_max_height, int) or image_max_height < 100:
        image_max_height = None
    if not image_max_height and not image_max_width:
        return

    # 处理 image_max_type 允许的值
    image_max_type = (get_site_config('image_max_type')
                      or 'webp-jpg').lower().strip()
    if not isinstance(image_max_type, string_types):
        image_max_type = 'webp-jpg'
    if not re.match("[a-z-]+$", image_max_type):
        image_max_type = "jpg"

    if "webp" in image_max_type:
        request_client_accept = request.headers.get("Accept") or ""
        if "image/webp" not in request_client_accept:
            # webp 浏览器不支持的情况下
            image_max_type = "png" if ext == "png" else "jpg"

    if image_max_type == 'webp-jpg':
        mimetype = 'image/webp'
    else:
        if '/' not in image_max_type:
            mimetype = 'image/%s' % image_max_type
        else:
            mimetype = image_max_type
        if mimetype == 'image/jpg':
            mimetype = 'image/jpeg'

    if "webp" not in mimetype:
        # 非 webp,并且文件中能读取到 size 的,判断是否需要进行缩略图的处理
        image_width = record.get("image_width")
        image_height = record.get("image_height")
        if image_width and image_height:
            if image_max_width and image_width < image_max_width:
                return
            if image_max_height and image_height < image_max_height:
                return
    if "webp" in image_max_type:
        ext = "webp"

    cache_image_filepath = "_cache/images/%s/%s-%s-%s.%s" % (
        file_id, image_max_type, image_max_width, image_max_height, ext)
    cache_image_record = get_record_by_path(bucket=bucket,
                                            path=cache_image_filepath)

    if cache_image_record:
        # 已经存在了
        return storage.as_web_response(bucket=bucket,
                                       record=cache_image_record,
                                       mimetype=mimetype,
                                       try_resized_image=False)
    else:
        # todo 这里应该增加一个 time-block,避免潜在的攻击存在
        # 构建一个缩略图
        raw_content = storage.get_raw_content(bucket=bucket,
                                              record_data=record)
        if not raw_content: return
        try:
            im = get_im(raw_content)
        except:
            im = None
        if not im:
            # 标识,下次就不会尝试了
            update_record(bucket,
                          record_id=record.get("_id"),
                          _get_im_failed=True)
            return
        degrees = to_int(record.get("degrees"), default_if_fail=0)
        if image_max_type == 'webp-jpg':
            #resized_jpg_content = resize_image(im, width=image_max_width, height=image_max_height, image_type='jpg')
            #resized_jpg_im = get_im(resized_jpg_content)
            resized_im_content = resize_image(im,
                                              width=image_max_width,
                                              height=image_max_height,
                                              image_type='webp',
                                              degrees=degrees)
            if not resized_im_content:
                update_record(bucket,
                              record_id=record.get("_id"),
                              _get_im_failed=True)
                return
            #del im, resized_im_content # resized_jpg_im,
        else:
            resized_im_content = resize_image(im,
                                              width=image_max_width,
                                              height=image_max_height,
                                              image_type=image_max_type,
                                              degrees=degrees)
        cache_image_record = sync_file_by_server_side(
            bucket=bucket,
            relative_path=cache_image_filepath,
            content=resized_im_content,
            is_dir=False,
            is_deleted=False,
            return_record=True)
        if cache_image_record:
            return storage.as_web_response(bucket=bucket,
                                           record=cache_image_record,
                                           mimetype=mimetype,
                                           try_resized_image=False)