def js_view(title, url=None, group_id=None, view_type='', **kwargs): if url is None: # 默认值, 这样图片调用的时候, 只要一个传入就可以了 url = title url = smart_unicode(url) if isinstance(title, (tuple, list)) and len(title) == 2: title, thumbnail = title # 图片类型的 else: title = smart_unicode(title) mime_type = guess_type(title) or '' if mime_type.startswith('image/'): thumbnail = title # title 本身就是一张图片 title = kwargs.get('alt') or os.path.split(title)[ -1] # 文件名作为 title title = smart_unicode(title) else: thumbnail = '' if not view_type: # 自动推断 if thumbnail: view_type = 'image' elif url.endswith('.mp4'): view_type = 'video' else: link_mime_type = guess_type(url) or '' if link_mime_type.startswith('image/'): view_type = 'image' else: view_type = 'iframe' class_name = kwargs.get('class_name') or '' css_class = 'js_view js_view_%s %s' % (view_type, class_name) if group_id: css_class += ' js_view_group ' else: group_id = '' dom_id = get_a_random_dom_id() html_content = render_api_template('js_view', view_type=view_type, title=title, thumbnail=thumbnail, url=url, css_class=css_class, uuid=dom_id, group_id=group_id, return_html=True, **kwargs) return html_content
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 get_compiled_data(self): mime_type = guess_type(self.path) if mime_type and mime_type.startswith('image/'): file_type = 'image' else: file_type = 'file' data = dict( _type = file_type, type = file_type, _order = self.file_order_value, ) if file_type == 'file': # 如果纯粹是 file 类型,且大小在容许的范围内,才尝试将原始内容直接放到 record 内 ext = os.path.splitext(self.path)[-1].lower().strip('.') if ext in FRONTEND_EXTS and len(self.raw_content)<MAX_RECORD_SIZE: data.update(dict( raw_content=self.raw_content, raw_content_size=len(self.raw_content), _zipped=False, )) compiled_type, compiled_content = compile_frontend_resource(ext, raw_content=self.raw_content) if compiled_content and compiled_type: data['compiled_type'] = compiled_type data['compiled_content'] = compiled_content else: raw_content = self.gb64_raw_content if len(raw_content) < MAX_RECORD_SIZE: data.update(dict( raw_content=self.gb64_raw_content, raw_content_size=len(self.gb64_raw_content), _zipped=True, )) # 而比如 图片,不论大小,全部直传 return data
def accept_upload_file_from_client(self, bucket, record_data, get_raw_content_func=None): # return ok, failed, existed if not self.should_upload_file_by_client(bucket, record_data): return "failed" filepath = self.get_filepath_from_record(bucket=bucket, record_data=record_data) if not filepath: return "failed" if not get_raw_content_func: return "failed" if hasattr(get_raw_content_func, "__call__"): raw_content = get_raw_content_func() else: raw_content = get_raw_content_func if len(raw_content) > MAX_FILE_SIZE: return "failed" if not self.exists(bucket, record_data): if not raw_content or not isinstance(raw_content, string_types): return "failed" # qcloud_cos.cos_common.maplist content_type = guess_type(record_data.get("path")) relative_path = record_data.get("path") or "" filename = os.path.split(relative_path)[-1] headers = dict() if filename: headers["ContentDisposition"] = smart_str('attachment;filename="%s"' % relative_path) if DEBUG: print("upload %s to qcloud" % relative_path) uploaded = upload_file_to_qcloud_for_bucket(bucket, filepath, raw_content, content_type=content_type, **headers) if uploaded: file_size = len(raw_content) image_info = {} if guess_type(relative_path).startswith("image/"): image_info = get_image_info_from_raw_content(raw_content) self.update_record_when_file_stored(bucket, record_data, file_size=file_size, image_info=image_info) return "ok" else: return "failed" else: if raw_content and isinstance(raw_content, string_types): file_size = len(raw_content) else: file_size = 0 self.update_record_when_file_stored(bucket, record_data, file_size=file_size) # try to update the record return "existed"
def post_title(self): # 获取post的title title = self.get_meta_value('title', '') # 文中没有声明,看有没有唯一的H1作为title if not title and getattr(self.content, 'title', None) and getattr( self.content, 'title_from_post', False): title = self.content.title if not title: # 仍然没有title的,就取文件名 title = self.title # 保留了大小写 if guess_type(title): # 如果是后缀名的,则是把title去掉后缀 title = os.path.splitext(title)[0] return smart_unicode(title.strip())
def send_file_with_304(filepath, mimetype=None): if not os.path.isfile(filepath): return # ignore if not is_filepath_modified(filepath): return get_304_response() else: mimetype = mimetype or guess_type(filepath, 'application/octet-stream') response = send_file(filepath, mimetype=mimetype) try: mtime = int(os.path.getmtime(filepath)) response.headers['Last-Modified'] = smart_str(mtime) except: pass return response
def upload_static_files_to_cdn(static_files_root, cdn_static_prefix, secret_id, secret_key, bucket, region, force_update=False): sub_filepaths = get_all_sub_files(static_files_root) for filepath in sub_filepaths: if is_a_hidden_path(filepath): continue ext = os.path.splitext(filepath)[-1] if ext in [".py", ".pyc", ".pyd"]: continue #print(filepath) relative_path = get_relative_path(filepath, static_files_root) cnd_path = "/%s/%s" % (cdn_static_prefix.strip("/"), relative_path.strip("/")) if not force_update: if has_file_on_qcloud(cnd_path, secret_id=secret_id, secret_key=secret_key, bucket=bucket, region=region): qcloud_file_meta = get_file_meta_on_qcloud( cnd_path, secret_id=secret_id, secret_key=secret_key, bucket=bucket, region=region) if qcloud_file_meta and isinstance(qcloud_file_meta, dict): q_version = qcloud_file_meta.get("ETag", "").strip("'").strip('"') if q_version and get_md5_for_file(filepath) == q_version: continue with open(filepath, "rb") as f: upload_file_obj_to_qcloud(file_obj=f, url_path=cnd_path, secret_id=secret_id, secret_key=secret_key, bucket=bucket, region=region, content_type=guess_type(filepath)) print(filepath)
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 as_web_response(self, bucket, record, mimetype="", try_resized_image=True): # 只处理存储在外部(包括本地),但不在 database 中的数据 file_stored = record.get("_file_stored") if not file_stored: return relative_path = record.get('path') if not relative_path: return # ignore local_filepath = self.get_local_filepath(bucket, record) mimetype = mimetype or guess_type( relative_path) or 'application/octet-stream' # 处理缩略图的对应 if try_resized_image and mimetype.startswith("image"): resized_image_response = get_response_for_resized_image( bucket, record, self) if resized_image_response: return resized_image_response if local_filepath: if os.path.isfile(local_filepath): response = send_file(local_filepath, mimetype=mimetype) spawn(self.update_bucket_bandwidth, bucket, record) set_304_response_for_doc(response=response, doc=record, date_field='mtime') return response else: return else: file_url = self.get_url(bucket, record) if file_url: spawn(self.update_bucket_bandwidth, bucket, record) return p_redirect(file_url) else: return
def get_download_response_for_record(self, bucket, record_data, try_resized_image=False): # 同步回去的 response # 如果是 Web 端给普通访客的,则会根据需要自动提供缩略图的逻辑支持 raw_content = record_data.get('raw_content') or record_data.get( 'content') or '' if raw_content and record_data.get('_zipped'): try: raw_content = ungzip_content(raw_content, base64=True) except: pass mime_type = guess_type(record_data.get( "path", "")) or "application/octet-stream" if raw_content: raw_content = to_bytes(raw_content) return send_file(io.BytesIO(raw_content), mimetype=mime_type) else: file_response = self.as_web_response( bucket, record_data, try_resized_image=try_resized_image) return file_response # 可能是 None
def accept_upload_file_from_client(self, bucket, record_data, get_raw_content_func=None): # return ok, failed, existed if not self.should_upload_file_by_client(bucket, record_data): return "failed" filepath = self.get_filepath_from_record(bucket=bucket, record_data=record_data) if not filepath: return "failed" if not get_raw_content_func: return "failed" if not os.path.isfile(filepath): if hasattr(get_raw_content_func, "__call__"): raw_content = get_raw_content_func() else: raw_content = get_raw_content_func if not raw_content or not isinstance(raw_content, string_types): return "failed" if len(raw_content) > MAX_FILE_SIZE: return "failed" if DEBUG: relative_path = record_data.get("path") or "" print("store %s to local" % relative_path) write_file(filepath, raw_content) file_size = len(raw_content) image_info = None if guess_type(filepath).startswith("image/"): image_info = get_image_info_from_raw_content(raw_content) self.update_record_when_file_stored(bucket, record_data, file_size=file_size, image_info=image_info) # update the record return "ok" else: try: file_size = os.path.getsize(filepath) or 0 except: file_size = 0 self.update_record_when_file_stored(bucket, record_data, file_size=file_size) # try to update the record return "existed"
def is_a_image_file(filepath): mimetype = guess_type(filepath) or '' if mimetype.startswith('image/'): return True else: return False
def auto_a(cls, title, href, a_title=None, class_name='', group_id='', target='', dom_id=None, **kwargs): # 跟 js_view 关联起来, a_title=alter_title; 如果不是和 js_view 则会使用a这个生成函数 href_mime_type = guess_type(href) use_js_view = False view_type = 'iframe' group_id = group_id or kwargs.pop('group', '') or '' dom_id = dom_id or get_a_random_dom_id() # 特殊 URL 的对应,因为某些场景(smartpage)中不方便定义 a_title 这个逻辑 special_protocols = ['qrcode', 'iframe'] for special_protocol in special_protocols: special_protocol_prefix = '%s://' % special_protocol if href.startswith(special_protocol_prefix): a_title = special_protocol href = href.replace(special_protocol_prefix, '', 1).strip() if '://' not in href: # 本 site 内的url,确保以 / 开头 href = '/%s' % href.lstrip('/') if not class_name: class_name = kwargs.pop('class', '') title_mime_type = guess_type(title) if title_mime_type and title_mime_type.startswith('image/'): # 自动转为图片的 html 片段 image_as_title = '<img src="%s">' % title else: image_as_title = title if title and href and isinstance(title, string_types) and isinstance( href, string_types): if href.endswith('.mp4'): # 视频的封面是图片 return cls.js_view(image_as_title, href, view_type='video', class_name=class_name) if href.endswith('.swf') or str_has( href, ['vimeo.com/video', 'youtube.com', 'youku.com', 'tudou.com'], just_in=True): use_js_view = True elif href.startswith('.') or href.startswith('#') and len( href.strip()) != 1: view_type = 'modal' use_js_view = True elif a_title == 'iframe' or str_has( href, ['gdgdocs.org', 'jinshuju', 'mikecrm.com'], just_in=True): use_js_view = True elif a_title in ["qrcode", "erweima"]: use_js_view = True view_type = 'qrcode' elif href_mime_type.startswith('image/'): use_js_view = True view_type = 'image' if use_js_view: return cls.js_view(title, href, view_type=view_type, class_name=class_name, group_id=group_id, target=target, dom_id=dom_id, **kwargs) else: return cls.a(image_as_title, href, class_name=class_name, target=target, dom_id=dom_id, **kwargs) else: return '' # failed
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, )
def is_image(obj): # 一个字符串是否是图片的 url if isinstance(obj, (str, unicode)): mime_type = guess_type(obj) if mime_type and mime_type.startswith('image/'): return False return False