├── .gitignore
├── LICENSE
├── MANIFEST.in
├── farbox_bucket
├── LICENSE.py
├── __init__.py
├── bucket
│ ├── __init__.py
│ ├── clouds
│ │ ├── __init__.py
│ │ └── storage
│ │ │ ├── __init__.py
│ │ │ └── qcloud.py
│ ├── create.py
│ ├── defaults.py
│ ├── delete.py
│ ├── domain
│ │ ├── __init__.py
│ │ ├── info.py
│ │ ├── register.py
│ │ ├── ssl_utils.py
│ │ ├── utils.py
│ │ └── web_utils.py
│ ├── helper
│ │ ├── __init__.py
│ │ └── files_related.py
│ ├── invite.py
│ ├── node.py
│ ├── private_configs.py
│ ├── record
│ │ ├── __init__.py
│ │ ├── create.py
│ │ ├── get
│ │ │ ├── __init__.py
│ │ │ ├── folder.py
│ │ │ ├── get.py
│ │ │ ├── helper.py
│ │ │ ├── mix.py
│ │ │ ├── path_related.py
│ │ │ ├── refer_doc_related.py
│ │ │ ├── slash_related.py
│ │ │ ├── tag_related.py
│ │ │ └── utils.py
│ │ ├── helper
│ │ │ ├── __init__.py
│ │ │ └── update_record.py
│ │ ├── related
│ │ │ ├── __init__.py
│ │ │ ├── for_all.py
│ │ │ ├── for_created.py
│ │ │ ├── for_deleted.py
│ │ │ └── sub
│ │ │ │ ├── __init__.py
│ │ │ │ ├── for_posts.py
│ │ │ │ └── utils.py
│ │ ├── reset.py
│ │ ├── update.py
│ │ └── utils.py
│ ├── service
│ │ ├── __init__.py
│ │ ├── bucket_service_info.py
│ │ └── yearly_bucket_by_alipay.py
│ ├── status.py
│ ├── storage
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── default.py
│ │ ├── helpers
│ │ │ ├── __init__.py
│ │ │ ├── auto_resized_image.py
│ │ │ └── before_store_image.py
│ │ ├── local_file_system.py
│ │ └── qcloud_storage.py
│ ├── sync
│ │ ├── __init__.py
│ │ ├── node.py
│ │ ├── remote.py
│ │ └── sync_api.py
│ ├── template_related
│ │ ├── __init__.py
│ │ ├── bucket_template_web_api.py
│ │ └── load_theme_from_template_folder.py
│ ├── token
│ │ ├── __init__.py
│ │ ├── bucket_api_token.py
│ │ ├── bucket_signature_and_check.py
│ │ ├── simple_encrypt_token.py
│ │ └── utils.py
│ ├── usage
│ │ ├── __init__.py
│ │ └── bucket_usage_utils.py
│ ├── utils.py
│ └── web_api
│ │ ├── __init__.py
│ │ ├── handler.py
│ │ └── verify.py
├── client
│ ├── __init__.py
│ ├── action.py
│ ├── debug_site.py
│ ├── dump_template.py
│ ├── message.py
│ ├── project.py
│ ├── run.py
│ ├── sync
│ │ ├── __init__.py
│ │ ├── compiler
│ │ │ ├── __init__.py
│ │ │ ├── basic_compiler.py
│ │ │ ├── comments_compiler.py
│ │ │ ├── file_compiler.py
│ │ │ ├── folder_compiler.py
│ │ │ ├── post_compiler.py
│ │ │ ├── utils.py
│ │ │ └── visits_compiler.py
│ │ ├── compiler_worker.py
│ │ ├── site.py
│ │ └── sync.py
│ └── sync_from
│ │ ├── __init__.py
│ │ └── sync_from.py
├── clouds
│ ├── __init__.py
│ ├── dropbox
│ │ └── __init__.py
│ ├── qcloud.py
│ └── wechat
│ │ ├── __init__.py
│ │ ├── bind_wechat.py
│ │ ├── build_wechat_menu.py
│ │ ├── utils
│ │ ├── __init__.py
│ │ ├── __message_template.py
│ │ ├── _message_template.py
│ │ ├── check.py
│ │ ├── menu.py
│ │ ├── message.py
│ │ └── token.py
│ │ ├── views.py
│ │ ├── wechat_handler.py
│ │ └── wechat_text_image_sync_worker.py
├── console.py
├── deploy
│ ├── __init__.py
│ ├── build
│ │ ├── __init__.py
│ │ ├── build_client_image.py
│ │ └── build_image.py
│ ├── deploy.py
│ └── run
│ │ ├── __init__.py
│ │ ├── configs
│ │ ├── __init__.py
│ │ ├── backend_jobs.py
│ │ ├── backup
│ │ │ └── nginx_websocket.conf
│ │ ├── gunicorn.conf.py
│ │ ├── gunicorn_websocket.conf.py
│ │ ├── memcached.conf
│ │ ├── nginx
│ │ │ ├── nginx.conf
│ │ │ ├── nginx_body.conf
│ │ │ ├── server.crt
│ │ │ └── server.key
│ │ ├── openresty
│ │ │ ├── access.lua
│ │ │ ├── auto_ssl.lua
│ │ │ └── lib
│ │ │ │ └── resty
│ │ │ │ ├── http.lua
│ │ │ │ └── http_headers.lua
│ │ ├── ssdb.conf
│ │ └── supervisord.conf
│ │ ├── files.py
│ │ └── run.sh
├── for_dev
│ ├── __init__.py
│ ├── check_alipay.py
│ ├── check_encrypt_performance.py
│ ├── jinja_template_source.py
│ └── markdown_post_compile_info.py
├── i18n
│ ├── __init__.py
│ └── zh_cn.py
├── server
│ ├── __init__.py
│ ├── avatar.py
│ ├── avatar_view.py
│ ├── backend
│ │ ├── __init__.py
│ │ ├── backend_jobs.py
│ │ ├── service.py
│ │ ├── status
│ │ │ ├── __init__.py
│ │ │ ├── bucket_web_template.py
│ │ │ └── server_status.py
│ │ └── sync
│ │ │ ├── __init__.py
│ │ │ ├── buckets.py
│ │ │ └── utils.py
│ ├── bucket_render
│ │ ├── __init__.py
│ │ ├── _keys_config_info.py
│ │ ├── builtin_theme
│ │ │ ├── __init__.py
│ │ │ ├── _render.py
│ │ │ ├── album.py
│ │ │ └── wiki.py
│ │ ├── render.py
│ │ └── static_file.py
│ ├── comments
│ │ ├── __init__.py
│ │ ├── add.py
│ │ ├── contacts.py
│ │ ├── dump.py
│ │ ├── notification.py
│ │ ├── template.py
│ │ └── utils.py
│ ├── dangerous
│ │ ├── __init__.py
│ │ ├── install_py_package.py
│ │ ├── log_rotate.py
│ │ ├── restart.py
│ │ └── start_elasticsearch_server.py
│ ├── es
│ │ ├── __init__.py
│ │ ├── es_client.py
│ │ ├── es_search.py
│ │ ├── es_status.py
│ │ ├── es_sync_db_data.py
│ │ └── es_utils.py
│ ├── helpers
│ │ ├── __init__.py
│ │ ├── bucket.py
│ │ ├── file_manager.py
│ │ ├── file_manager_downloader.py
│ │ ├── markdown_doc_append_worker.py
│ │ ├── smart_scss.py
│ │ └── upload_static_files_to_cdn.py
│ ├── realtime
│ │ ├── __init__.py
│ │ ├── server.py
│ │ └── utils.py
│ ├── static
│ │ ├── __init__.py
│ │ ├── api
│ │ │ ├── html
│ │ │ │ ├── auto_sidebar
│ │ │ │ │ ├── auto_sidebar.coffee
│ │ │ │ │ ├── auto_sidebar.css
│ │ │ │ │ ├── auto_sidebar.js
│ │ │ │ │ └── auto_sidebar.scss
│ │ │ │ ├── auto_toc
│ │ │ │ │ ├── affix.js
│ │ │ │ │ ├── auto_toc.coffee
│ │ │ │ │ ├── auto_toc.css
│ │ │ │ │ ├── auto_toc.js
│ │ │ │ │ ├── auto_toc.scss
│ │ │ │ │ ├── mixed.js
│ │ │ │ │ └── scrollspy.js
│ │ │ │ ├── form
│ │ │ │ │ ├── ajax.coffee
│ │ │ │ │ ├── ajax.js
│ │ │ │ │ ├── ajax_submit.coffee
│ │ │ │ │ ├── ajax_submit.js
│ │ │ │ │ ├── fields
│ │ │ │ │ │ ├── color.coffee
│ │ │ │ │ │ ├── color.js
│ │ │ │ │ │ ├── form.coffee
│ │ │ │ │ │ ├── form.css
│ │ │ │ │ │ ├── form.js
│ │ │ │ │ │ ├── form.scss
│ │ │ │ │ │ ├── icon.coffee
│ │ │ │ │ │ ├── icon.js
│ │ │ │ │ │ ├── image.coffee
│ │ │ │ │ │ └── image.js
│ │ │ │ │ ├── file_field.coffee
│ │ │ │ │ ├── file_field.js
│ │ │ │ │ ├── grid_form.css
│ │ │ │ │ ├── grid_form.scss
│ │ │ │ │ ├── simple_form.css
│ │ │ │ │ └── simple_form.scss
│ │ │ │ └── js_view
│ │ │ │ │ ├── colorbox.css
│ │ │ │ │ ├── images
│ │ │ │ │ ├── border1.png
│ │ │ │ │ ├── border2.png
│ │ │ │ │ ├── loading.gif
│ │ │ │ │ └── readme.txt
│ │ │ │ │ ├── jquery.colorbox.js
│ │ │ │ │ ├── jquery.modal.css
│ │ │ │ │ ├── jquery.modal.js
│ │ │ │ │ ├── jquery.qrcode.js
│ │ │ │ │ ├── jquery.qrcode.min.js
│ │ │ │ │ ├── js_view.coffee
│ │ │ │ │ └── js_view.js
│ │ │ └── syntax
│ │ │ │ ├── modal.coffee
│ │ │ │ ├── modal.css
│ │ │ │ ├── modal.js
│ │ │ │ ├── modal.scss
│ │ │ │ ├── page
│ │ │ │ ├── load_pages.coffee
│ │ │ │ └── load_pages.js
│ │ │ │ ├── slider
│ │ │ │ ├── slider.coffee
│ │ │ │ ├── slider.css
│ │ │ │ ├── slider.js
│ │ │ │ └── slider.scss
│ │ │ │ ├── tab.css
│ │ │ │ └── tab.scss
│ │ ├── basic
│ │ │ ├── basic.css
│ │ │ ├── basic.scss
│ │ │ ├── footer.css
│ │ │ ├── footer.scss
│ │ │ ├── post_preview.css
│ │ │ ├── post_preview.scss
│ │ │ ├── simple_list.css
│ │ │ └── simple_list.scss
│ │ ├── builtin_themes
│ │ │ ├── knowbase
│ │ │ │ ├── particles.js
│ │ │ │ ├── run_particles.js
│ │ │ │ ├── style.css
│ │ │ │ └── style.scss
│ │ │ └── waterfall
│ │ │ │ ├── responsive_waterfall.js
│ │ │ │ ├── script.coffee
│ │ │ │ ├── script.js
│ │ │ │ ├── style.css
│ │ │ │ └── style.scss
│ │ ├── comments
│ │ │ ├── script.coffee
│ │ │ ├── script.js
│ │ │ ├── style.css
│ │ │ └── style.scss
│ │ ├── datatables
│ │ │ ├── DataTables-1.10.20
│ │ │ │ ├── css
│ │ │ │ │ ├── dataTables.bootstrap.css
│ │ │ │ │ ├── dataTables.bootstrap.min.css
│ │ │ │ │ ├── dataTables.bootstrap4.css
│ │ │ │ │ ├── dataTables.bootstrap4.min.css
│ │ │ │ │ ├── dataTables.foundation.css
│ │ │ │ │ ├── dataTables.foundation.min.css
│ │ │ │ │ ├── dataTables.jqueryui.css
│ │ │ │ │ ├── dataTables.jqueryui.min.css
│ │ │ │ │ ├── dataTables.semanticui.css
│ │ │ │ │ ├── dataTables.semanticui.min.css
│ │ │ │ │ ├── jquery.dataTables.css
│ │ │ │ │ └── jquery.dataTables.min.css
│ │ │ │ ├── images
│ │ │ │ │ ├── sort_asc.png
│ │ │ │ │ ├── sort_asc_disabled.png
│ │ │ │ │ ├── sort_both.png
│ │ │ │ │ ├── sort_desc.png
│ │ │ │ │ └── sort_desc_disabled.png
│ │ │ │ └── js
│ │ │ │ │ ├── dataTables.bootstrap.js
│ │ │ │ │ ├── dataTables.bootstrap.min.js
│ │ │ │ │ ├── dataTables.bootstrap4.js
│ │ │ │ │ ├── dataTables.bootstrap4.min.js
│ │ │ │ │ ├── dataTables.foundation.js
│ │ │ │ │ ├── dataTables.foundation.min.js
│ │ │ │ │ ├── dataTables.jqueryui.js
│ │ │ │ │ ├── dataTables.jqueryui.min.js
│ │ │ │ │ ├── dataTables.semanticui.js
│ │ │ │ │ ├── dataTables.semanticui.min.js
│ │ │ │ │ ├── jquery.dataTables.js
│ │ │ │ │ └── jquery.dataTables.min.js
│ │ │ ├── datatables.css
│ │ │ ├── datatables.js
│ │ │ ├── datatables.min.css
│ │ │ └── datatables.min.js
│ │ ├── defaults
│ │ │ ├── admin.png
│ │ │ ├── avatar.png
│ │ │ ├── drop_image_here.png
│ │ │ ├── favicon.ico
│ │ │ ├── site_avatar.png
│ │ │ └── visitor.png
│ │ ├── donate
│ │ │ ├── alipay.jpg
│ │ │ └── wechat.jpg
│ │ ├── gfonts
│ │ │ ├── Josefin+Sans_400_normal.svg
│ │ │ ├── Josefin+Sans_400_normal.ttf
│ │ │ ├── Josefin+Sans_400_normal.woff
│ │ │ ├── Julius+Sans+One_400_normal.svg
│ │ │ ├── Julius+Sans+One_400_normal.ttf
│ │ │ ├── Julius+Sans+One_400_normal.woff
│ │ │ ├── Lato_400_normal.svg
│ │ │ ├── Lato_400_normal.ttf
│ │ │ ├── Lato_400_normal.woff
│ │ │ ├── calligraffitti-regular-webfont.eot
│ │ │ ├── calligraffitti-regular-webfont.svg
│ │ │ ├── calligraffitti-regular-webfont.ttf
│ │ │ ├── calligraffitti-regular-webfont.woff
│ │ │ └── calligraffitti-regular-webfont.woff2
│ │ ├── images
│ │ │ ├── border1.png
│ │ │ ├── border2.png
│ │ │ ├── loading.gif
│ │ │ └── readme.txt
│ │ ├── lib
│ │ │ ├── animate.3.5.2.min.css
│ │ │ ├── essage
│ │ │ │ ├── essage.css
│ │ │ │ └── essage.js
│ │ │ ├── fontawesome
│ │ │ │ ├── css
│ │ │ │ │ ├── font-awesome.css
│ │ │ │ │ ├── font-awesome.css.map
│ │ │ │ │ └── font-awesome.min.css
│ │ │ │ ├── fonts
│ │ │ │ │ ├── FontAwesome.otf
│ │ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ │ ├── fontawesome-webfont.svg
│ │ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ │ └── fontawesome-webfont.woff2
│ │ │ │ └── selector
│ │ │ │ │ ├── icon-selector.css
│ │ │ │ │ └── icon-selector.js
│ │ │ ├── fonts
│ │ │ │ ├── merriweather.css
│ │ │ │ ├── merriweather
│ │ │ │ │ ├── 1.woff2
│ │ │ │ │ ├── 2.woff2
│ │ │ │ │ ├── 3.woff2
│ │ │ │ │ └── 4.woff2
│ │ │ │ └── open_sans.css
│ │ │ ├── hint.min.css
│ │ │ ├── jquery-linedtextarea.css
│ │ │ ├── jquery-linedtextarea.js
│ │ │ ├── jquery-ui.min.js
│ │ │ ├── jquery.contextMenu.css
│ │ │ ├── jquery.contextMenu.js
│ │ │ ├── jquery.dateFormat-1.0.js
│ │ │ ├── jquery.form.js
│ │ │ ├── jquery.js
│ │ │ ├── jquery.json.min.js
│ │ │ ├── jquery.modal.css
│ │ │ ├── jquery.modal.js
│ │ │ ├── jquery.qrcode.js
│ │ │ ├── jquery.qrcode.min.js
│ │ │ ├── jquery.tabslet.min.js
│ │ │ ├── js.cookie.js
│ │ │ ├── jstree
│ │ │ │ ├── jstree.js
│ │ │ │ ├── jstree.min.js
│ │ │ │ └── themes
│ │ │ │ │ ├── default-dark
│ │ │ │ │ ├── 32px.png
│ │ │ │ │ ├── 40px.png
│ │ │ │ │ ├── style.css
│ │ │ │ │ ├── style.min.css
│ │ │ │ │ └── throbber.gif
│ │ │ │ │ └── default
│ │ │ │ │ ├── 32px.png
│ │ │ │ │ ├── 40px.png
│ │ │ │ │ ├── style.css
│ │ │ │ │ ├── style.min.css
│ │ │ │ │ └── throbber.gif
│ │ │ ├── mark
│ │ │ │ ├── jquery.mark.js
│ │ │ │ ├── jquery.mark.min.js
│ │ │ │ ├── mark.js
│ │ │ │ └── mark.min.js
│ │ │ ├── markdown
│ │ │ │ ├── basic.css
│ │ │ │ ├── basic.scss
│ │ │ │ ├── markdown.css
│ │ │ │ └── markdown.scss
│ │ │ ├── markdown_js
│ │ │ │ ├── echarts.min.js
│ │ │ │ ├── flowchart.js
│ │ │ │ ├── flowchart.js.map
│ │ │ │ ├── mathjax
│ │ │ │ │ └── tex-svg.js
│ │ │ │ ├── mermaid
│ │ │ │ │ ├── mermaid.css
│ │ │ │ │ ├── mermaid.dark.css
│ │ │ │ │ ├── mermaid.forest.css
│ │ │ │ │ └── mermaid.min.js
│ │ │ │ ├── mindmap
│ │ │ │ │ ├── d3-flextree.js
│ │ │ │ │ ├── d3-tip.js
│ │ │ │ │ ├── d3.min.js
│ │ │ │ │ ├── d3_LICENSE.txt
│ │ │ │ │ ├── demo.html
│ │ │ │ │ ├── markmap_LICENSE.txt
│ │ │ │ │ ├── md.css
│ │ │ │ │ ├── readme.txt
│ │ │ │ │ ├── run.js
│ │ │ │ │ ├── view.mindmap.css
│ │ │ │ │ └── view.mindmap.js
│ │ │ │ └── raphael-min.js
│ │ │ ├── menu
│ │ │ │ ├── jquery-ui.custom.min.js
│ │ │ │ ├── jquery.mjs.nestedSortable.js
│ │ │ │ └── smartmenu
│ │ │ │ │ ├── LICENSE-MIT
│ │ │ │ │ ├── css
│ │ │ │ │ ├── sm-base.css
│ │ │ │ │ ├── sm-base.scss
│ │ │ │ │ ├── sm-blue
│ │ │ │ │ │ └── sm-blue.css
│ │ │ │ │ ├── sm-clean
│ │ │ │ │ │ └── sm-clean.css
│ │ │ │ │ ├── sm-core-css.css
│ │ │ │ │ ├── sm-mint
│ │ │ │ │ │ └── sm-mint.css
│ │ │ │ │ └── sm-simple
│ │ │ │ │ │ └── sm-simple.css
│ │ │ │ │ ├── jquery.smartmenus.js
│ │ │ │ │ └── jquery.smartmenus.min.js
│ │ │ ├── minicolors
│ │ │ │ ├── jquery.minicolors.css
│ │ │ │ ├── jquery.minicolors.js
│ │ │ │ └── jquery.minicolors.min.js
│ │ │ ├── pure.css
│ │ │ ├── pure_patch.css
│ │ │ ├── pure_patch.scss
│ │ │ ├── textcomplete
│ │ │ │ ├── jquery.textcomplete.js
│ │ │ │ └── jquery.textcomplete.min.js
│ │ │ ├── three
│ │ │ │ ├── 3d-force-graph.min.js
│ │ │ │ ├── three-spritetext.min.js
│ │ │ │ └── three.js
│ │ │ ├── unslider
│ │ │ │ ├── css
│ │ │ │ │ ├── unslider-dots.css
│ │ │ │ │ └── unslider.css
│ │ │ │ └── js
│ │ │ │ │ ├── unslider-min.js
│ │ │ │ │ └── unslider.js
│ │ │ ├── video-js
│ │ │ │ ├── font
│ │ │ │ │ ├── VideoJS.eot
│ │ │ │ │ ├── VideoJS.svg
│ │ │ │ │ ├── VideoJS.ttf
│ │ │ │ │ └── VideoJS.woff
│ │ │ │ ├── video-js.css
│ │ │ │ ├── video-js.min.css
│ │ │ │ ├── video-js.swf
│ │ │ │ ├── video.js
│ │ │ │ ├── video.js.map
│ │ │ │ ├── video.min.js
│ │ │ │ └── video.min.js.map
│ │ │ ├── webuploader.html5only.min.js
│ │ │ └── wtf-forms.css
│ │ ├── nav
│ │ │ ├── jquery.smartmenus.js
│ │ │ ├── jquery.smartmenus.min.js
│ │ │ ├── menu
│ │ │ │ ├── jquery-ui.custom.min.js
│ │ │ │ ├── jquery.mjs.nestedSortable.js
│ │ │ │ └── smartmenu
│ │ │ │ │ ├── LICENSE-MIT
│ │ │ │ │ ├── css
│ │ │ │ │ ├── sm-base.css
│ │ │ │ │ ├── sm-base.scss
│ │ │ │ │ ├── sm-blue
│ │ │ │ │ │ └── sm-blue.css
│ │ │ │ │ ├── sm-clean
│ │ │ │ │ │ └── sm-clean.css
│ │ │ │ │ ├── sm-core-css.css
│ │ │ │ │ ├── sm-mint
│ │ │ │ │ │ └── sm-mint.css
│ │ │ │ │ └── sm-simple
│ │ │ │ │ │ └── sm-simple.css
│ │ │ │ │ ├── jquery.smartmenus.js
│ │ │ │ │ └── jquery.smartmenus.min.js
│ │ │ ├── nav.css
│ │ │ ├── nav.scss
│ │ │ ├── run_menu.coffee
│ │ │ ├── run_menu.js
│ │ │ ├── sm-base.css
│ │ │ ├── sm-base.scss
│ │ │ └── sm-core-css.css
│ │ ├── pages
│ │ │ ├── bucket
│ │ │ │ ├── modify_invite_bucket.css
│ │ │ │ └── modify_invite_bucket.scss
│ │ │ ├── code_editor
│ │ │ │ ├── codemirror
│ │ │ │ │ ├── codemirror.css
│ │ │ │ │ ├── codemirror.js
│ │ │ │ │ ├── mode
│ │ │ │ │ │ ├── coffeescript.js
│ │ │ │ │ │ ├── css.js
│ │ │ │ │ │ ├── htmlmixed.js
│ │ │ │ │ │ ├── jade.js
│ │ │ │ │ │ ├── javascript.js
│ │ │ │ │ │ ├── markdown.js
│ │ │ │ │ │ └── xml.js
│ │ │ │ │ └── solarized.css
│ │ │ │ ├── editor.coffee
│ │ │ │ ├── editor.css
│ │ │ │ ├── editor.js
│ │ │ │ └── editor.scss
│ │ │ ├── csv_editor
│ │ │ │ ├── csv.css
│ │ │ │ └── csv.js
│ │ │ ├── default_homepage
│ │ │ │ ├── cover.css
│ │ │ │ ├── cover.scss
│ │ │ │ ├── markdown@2x.jpg
│ │ │ │ ├── style.css
│ │ │ │ └── style.scss
│ │ │ ├── file_manager
│ │ │ │ ├── tree.coffee
│ │ │ │ ├── tree.css
│ │ │ │ ├── tree.js
│ │ │ │ └── tree.scss
│ │ │ ├── markdown_page.css
│ │ │ ├── page.css
│ │ │ ├── site
│ │ │ │ └── menu
│ │ │ │ │ ├── editor.coffee
│ │ │ │ │ ├── editor.js
│ │ │ │ │ ├── menu_editor.css
│ │ │ │ │ ├── menu_editor.scss
│ │ │ │ │ ├── run.coffee
│ │ │ │ │ └── run.js
│ │ │ ├── table.css
│ │ │ ├── table.scss
│ │ │ ├── text_editor
│ │ │ │ ├── text_editor.coffee
│ │ │ │ ├── text_editor.css
│ │ │ │ ├── text_editor.js
│ │ │ │ └── text_editor.scss
│ │ │ └── web_editor
│ │ │ │ ├── jquery.dateFormat-1.0.js
│ │ │ │ ├── jquery.min.js
│ │ │ │ ├── knockout-min.js
│ │ │ │ ├── web_editor.coffee
│ │ │ │ ├── web_editor.css
│ │ │ │ ├── web_editor.js
│ │ │ │ └── web_editor.scss
│ │ ├── realtime
│ │ │ ├── debug_template.js
│ │ │ └── realtime.js
│ │ ├── static_render.py
│ │ └── unsplash
│ │ │ ├── 2.jpg
│ │ │ ├── 5.jpg
│ │ │ └── 6.jpg
│ ├── statistics
│ │ ├── __init__.py
│ │ ├── after_request.py
│ │ ├── post_visits.py
│ │ └── usage_collect.py
│ ├── template_system
│ │ ├── __init__.py
│ │ ├── api_template_render.py
│ │ ├── app_functions
│ │ │ ├── __init__.py
│ │ │ ├── after_request
│ │ │ │ ├── __init__.py
│ │ │ │ ├── basic.py
│ │ │ │ └── cache_page.py
│ │ │ ├── before_and_after_request
│ │ │ │ ├── __init__.py
│ │ │ │ └── time_cost.py
│ │ │ ├── before_request
│ │ │ │ ├── __init__.py
│ │ │ │ ├── basic.py
│ │ │ │ └── site_visitor_password.py
│ │ │ └── utils.py
│ │ ├── attr_patch
│ │ │ ├── __init__.py
│ │ │ ├── all.py
│ │ │ ├── array.py
│ │ │ ├── dictionary.py
│ │ │ ├── fake_fields.py
│ │ │ └── strings.py
│ │ ├── env.py
│ │ ├── errors.py
│ │ ├── exceptions.py
│ │ ├── helper
│ │ │ ├── __init__.py
│ │ │ ├── get_post_with_greed.py
│ │ │ ├── post_compile_url_for_wiki_links.py
│ │ │ └── post_referred_docs.py
│ │ ├── model
│ │ │ ├── __init__.py
│ │ │ ├── category.py
│ │ │ ├── date.py
│ │ │ └── text.py
│ │ ├── namespace
│ │ │ ├── __init__.py
│ │ │ ├── bucket.py
│ │ │ ├── built_in.py
│ │ │ ├── data.py
│ │ │ ├── html.py
│ │ │ ├── post.py
│ │ │ ├── record.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── site.py
│ │ │ └── utils
│ │ │ │ ├── __init__.py
│ │ │ │ ├── form_utils.py
│ │ │ │ ├── nav_utils.py
│ │ │ │ └── post_utils.py
│ │ ├── syntax_block
│ │ │ ├── __init__.py
│ │ │ ├── compatibility.py
│ │ │ ├── lazy_html.py
│ │ │ ├── modal.py
│ │ │ ├── page.py
│ │ │ ├── pure.py
│ │ │ ├── refer.py
│ │ │ └── slider.py
│ │ ├── template_system_patch.py
│ │ └── templates
│ │ │ ├── __init__.py
│ │ │ ├── build.py
│ │ │ └── info.py
│ ├── utils
│ │ ├── __init__.py
│ │ ├── cache_for_function.py
│ │ ├── cookie.py
│ │ ├── doc_url.py
│ │ ├── func.py
│ │ ├── lazy.py
│ │ ├── record_and_paginator
│ │ │ ├── __init__.py
│ │ │ ├── base_paginator.py
│ │ │ ├── paginator.py
│ │ │ ├── paginator_for_record.py
│ │ │ └── utils.py
│ │ ├── request.py
│ │ ├── request_context_vars.py
│ │ ├── request_path.py
│ │ ├── response.py
│ │ ├── response_html.py
│ │ ├── site_resource.py
│ │ └── verification_code.py
│ ├── views
│ │ ├── __init__.py
│ │ ├── api.py
│ │ ├── bucket.py
│ │ ├── file_manager.py
│ │ ├── for_admin.py
│ │ ├── install_ssl.py
│ │ ├── my.py
│ │ ├── system.py
│ │ └── wiki_link_fallback.py
│ └── web_app.py
├── settings.py
├── themes
│ ├── Cais
│ │ ├── archive.jade
│ │ ├── base.jade
│ │ ├── css
│ │ │ ├── markdown.scss
│ │ │ └── style.scss
│ │ ├── feed.jade
│ │ ├── index+tag.jade
│ │ ├── post.jade
│ │ └── readme.txt
│ ├── Classify
│ │ ├── archive.jade
│ │ ├── base.jade
│ │ ├── category.jade
│ │ ├── css
│ │ │ └── style.scss
│ │ ├── feed.jade
│ │ ├── index.jade
│ │ └── post.jade
│ ├── Esta
│ │ ├── archive.jade
│ │ ├── base.jade
│ │ ├── index+tag.jade
│ │ ├── mixins.jade
│ │ ├── post.jade
│ │ └── style.scss
│ ├── Fexo
│ │ ├── base.jade
│ │ ├── category+categories.jade
│ │ ├── index.jade
│ │ ├── license.txt
│ │ ├── mixins.jade
│ │ ├── post.jade
│ │ └── static
│ │ │ └── style.scss
│ ├── Puti
│ │ ├── License.txt
│ │ ├── archive.jade
│ │ ├── base.jade
│ │ ├── css
│ │ │ ├── animate.3.5.2.min.css
│ │ │ ├── markdown.scss
│ │ │ └── style.scss
│ │ ├── feed.jade
│ │ ├── index+tag.jade
│ │ ├── post.jade
│ │ └── readme.txt
│ ├── Sollrei
│ │ ├── archive.jade
│ │ ├── base.jade
│ │ ├── css
│ │ │ ├── fonts.css
│ │ │ ├── reset.scss
│ │ │ └── style.scss
│ │ ├── index+category+tag.jade
│ │ ├── js
│ │ │ ├── index.js
│ │ │ └── particles.js
│ │ └── post.jade
│ ├── Wiki
│ │ ├── index+post.jade
│ │ └── static
│ │ │ ├── instantclick.js
│ │ │ └── style.scss
│ ├── __init__.py
│ └── build_themes.py
└── utils
│ ├── __init__.py
│ ├── async_block.py
│ ├── cache.py
│ ├── cli_color.py
│ ├── client_sync
│ ├── __init__.py
│ ├── detect.py
│ ├── log.py
│ └── sync_utils.py
│ ├── console_utils.py
│ ├── convert
│ ├── __init__.py
│ ├── coffee2js.py
│ ├── css.py
│ ├── jade2jinja.py
│ └── utils.py
│ ├── data.py
│ ├── date.py
│ ├── encrypt
│ ├── __init__.py
│ ├── aes_encrypt.py
│ ├── des_encrypt.py
│ ├── key_encrypt.py
│ └── simple.py
│ ├── env.py
│ ├── error.py
│ ├── file_version.py
│ ├── functional.py
│ ├── gevent_run.py
│ ├── gevent_utils.py
│ ├── gzip_content.py
│ ├── html.py
│ ├── image
│ ├── __init__.py
│ ├── exif.py
│ ├── resize.py
│ └── utils.py
│ ├── ip
│ ├── __init__.py
│ └── utils.py
│ ├── ipfs_utils.py
│ ├── logger.py
│ ├── mail
│ ├── __init__.py
│ ├── basic_utils.py
│ ├── system.py
│ └── utils.py
│ ├── md_related
│ ├── __init__.py
│ ├── filter_posts_info.py
│ └── markdown_doc_links.py
│ ├── memcache.py
│ ├── memcache_block.py
│ ├── mime.py
│ ├── monkey
│ ├── __init__.py
│ └── http.py
│ ├── objectid.py
│ ├── path.py
│ ├── pay
│ ├── __init__.py
│ ├── alipay.py
│ └── alipay_api.py
│ ├── simple_encrypt.py
│ ├── ssdb_client.py
│ ├── ssdb_utils.py
│ ├── ssl_related.py
│ ├── system_status_recorder.py
│ ├── url.py
│ └── web_utils
│ ├── __init__.py
│ ├── flask_httpauth.py
│ ├── request.py
│ └── response.py
├── readme.md
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.pyc
3 | *.pyd
4 | *.DS_Store
5 | test[!s]*
6 | tmp*
7 | web/static/unsplash/origin
8 | draft/*
9 | configs/debug.txt
10 | project.dockerfile
11 | project.packages
12 | dist/*
13 | *.egg-info/*
14 | farbox_bucket/bitcron/*
15 | PKG-INFO
16 | *.cfg
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 hepochen@gmail.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | Any user logging into a system that embeds the code from the current project,
13 | must prominently inform the user that the supported client Apps include
14 | Metion (on the Apple App Store) and MarkEditor (https://markeditor.com).
15 | [任何用户登录到包含了当前项目代码的系统中,必须要在显著的位置告知用户对应支持的客户端中包括
16 | Metion (on Apple App Store) 以及 MarkEditor (https://markeditor.com)。]
17 |
18 | If the site is driven by current project, it would be appreciated if the
19 | `Powered by FarBox` signature could be retained at the bottom of the site.
20 | [如果网站由当前项目驱动,希望能在网站底部保留 `Powered by FarBox` 的签名,非常感谢。]
21 |
22 | The above copyright notice and this permission notice shall be included in all
23 | copies or substantial portions of the Software.
24 |
25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 | SOFTWARE.
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include farbox_bucket/server/static *
2 | recursive-include farbox_bucket/themes *
3 | recursive-include farbox_bucket/deploy/run *
--------------------------------------------------------------------------------
/farbox_bucket/LICENSE.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 |
4 |
5 | LICENSE = """
6 | MIT License
7 |
8 | Copyright (c) 2021 hepochen@gmail.com
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | Any user logging into a system that embeds the code from the current project,
18 | must prominently inform the user that the supported client Apps include
19 | Metion (on the Apple App Store) and MarkEditor (https://markeditor.com).
20 | [任何用户登录到包含了当前项目代码的系统中,必须要在显著的位置告知用户对应支持的客户端中包括
21 | Metion (on Apple App Store) 以及 MarkEditor (https://markeditor.com)。]
22 |
23 | If the site is driven by current project, it would be appreciated if the
24 | `Powered by FarBox` signature could be retained at the bottom of the site.
25 | [如果网站由当前项目驱动,希望能在网站底部保留 `Powered by FarBox` 的签名,非常感谢。]
26 |
27 | The above copyright notice and this permission notice shall be included in all
28 | copies or substantial portions of the Software.
29 |
30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 | SOFTWARE.
37 | """
--------------------------------------------------------------------------------
/farbox_bucket/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
4 | version = '0.2020'
--------------------------------------------------------------------------------
/farbox_bucket/bucket/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 | from .utils import *
4 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/clouds/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/clouds/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/clouds/storage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/clouds/storage/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/defaults.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 |
3 | # 基础结构
4 | zero_id = '0'*24 # 创世ID, 一旦创建,不可修改
5 | zero_id_for_user = '0'*23 + '1' # 用户的设定,会进行加密
6 | zero_id_for_site = '0'*23 + '3' # site configs
7 | zero_id_for_secret = '0'*23 + '4' # secret site configs,也会进行加密
8 |
9 | # 基础数据
10 | zero_id_for_pages = '0'*23 + '2'
11 | zero_id_for_files = '0'*23 + '6'
12 | zero_id_for_posts = '0'*23 + '7'
13 |
14 | # 变动支持
15 | zero_id_for_histories = '0'*22 + '11'
16 | zero_id_for_statistics = '0'*22 + '12'
17 | zero_id_for_orders = '0'*22 + '13' # 配合 zero_id_for_files
18 | zero_id_for_inbox = '0'*22 + '14'
19 |
20 | # todo 变动区域分为两种类型,一个是整个 bucket 内保持同步的(如何处理冲突呢?),一个是只在当前 node 生效的
21 | # todo 倾向于只有一种,就是只在当前 node 生效的
22 |
23 |
24 | # 主要是外部调用 get_records 查询的时候,给一个基准 id,可以避免 zero_ids 被查询到
25 | # 主要是模板引擎中调用
26 | zero_id_for_finder = '0'*22 + '99'
27 |
28 | zero_ids = [zero_id, zero_id_for_user, zero_id_for_site, zero_id_for_secret,
29 | zero_id_for_pages, zero_id_for_files, zero_id_for_posts,
30 | zero_id_for_histories, zero_id_for_statistics,
31 | zero_id_for_orders, zero_id_for_inbox]
32 |
33 |
34 | bucket_config_doc_id_names = {
35 | 'init': zero_id,
36 | 'user': zero_id_for_user,
37 | 'site': zero_id_for_site,
38 | 'secret': zero_id_for_secret,
39 | 'pages': zero_id_for_pages,
40 | 'files': zero_id_for_files,
41 | 'posts': zero_id_for_posts,
42 | 'histories': zero_id_for_histories,
43 | 'statistics': zero_id_for_statistics,
44 | 'orders': zero_id_for_orders,
45 | 'inbox': zero_id_for_inbox,
46 | }
47 |
48 | config_names_not_allowed_set_by_user = ['init', 'histories', 'statistics', 'inbox']
49 |
50 |
51 |
52 | BUCKET_RECORD_SORT_TYPES = ('post', 'image', 'file', 'folder', 'comments')
53 |
54 | BUCKET_RECORD_SLASH_TYPES = ('post', 'image', 'file', 'folder', 'comments', "visits")
--------------------------------------------------------------------------------
/farbox_bucket/bucket/delete.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils.ssdb_utils import hdel, hclear
3 | from farbox_bucket.bucket.utils import remove_bucket_from_buckets, clear_related_buckets
4 | from farbox_bucket.bucket.record.get.helper import loop_records_for_bucket
5 | from farbox_bucket.bucket.storage.default import storage
6 |
7 |
8 |
9 | def delete_bucket(bucket, delete_files=True):
10 | if not bucket:
11 | return
12 | # 清空一个 bucket 的相关逻辑,但是要慎重使用,一般除了 本地Debug 之外,不进行这个操作
13 | clear_related_buckets(bucket)
14 |
15 | # after_record_created 中的一些数据统计清理
16 | hdel('_bucket_usage', bucket)
17 | hdel('_records_count', bucket)
18 |
19 | if delete_files:
20 | # 删除对应的文件
21 | loop_records_for_bucket(bucket, storage.when_record_deleted)
22 |
23 | # at last
24 | hclear(bucket)
25 | remove_bucket_from_buckets(bucket)
--------------------------------------------------------------------------------
/farbox_bucket/bucket/domain/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/domain/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/helper/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils.encrypt.key_encrypt import create_private_public_keys
3 |
4 |
5 | def get_private_key_on_server_side():
6 | private_key, public_key = create_private_public_keys()
7 | return private_key
8 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/record/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/get/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/record/get/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/get/helper.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from .get import get_records_for_bucket
3 |
4 |
5 |
6 | def loop_records_for_bucket(bucket, func_for_record, limit=100, raw=False):
7 | start_record_id = None
8 | while True:
9 | records = get_records_for_bucket(
10 | bucket = bucket,
11 | start_record_id = start_record_id,
12 | limit = limit,
13 | includes_start_record_id = False,
14 | raw = raw,
15 | )
16 | for record in records:
17 | func_for_record(record)
18 | if not records or len(records) != limit:
19 | break
20 | last_record = records[-1]
21 | if isinstance(last_record, dict):
22 | start_record_id = last_record['_id']
23 | else:
24 | start_record_id = last_record[0]
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/get/slash_related.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 | from farbox_bucket.utils.ssdb_utils import zscan
4 |
5 | from farbox_bucket.bucket.utils import get_bucket_name_for_slash
6 | from farbox_bucket.utils import smart_unicode
7 |
8 | from .path_related import get_records_by_paths, filter_paths_under_path
9 |
10 |
11 | def get_paths_by_slash_number(bucket, level_start, level_end='', under=''):
12 | bucket_for_slash = get_bucket_name_for_slash(bucket)
13 | paths = []
14 | raw_result = zscan(bucket_for_slash, score_start=level_start, score_end=level_end, limit=30000)
15 | for path, level_value in raw_result:
16 | paths.append(smart_unicode(path))
17 | paths = filter_paths_under_path(paths, under=under)
18 | return paths
19 |
20 |
21 |
22 |
23 | def get_records_by_slash_number(bucket, level_start, level_end='', under=''):
24 | paths = get_paths_by_slash_number(bucket=bucket, level_start=level_start, level_end=level_end, under=under)
25 | records = get_records_by_paths(bucket=bucket, paths=paths)
26 | return records
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/helper/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/record/helper/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/helper/update_record.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.bucket.utils import has_bucket
3 | from farbox_bucket.bucket.record.create import create_record, update_path_related_when_record_changed
4 |
5 |
6 |
7 |
8 |
9 | def update_record_directly(bucket, record):
10 | # 通过 record 来更新 record,不需要额外的编译
11 | # 如果有 path 路径,不要去更改它
12 | if not isinstance(record, dict):
13 | return False
14 | if not has_bucket(bucket):
15 | return False
16 | record['_auto_clean_bucket'] = True
17 |
18 | # 创建新的 record
19 | create_record(bucket, record)
20 |
21 | object_id = record.get("_id")
22 | if object_id:
23 | update_path_related_when_record_changed(bucket, object_id, record)
24 |
25 | return True
26 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/related/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/record/related/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/related/for_all.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 | from farbox_bucket.utils.ssdb_utils import hincr, py_data_to_ssdb_data
4 | from farbox_bucket.bucket.utils import update_bucket_max_id
5 | from farbox_bucket.bucket.record.utils import get_path_from_record, get_data_type
6 |
7 | from .for_created import after_path_related_record_created
8 | from .for_deleted import after_path_related_record_deleted
9 |
10 |
11 |
12 | def update_path_related_when_record_changed(bucket, record_id, record_data):
13 | # 注意:!!!! 凡是 record 中有指定 path 段的,都是可以被更新的;如果不希望这个 record 被 删除,就不要赋予这个字段
14 | if not isinstance(record_data, dict):
15 | return
16 | if not bucket or not record_id:
17 | return
18 | is_deleted = record_data.get('is_deleted', False)
19 |
20 |
21 | # path 相关的逻辑
22 | path = get_path_from_record(record_data)
23 | if not path:
24 | return
25 | if is_deleted:
26 | # delete the record, 实际上都是增量,只是一个 action=delete 的标识而已; 但也有直接把 record 删除掉的
27 | after_path_related_record_deleted(bucket, record_data=record_data)
28 | else: # create or update
29 | after_path_related_record_created(bucket, record_id, record_data)
30 |
31 |
32 |
33 | def after_record_created(bucket, py_record_data, object_id, should_update_bucket_max_id=False):
34 | if should_update_bucket_max_id and object_id:
35 | # 由 API 构建的, 会产生一个新的 object_id
36 | update_bucket_max_id(bucket, object_id)
37 |
38 | byte_record_data = py_data_to_ssdb_data(py_record_data) # must be string_types
39 |
40 | hincr('_bucket_usage', bucket, len(byte_record_data)) # 容量增加
41 | hincr('_records_count', 'all', num=1) # 如果系统中 bucket 被删除,这个增量是不会减少的
42 | hincr('_records_count', bucket, num=1)
43 |
44 | update_path_related_when_record_changed(bucket, object_id, py_record_data)
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/related/sub/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/record/related/sub/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/related/sub/utils.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.bucket.record.utils import get_data_type
3 | from .for_posts import update_post_tags_words_info
4 |
5 |
6 | def update_tags_info_for_posts(bucket, record_data):
7 | # store the files info
8 |
9 | doc_type = get_data_type(record_data)
10 | if doc_type == 'post':
11 | update_post_tags_words_info(bucket=bucket, record_data=record_data)
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/reset.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from .get.helper import loop_records_for_bucket
3 | from farbox_bucket.bucket.defaults import zero_ids
4 | from farbox_bucket.utils.ssdb_utils import hdel, hdel_many
5 | from farbox_bucket.bucket.utils import get_bucket_files_info
6 | from farbox_bucket.bucket.record.get.path_related import get_record_id_by_path
7 | from farbox_bucket.bucket.record.related.for_all import update_path_related_when_record_changed
8 |
9 |
10 |
11 | def reset_related_records(bucket):
12 | def reset_record(record):
13 | record_id = record.get('_id')
14 | update_path_related_when_record_changed(bucket=bucket, record_id=record_id, record_data=record)
15 | loop_records_for_bucket(bucket, func_for_record=reset_record)
16 |
17 |
18 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/record/update.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils.data import json_dumps, json_loads
3 | from .get.get import get_record
4 | from .get.path_related import get_record_id_by_path
5 | from farbox_bucket.utils.ssdb_utils import hset, ssdb_data_to_py_data, py_data_to_ssdb_data
6 | from farbox_bucket.bucket.record.related.for_created import update_record_order_value_to_related_db
7 |
8 | # 如非特殊,不要对一个 record 进行 update
9 |
10 | fields_not_allowed_to_update = ['_id', '_pre_id', 'id', 'path']
11 |
12 | def update_record(bucket, record_id, **kwargs):
13 | if not record_id:
14 | return False
15 | if isinstance(record_id, dict):
16 | record_id = record_id.get("_id")
17 | record = get_record(bucket, record_id, force_dict=True)
18 | if not record:
19 | return False
20 | for field in fields_not_allowed_to_update: # 不允许更改的字段
21 | kwargs.pop(field, None)
22 | if not kwargs:
23 | return False
24 | record.update(kwargs) # update
25 | hset(bucket, record_id, record)
26 |
27 | order_value_in_kwargs = kwargs.get("_order")
28 | if isinstance(order_value_in_kwargs, (float, int)) and record.get("path"):
29 | # update path related _order value, specially for image
30 | update_record_order_value_to_related_db(bucket, record)
31 |
32 | return True
33 |
34 |
35 |
36 | def update_record_by_path(bucket, path, **kwargs):
37 | record_id = get_record_id_by_path(bucket, path)
38 | if record_id:
39 | return update_record(bucket, record_id, **kwargs)
40 | else:
41 | return False
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/service/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/service/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/storage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/storage/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/storage/default.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.bucket.clouds.storage.qcloud import qcloud_is_valid
3 | from .local_file_system import LocalStorage
4 | from .qcloud_storage import QCloudStorage
5 |
6 |
7 | def get_default_storage():
8 | if qcloud_is_valid:
9 | return QCloudStorage()
10 | else:
11 | return LocalStorage()
12 |
13 |
14 | storage = get_default_storage()
--------------------------------------------------------------------------------
/farbox_bucket/bucket/storage/helpers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/storage/helpers/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/storage/helpers/before_store_image.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils.image.utils import get_im, get_im_size
3 | from farbox_bucket.utils.image.exif import Exif
4 | from farbox_bucket.utils.date import get_image_date
5 | from farbox_bucket.bucket.utils import get_bucket_utc_offset
6 | from farbox_bucket.utils.date import date_to_timestamp
7 |
8 | # 在图片存储之前,解析图片的信息,包括旋转相关的逻辑
9 |
10 |
11 | def do_get_image_info_from_raw_content(raw_content):
12 | info = {}
13 | im = get_im(raw_content)
14 | if not im:
15 | return info
16 | exif_obj = Exif(im)
17 | exif = exif_obj.data # 获得exif信息,并且会自动旋转图片
18 | info['exif'] = exif
19 | info['degrees'] = exif_obj.degrees # 旋转角度多少才能正回来
20 | # 从exif中取日期
21 | utc_offset = get_bucket_utc_offset()
22 | image_date = get_image_date(exif, None, utc_offset)
23 | if image_date:
24 | info["date"] = image_date
25 | sort_value = date_to_timestamp(image_date, is_utc=True)
26 | info["_order"] = sort_value # 要处理图片的排序
27 | im_size = get_im_size(im)
28 | image_width, image_height = im_size
29 | if image_width and image_height:
30 | info['image_width'] = image_width
31 | info['image_height'] = image_height
32 | return info
33 |
34 |
35 | def get_image_info_from_raw_content(raw_content):
36 | try:
37 | return do_get_image_info_from_raw_content(raw_content)
38 | except:
39 | return {}
40 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/sync/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/sync/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/template_related/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/template_related/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/token/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/token/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/token/bucket_signature_and_check.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import time
3 | from farbox_bucket.settings import server_secret_key
4 | from farbox_bucket.utils import get_md5, string_types, to_int
5 |
6 |
7 |
8 | def get_signature_for_bucket(bucket, timestamp=None, salt=None):
9 | # -
10 | timestamp = timestamp or int(time.time())
11 | value_to_hash = "%s-%s-%s" % (timestamp, bucket, server_secret_key)
12 | if salt:
13 | value_to_hash = "%s-%s" % (value_to_hash, salt)
14 | signature_body = get_md5(value_to_hash)
15 | signature = "%s-%s" % (timestamp, signature_body)
16 | return signature
17 |
18 |
19 |
20 | def check_signature_for_bucket(bucket, signature, salt=None, hours=24):
21 | if not isinstance(signature, string_types):
22 | return False
23 | if signature.count("-") != 1:
24 | return False
25 | signature_timestamp, signature_body = signature.split("-", 1)
26 | signature_timestamp = to_int(signature_timestamp, default_if_fail=0)
27 | if not signature_timestamp:
28 | return False
29 | timestamp = int(time.time())
30 | diff = timestamp - signature_timestamp
31 | if diff > hours*60*60: # 1 day by default
32 | return False
33 | signature_should_be = get_signature_for_bucket(bucket, signature_timestamp, salt=salt)
34 | if signature == signature_should_be:
35 | return True
36 | return False
--------------------------------------------------------------------------------
/farbox_bucket/bucket/token/simple_encrypt_token.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils import string_types
3 | from farbox_bucket.utils.ssdb_utils import hset, hget, hexists
4 | from farbox_bucket.utils.encrypt.simple import simple_encrypt, simple_decrypt
5 | from farbox_bucket.utils.data import json_dumps, json_loads
6 |
7 |
8 | # simple_bucket_token 是唯一不可更改的,主要是做加密和解密的;不能暴露给任何人
9 |
10 | def get_simple_bucket_token(bucket):
11 | token = hget('_simple_bucket_token', bucket) or ''
12 | return token
13 |
14 |
15 | def set_simple_bucket_token(bucket, private_key_md5):
16 | if not bucket:
17 | return
18 | if isinstance(private_key_md5, string_types) and len(private_key_md5)<100:
19 | old_value = get_simple_bucket_token(bucket)
20 | if old_value == private_key_md5:
21 | return
22 | hset('_simple_bucket_token', bucket, private_key_md5)
23 |
24 |
25 |
26 | def get_normal_data_by_simple_token(bucket, encrypted_data, force_py_data=True, default_if_failed=None):
27 | # force_py_data = True 的时候,必须是 list/tuple/dict 的数据类型
28 | if not encrypted_data:
29 | return encrypted_data
30 | token = get_simple_bucket_token(bucket)
31 | if token and isinstance(encrypted_data, string_types):
32 | result = simple_decrypt(encrypted_data, token)
33 | try: result = json_loads(result)
34 | except: pass
35 | else:
36 | result = encrypted_data
37 | if force_py_data:
38 | if isinstance(result, (list, tuple, dict)):
39 | return result
40 | else:
41 | return default_if_failed
42 | else:
43 | return result
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/farbox_bucket/bucket/usage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/usage/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/bucket/web_api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/bucket/web_api/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/client/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/client/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/client/sync/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from .site import sync_site_folder_simply as sync_to_farbox
3 | from farbox_bucket.client.sync_from.sync_from import sync_from_farbox
--------------------------------------------------------------------------------
/farbox_bucket/client/sync/compiler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/client/sync/compiler/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/client/sync/compiler/comments_compiler.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import time, os
3 | from farbox_bucket.client.sync.compiler.basic_compiler import BasicSyncCompiler
4 | from farbox_bucket.utils.data import csv_to_list, csv_data_to_objects
5 |
6 |
7 |
8 | class CommentsSyncCompiler(BasicSyncCompiler):
9 | def __init__(self, *args, **kwargs):
10 | kwargs['doc_type'] = kwargs.get('doc_type') or 'comments'
11 | BasicSyncCompiler.__init__(self, *args, **kwargs)
12 |
13 | def get_compiled_data(self):
14 | data_list = csv_to_list(self.raw_content,
15 | max_rows=1000, # 1k条记录最多
16 | max_columns=50,
17 | auto_fill=True
18 | )
19 | objects = csv_data_to_objects(data_list)
20 | _order_value = time.time()
21 | if self.abs_filepath and os.path.isfile(self.abs_filepath):
22 | _order_value = os.path.getmtime(self.abs_filepath)
23 | data = dict(
24 | _order = _order_value,
25 | objects = objects,
26 | raw_content = self.raw_content,
27 | data = data_list,
28 | )
29 | return data
30 |
--------------------------------------------------------------------------------
/farbox_bucket/client/sync/compiler/folder_compiler.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from farbox_bucket.client.sync.compiler.post_compiler import PostSyncCompiler
3 | import os
4 |
5 |
6 | # folder 从某种角度来说,只是记录这个数据,而不是更多的关系上的,因为无法从 path 上进行查询匹配
7 | # folder_doc
8 |
9 | class FolderSyncCompiler(PostSyncCompiler):
10 | def __init__(self, *args, **kwargs):
11 | kwargs['doc_type'] = kwargs.get('doc_type') or 'folder'
12 | PostSyncCompiler.__init__(self, *args, **kwargs)
13 |
14 | def get_compiled_data(self):
15 | data = PostSyncCompiler.get_compiled_data(self)
16 | if self.abs_filepath and os.path.isdir(self.abs_filepath):
17 | folder_relative_path = self.relative_path
18 | else:
19 | folder_relative_path = self.relative_path.strip('/')
20 | data['path'] = folder_relative_path
21 | data['relative_path'] = folder_relative_path
22 | data['is_dir'] = True
23 | data['slash_number'] = folder_relative_path.count('/')
24 | data['_type'] = 'folder'
25 | data['type'] = 'folder'
26 | return data
27 |
--------------------------------------------------------------------------------
/farbox_bucket/client/sync/compiler/visits_compiler.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.client.sync.compiler.basic_compiler import BasicSyncCompiler
3 | from farbox_bucket.utils.data import csv_to_list, csv_data_to_objects
4 |
5 | # 解析 _data/visits.csv 文件,并转为相应的 data 数据
6 | # server 端对于这个 data,会截取前 1000,作为 visits 的逻辑
7 |
8 | class VisitsSyncCompiler(BasicSyncCompiler):
9 | def __init__(self, *args, **kwargs):
10 | kwargs['doc_type'] = kwargs.get('doc_type') or 'visits'
11 | BasicSyncCompiler.__init__(self, *args, **kwargs)
12 |
13 | def get_compiled_data(self):
14 | data_list = csv_to_list(self.raw_content,
15 | max_rows=10001, # 1w条记录最多
16 | max_columns=50,
17 | auto_fill=True
18 | )
19 | objects = csv_data_to_objects(data_list)
20 | data = dict(
21 | objects = objects,
22 | raw_content = self.raw_content,
23 | data=data_list,
24 | )
25 | return data
26 |
27 |
--------------------------------------------------------------------------------
/farbox_bucket/client/sync_from/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from .sync_from import sync_from_farbox
--------------------------------------------------------------------------------
/farbox_bucket/clouds/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/clouds/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/clouds/dropbox/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 | # Dropbox 这类的云端,不是优选项,相当于把整个 bucket 的逻辑彻底交给第三方更新,与 FarBox Bucket 的基本结构有冲突,
4 | # 在 Client 端**无法控制**同步的逻辑,并且是批量数据涌进来的,估计容易出问题。
5 | # 如果不处理批量涌入的问题,只处理 delta 可能会好一些,但是使用者是无法接受没有 『初始化』 数据的。
6 | # 再考虑到 FarBox 目前本身项目代码开放,自己跑一个脚本进行差量同步也是低成本的,而且**通用性**更高;
7 | # 通过 Dropbox 在服务端进行 Hook 的更新,考虑副作用的前提下,必要性不大。@2021
8 |
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/build_wechat_menu.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.clouds.wechat.utils.menu import create_menus
3 |
4 |
5 | def create_menus_on_wechat():
6 | menus = {
7 | "button": [
8 | {
9 | "name": u"+图",
10 | "sub_button": [
11 | {
12 | "type": "pic_sysphoto",
13 | "name": u"拍摄照片",
14 | "key": "pic_sysphoto"
15 | },
16 | {
17 | "type": "pic_weixin",
18 | "name": u"本地照片",
19 | "key": "pic_weixin"
20 | },
21 | ],
22 | },
23 | {
24 | "name": u"管理",
25 | "sub_button": [
26 | {
27 | "type": "scancode_waitmsg",
28 | "name": u"扫码绑定",
29 | "key": "bind",
30 | },
31 | {
32 | "type": "click",
33 | "name": u"解除绑定",
34 | "key": "unbind"
35 | },
36 | {
37 | "type": "click",
38 | "name": u"当前状态",
39 | "key": "bind_status"
40 | },
41 | ]
42 | },
43 | ]
44 | }
45 |
46 | return create_menus(menus)
47 |
48 |
49 | if __name__ == '__main__':
50 | create_menus_on_wechat()
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/utils/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'hepochen'
2 |
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/utils/__message_template.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from farbox_bucket.utils.convert.jade2jinja import convert_jade_to_html
3 |
4 | SEND_MESSAGE_WECHAT_TEMPLATE = convert_jade_to_html("""
5 | xml
6 | ToUserName
7 | FromUserName
8 | CreateTime= now.format('%s')
9 | MsgType text
10 | Content
11 | FuncFlag 0
12 | """)
13 |
14 |
15 | SEND_POSTS_WECHAT_TEMPLATE = convert_jade_to_html("""
16 | xml
17 | ToUserName
18 | FromUserName
19 | CreateTime= now.format('%s')
20 | MsgType news
21 | ArticleCount= posts.length
22 | Articles
23 | for post in posts
24 | item
25 | Title
26 | Description
27 | img_get_vars = 'width=640&height=640&outbound_link_password='+get_outbound_link_password(days=7)
28 | if post.cover
29 | PicUrl
30 | elif loop.index==1
31 | PicUrl
32 | Url
33 | """)
34 |
35 |
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/utils/_message_template.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 |
3 |
4 | SEND_MESSAGE_WECHAT_TEMPLATE = """
5 |
6 |
7 |
8 |
9 | %s
10 |
11 | text
12 |
13 |
14 |
15 | 0
16 |
17 | """
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/utils/check.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from flask import request, abort
3 | from farbox_bucket.utils import get_sha1, to_int
4 | import time
5 |
6 |
7 | def _is_from_wechat(token, ttl=120):
8 | # 这里的 token,实际上实在 wechat 的后台自己设置的
9 | rv = request.values
10 | nonce = rv.get('nonce')
11 | timestamp = rv.get('timestamp')
12 | if not nonce or not timestamp:
13 | return False
14 | values_to_sign = [token, nonce, timestamp]
15 | values_to_sign.sort()
16 | to_sign = ''.join(values_to_sign)
17 | signature = get_sha1(to_sign)
18 | if rv.get('signature') != signature:
19 | return False
20 |
21 | if ttl:
22 | timestamp = to_int(timestamp)
23 | now = time.time()
24 | if (now-timestamp) > ttl:# (默认)超过2分钟前就算请求过期了,校验失败
25 | return False
26 |
27 | return True # at last
28 |
29 |
30 |
31 | def check_is_from_wechat(token, ttl=120, raise_error=True):
32 | status = _is_from_wechat(token, ttl=ttl)
33 | if raise_error and not status:
34 | # 需要触发错误,并且 status==False 的情况下,直接400扔出
35 | abort(400, 'not allowed or expired')
36 | return False
37 | else:
38 | return status
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/utils/menu.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | import requests
3 | import ujson as json
4 | from farbox_bucket.utils import string_types
5 | from .token import get_access_token, check_wechat_errors_and_update_token
6 |
7 | API_PREFIX = 'https://api.weixin.qq.com/cgi-bin/'
8 |
9 | def create_menus(menus):
10 | # wechat比较变态,menus需要是完整的json字符串
11 | url = API_PREFIX + 'menu/create'
12 | access_token = get_access_token(force_update=True)
13 | params = dict(access_token=access_token)
14 | #headers = {'content-type': 'application/json'}
15 | if isinstance(menus, string_types):
16 | data = menus
17 | else:
18 | data = json.dumps(menus, ensure_ascii=False)
19 | response = requests.post(url, data=data, params=params, verify=False)
20 | print response.json()
21 | try:
22 | json_data = response.json()
23 | check_wechat_errors_and_update_token(json_data)
24 | if json_data.get('errcode'):
25 | return False
26 | else:
27 | return True
28 | except:
29 | return False
30 |
31 |
32 | def get_menus():
33 | url = API_PREFIX + 'menu/get'
34 | access_token = get_access_token()
35 | params = dict(access_token=access_token)
36 | response = requests.get(url, params=params, verify=False)
37 | return response.json()
38 |
39 |
40 | def delete_menus():
41 | url = API_PREFIX + 'menu/delete'
42 | access_token = get_access_token()
43 | params = dict(access_token=access_token)
44 | response = requests.get(url, params=params, verify=False)
45 | return response.json()
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/utils/message.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import time
3 | from jinja2 import Template
4 | from ._message_template import SEND_MESSAGE_WECHAT_TEMPLATE
5 |
6 | wechat_message_template = None
7 | def get_wechat_message_template():
8 | global wechat_message_template
9 | if wechat_message_template is not None:
10 | return wechat_message_template
11 | wechat_message_template = Template(SEND_MESSAGE_WECHAT_TEMPLATE)
12 | return wechat_message_template
13 |
14 |
15 | def send_wechat_message(message, from_user_name="", to_user_name=""):
16 | # xml.FromUserName, xml.ToUserName
17 | # 被动地发送文本信息,即响应微信API的请求
18 | # set_content_type('application/xml')
19 | timestamp = str(int(time.time()))
20 | xml_content = SEND_MESSAGE_WECHAT_TEMPLATE % (from_user_name, to_user_name, timestamp, message)
21 | return xml_content
22 |
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/utils/token.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | import requests
3 | from farbox_bucket.utils.ssdb_utils import auto_cache_by_ssdb
4 | from farbox_bucket.utils.env import get_env
5 |
6 | WECHAT_APP_ID = get_env("wechat_app_id")
7 | WECHAT_APP_SECRET = get_env("wechat_app_secret")
8 |
9 |
10 | # 一个微信的open id 看起来可能是这样的: oZ454jpVhF15nHxs3ig-uCq_gqss
11 |
12 | API_PREFIX = 'https://api.weixin.qq.com/cgi-bin/'
13 |
14 | # 每天最多 2000 次
15 | def _get_access_token():
16 | if not WECHAT_APP_ID or not WECHAT_APP_SECRET:
17 | return ""
18 | url = API_PREFIX + 'token'
19 | params = {'grant_type': 'client_credential', 'appid': WECHAT_APP_ID, 'secret': WECHAT_APP_SECRET}
20 | response = requests.get(url, params=params, verify=False)
21 | try:
22 | token = response.json().get('access_token')
23 | except:
24 | try: print(response.json().get("errmsg"))
25 | except: pass
26 | token = ""
27 | return token
28 |
29 | def get_access_token(force_update=False):
30 | # 7200s的有效期
31 | # # 一个小时更新一次
32 | return auto_cache_by_ssdb("wechat_token", value_func=_get_access_token, ttl=3600, force_update=force_update)
33 |
34 |
35 | def check_wechat_errors_and_update_token(json_data):
36 | if not json_data:
37 | return # ignore
38 | error_code = json_data.get("errcode")
39 | if error_code == 40001: # access_token失效了
40 | get_access_token(force_update=True)
41 |
--------------------------------------------------------------------------------
/farbox_bucket/clouds/wechat/views.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from flask import abort
3 | from farbox_bucket.utils.env import get_env
4 | from farbox_bucket.server.web_app import app
5 | from farbox_bucket.bucket.token.utils import get_logined_bucket
6 | from farbox_bucket.clouds.wechat.bind_wechat import get_wechat_bind_code_for_bucket, get_wechat_user_docs_by_bucket
7 | from farbox_bucket.server.template_system.api_template_render import render_api_template_as_response
8 | from .wechat_handler import wechat_web_handler, WECHAT_TOKEN
9 |
10 | # 公众号后台获得公众号二维码,解析后是一个 URL 的字符串
11 | wechat_account_url = get_env("wechat_account_url") or ""
12 | wechat_account_url2 = get_env("wechat_account_url2") or ""
13 |
14 | @app.route("/__wechat_api", methods=["POST", "GET"])
15 | def wechat_api_view():
16 | return wechat_web_handler()
17 |
18 |
19 | @app.route("/__wechat_bind", methods=["POST", "GET"])
20 | def wechat_bind_view():
21 | if not WECHAT_TOKEN or not wechat_account_url:
22 | abort(404, "Wechat is not valid in current service")
23 | else:
24 | logined_bucket = get_logined_bucket(check=True)
25 | if not logined_bucket:
26 | return abort(404, "not login")
27 | bind_code = get_wechat_bind_code_for_bucket(logined_bucket)
28 | wechat_user_docs = get_wechat_user_docs_by_bucket(logined_bucket, with_name=True)
29 | response = render_api_template_as_response("wechat_bind.jade",
30 | wechat_user_docs=wechat_user_docs,
31 | bind_code=bind_code,
32 | wechat_account_url=wechat_account_url,
33 | wechat_account_url2 = wechat_account_url2)
34 | return response
35 |
36 |
37 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/build/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/deploy/build/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/deploy/build/build_client_image.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils import to_bytes, string_types, get_kwargs_from_console
3 | from xserver.docker_image.utils import build_docker_image
4 |
5 |
6 | docker_file_content = """FROM hepochen/pyweb:201908
7 | RUN apt-get -qq update
8 | ENV PYTHONIOENCODING=utf-8
9 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
10 | RUN apt-get install -y locales && locale-gen en_US.UTF-8
11 | RUN pip install farbox_bucket
12 | CMD ["/usr/bin/python", "-m", "farbox_bucket.client.run"]
13 | """
14 |
15 |
16 |
17 | # docker build -f Dockerfile -t hepochen/farbox_client:latest .
18 |
19 | def build_farbox_client_image(image_version):
20 | build_docker_image(
21 | image_name = 'farbox_client',
22 | image_version = image_version,
23 | docker_file_content = docker_file_content,
24 | )
25 |
26 |
27 | # build_farbox_client version=202105
28 | def build_farbox_client_image_from_console():
29 | kwargs = get_kwargs_from_console()
30 | image_version = kwargs.get('version') or '202105'
31 | build_farbox_client_image(image_version)
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/deploy/run/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/backend_jobs.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | import os
4 | os.environ['GEVENT_RESOLVER'] = 'ares'
5 | from gevent.monkey import patch_all; patch_all()
6 | import gevent
7 | import logging
8 |
9 |
10 | from farbox_bucket.server.backend.backend_jobs import backend_jobs
11 |
12 | if __name__ == '__main__':
13 | threads = []
14 | for job in backend_jobs:
15 | job = gevent.spawn(job)
16 | threads.append(job)
17 |
18 | logging.info('start cronjob now!')
19 |
20 | gevent.joinall(threads)
21 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/backup/nginx_websocket.conf:
--------------------------------------------------------------------------------
1 |
2 | upstream websocket_server {
3 | server unix:/tmp/websocket_server.sock fail_timeout=0;
4 | }
5 |
6 |
7 | location /_realtime/ {
8 | access_log off;
9 |
10 | tcp_nodelay on;
11 | proxy_buffering off;
12 |
13 | proxy_pass http://websocket_server;
14 | proxy_http_version 1.1;
15 | proxy_set_header Upgrade $http_upgrade;
16 | proxy_set_header Connection $connection_upgrade;
17 | proxy_set_header X-Real-IP $remote_addr;
18 | proxy_set_header X-Real-Port $remote_port;
19 | proxy_set_header Host $host;
20 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
21 |
22 | proxy_read_timeout 1h;
23 | proxy_send_timeout 1h;
24 | }
25 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/gunicorn.conf.py:
--------------------------------------------------------------------------------
1 | #coding:utf8
2 | import os
3 | os.environ['GEVENT_RESOLVER'] = 'ares'
4 | import multiprocessing
5 |
6 | try:
7 | import psutil as pu
8 | except:
9 | pu = None
10 |
11 | cpu_cores = multiprocessing.cpu_count()
12 | if cpu_cores >=8 :
13 | workers = cpu_cores
14 | else:
15 | workers = cpu_cores*2 + 1
16 | if workers > 11:
17 | workers = 11 # max workers
18 |
19 | if pu:
20 | mem_info = pu.virtual_memory()
21 | if mem_info.total < 5*1024*1024*1024: # 5G以下
22 | workers = 2
23 |
24 | bind = "unix:/tmp/web_server.sock"
25 | daemon = False
26 | worker_class = 'gevent'
27 | worker_connections = 1000 # worker的并发数,1k为默认值
28 | max_requests = 6000
29 | #preload = True
30 | timeout = 30
31 | graceful_timeout = 30
32 | pidfile = '/tmp/web_server.pid'
33 | proc_name = 'fb_bucket'
34 |
35 | limit_request_line = 6500
36 | # in bytes just 0.5k #目前并没有什么大的数据上的交互,但会影响url的长度限制
37 | # updated 201-3-20 支付宝这边回调的URL有点长 1300+
38 |
39 | # timeout 固定多少时间重启worker
40 | # graceful_timeout 接到重启后,多少时间后重启
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/gunicorn_websocket.conf.py:
--------------------------------------------------------------------------------
1 | #coding:utf8
2 | import os
3 | os.environ['GEVENT_RESOLVER'] = 'ares'
4 | workers = 1
5 | bind = "unix:/tmp/websocket_server.sock"
6 | daemon = False
7 | worker_class = 'geventwebsocket.gunicorn.workers.GeventWebSocketWorker'
8 | #worker_connections = 1000
9 | #max_requests = 5000 #默认为0,不然worker会被重启
10 | keepalive = 5
11 | timeout = 300
12 | graceful_timeout = 30
13 | pidfile = '/tmp/websocket_server.pid'
14 | limit_request_line = 500 #in bytes just 0.5k #目前并没有什么大的数据上的交互,但会影响url的长度限制
15 | proc_name = 'websocket'
16 | # timeout 固定多少时间重启worker
17 | # graceful_timeout 接到重启后,多少时间后重启
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/memcached.conf:
--------------------------------------------------------------------------------
1 | # memcached default config file
2 | # 2003 - Jay Bonci
3 | # This configuration file is read by the start-memcached script provided as
4 | # part of the Debian GNU/Linux distribution.
5 |
6 | # Run memcached as a daemon. This command is implied, and is not needed for the
7 | # daemon to run. See the README.Debian that comes with this package for more
8 | # information.
9 | -d
10 |
11 | # Log memcached's output to /var/log/memcached
12 | logfile /var/log/memcached.log
13 |
14 | # Be verbose
15 | # -v
16 |
17 | # Be even more verbose (print client commands as well)
18 | # -vv
19 |
20 | # Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
21 | # Note that the daemon will grow to this size, but does not start out holding this much
22 | # memory
23 | # 1G
24 | -m 1024
25 |
26 | # Default connection port is 11211
27 | -p 11211
28 |
29 | # Run the daemon as root. The start-memcached will default to running as root if no
30 | # -u command is present in this config file
31 | -u root
32 |
33 | # Specify which IP address to listen on. The default is to listen on all IP addresses
34 | # This parameter is one of the only security measures that memcached has, so make sure
35 | # it's listening on a firewalled interface.
36 | -l 127.0.0.1
37 |
38 | # Limit the number of simultaneous incoming connections. The daemon default is 1024
39 | -c 5000
40 |
41 | # Lock down all paged memory. Consult with the README and homepage before you do this
42 | # -k
43 |
44 | # Return error when memory is exhausted (rather than removing items)
45 | # -M
46 |
47 | # Maximize core file limit
48 | # -r
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/nginx/nginx_body.conf:
--------------------------------------------------------------------------------
1 |
2 | types_hash_max_size 2048;
3 |
4 | # sendfile() is more efficient than the combination of read(2) and write(2)
5 | sendfile on;
6 | tcp_nopush on;
7 |
8 | client_max_body_size 300M;
9 |
10 | proxy_buffering off;
11 | proxy_buffer_size 128k;
12 | proxy_buffers 4 256k;
13 | proxy_busy_buffers_size 256k;
14 | #buffer large proxied requests to the filesystem
15 | proxy_temp_path /tmp/nginx-tmp;
16 |
17 | gzip on;
18 | gzip_min_length 1k;
19 | gzip_buffers 4 16k;
20 | gzip_http_version 1.0;
21 | gzip_comp_level 6;
22 | gzip_types text/plain application/x-javascript application/javascript text/css application/xml application/json font/ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
23 | gzip_vary on;
24 | gzip_disable "msie6";
25 |
26 |
27 | location ~* \.(wmv|exe|asp|php)$ {
28 | access_log off;
29 | error_log /dev/null;
30 | deny all;
31 | }
32 |
33 | location / {
34 |
35 | access_by_lua_file /mt/web/configs/openresty/access.lua;
36 |
37 | if ($http_user_agent ~* monitor ) {
38 | return 200;
39 | access_log off;
40 | }
41 |
42 | # if ($request_method !~ ^(GET|POST|PUT)$) {
43 | # return 405;
44 | # access_log off;
45 | #}
46 |
47 | #if ($http_user_agent ~* (ChinaCache|Webluker) ) {
48 | # access_log off;
49 | # return 403;
50 | #}
51 |
52 | #proxy_request_buffering off;
53 | access_log /mt/web/log/nginx_web_server.access.log main;
54 | proxy_set_header X-Forwarded-For $remote_addr;
55 | proxy_set_header Host $http_host;
56 | proxy_redirect off;
57 | proxy_set_header X-Protocol $scheme;
58 | proxy_pass http://app_server;
59 |
60 | #limit_conn conn_limit_per_ip 50;
61 | }
62 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/nginx/server.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDlefPmmwVOHE4l
3 | VFUfpFGbElPMKETK6G00fcdElS5ArSVyfi0w5kwz4Xxsu/1kA/Eenc0zWOQuMkaZ
4 | gbPx3Oe3tTlmg8//DjNuh5P2mSnPlHw3fiXA3/h9vVqGjQKqZxdXyWSrUUzh7493
5 | M2ZjUgT2il9ZkhJ+nho9u8H0wFI6g1PYvjc8v+AQCkk7fXSqRlvJREt6DfAHaWEL
6 | UJjg101L2ZBysLRgY7wYnVIl2VagF41WSfEF9mGUBlRhitxJq5laJvyWkCdbp4wh
7 | /OSwX8PokmfYr9v5K9rFWv08FsHJRzdqZfOfca97oWROMzYcOgFMqFijjIN/qZF5
8 | Ep7ro82pAgMBAAECggEAX/426BWbD4TJr9XqUfUz6fGtui5yMIsv+5BOBkN9eLK1
9 | goKDtvvvjphZq0asheUcPVl3mG4r7aM8Y0SdmKR3DiMyIs8q+B/hpe/zFmoV0m7j
10 | 03biph9K3JaUQsrD/bJoUmG9yeiVh8HlutB2mT+bMeLKZjazo+HRSle7l/3HqA+y
11 | 0OHqAbFw/2befMEIvvjuPxpf0s485JHrA6fARLdVmLyAQqcYifdO5LdySaxzqr4Z
12 | KsRlxGRBOA0fk6UlYZa+t2Idhgid/NoqL2/SP3cyY5QqmcuIq3ZVDgIbZSoUPJWo
13 | dA8GY8+7OWSIdPmu6d3RG/6ahFLl+OLSiIu9RWc6XQKBgQD8+u29EAz1NMR2l2LS
14 | Zi2dtmOift68+NbI+txqYvXka1AOSSuenAl9OrU1ss4VfOSPom2XoBn0rTR0fvHQ
15 | 9rthevvey0bzBWzDkoxSnkYR/RpAskzKoU9teIgPsK1EkGf7LkARLeRh6AmWDg9p
16 | yEdNYFUrulwCEN0uWyw6Z3xzewKBgQDoNzMkoh6WPy5GBjjuS6nVY+p3MumnNqmI
17 | KmzEmrN99idR5JMNhWD4X9dUrnHzOESOer6aU5+x6mSfvE4zRjNAqFZocxs5YmB6
18 | +/vqGzNik8pE63HO22U7hCshZUyovXs073EKorl4ofdj7uX4/Hj9/lmOzSTLBJTB
19 | zz5sWXS4KwKBgCaf0ShqiO/vLIfGuUnSW+iWbkPjBvLnMzPgSULc9Rn44HIt7cD7
20 | pd8+1WfrcteJCAR+EilyQkQ/JaEbuKPk59sMQeRUOPLlwyNg/pemnqAkepuiHWNa
21 | mZvnKS7sFKhBO/73osR8sz/Xg48remL2NxyzNo3EmEOge4SWWvxXzIJ9AoGBAMrw
22 | 6u5aDLcsEkm6SGjhkVRflNqFkTPEjtbklNghhzpPNL/aLjYD2eJXCD4GkqmIBEos
23 | tYT0Dj2T5kq/a+xdro8UTyfLaQB2nHD+5YMMMJU3Ke+fgH/St58S/AqcmClkJ1f0
24 | 5mrwGX12t1kLwMogA7GeZzBo0n3mzAaxExHoAByvAoGBANSn/Y6GV6ct+BQIuJPj
25 | XHHKdKdTjD0CDpZJK7TAxHYvrNim+XL572xPXlgZMogEGCKwd0N/xxb9aOSuQk3R
26 | 0jFjTS6Rp8cNesqfWasfa1AIdWJjgha2uqWa+6U4E/XQ5zRMVSziEworMb8Uy6Nl
27 | 0kNd1qbTdCvSXY/4139IfnvF
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/openresty/access.lua:
--------------------------------------------------------------------------------
1 | local log = ngx.log
2 | local memcached = require "resty.memcached"
3 | local memc, err = memcached:new()
4 | if not memc then
5 | log(ngx.ERR, "failed to instantiate memc: ", err)
6 | return
7 | end
8 |
9 | memc:set_timeout(1000) -- 1 sec
10 |
11 | local ok, err = memc:connect("127.0.0.1", 11211)
12 | if not ok then
13 | log(ngx.ERR, "failed to connect: ", err)
14 | return
15 | end
16 |
17 | local client_ip = ngx.var.remote_addr
18 |
19 | local ip_block_id = "block-" .. client_ip
20 | local ip_block_value, flags, err = memc:get(ip_block_id)
21 |
22 | if err then
23 | log(ngx.ERR, "memcached error: ", err)
24 | return
25 | end
26 |
27 | -- put it into the connection pool of size 100,
28 | -- with 10 seconds max idle timeout
29 | local ok, err = memc:set_keepalive(10000, 100)
30 | if not ok then
31 | log(ngx.ERR, "cannot set keepalive: ", err)
32 | end
33 |
34 |
35 | if ip_block_value then
36 | ngx.exit(ngx.HTTP_FORBIDDEN)
37 | end
38 |
39 |
40 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/configs/ssdb.conf:
--------------------------------------------------------------------------------
1 | # ssdb-server config
2 | # MUST indent by TAB!
3 |
4 | # absolute path, or relative to path of this file, directory must exists
5 | work_dir = /mt/ssdb/data
6 | pidfile = /var/run/ssdb.pid
7 |
8 | server:
9 | ip: 0.0.0.0
10 | port: 8888
11 | # bind to public ip
12 | #ip: 0.0.0.0
13 | # format: allow|deny: all|ip_prefix
14 | # multiple allows or denys is supported
15 | #deny: all
16 | #allow: 127.0.0.1
17 | #allow: 192.168
18 | # auth password must be at least 32 characters
19 | #auth: very-strong-password
20 | #readonly: yes
21 | # in ms, to log slowlog with WARN level
22 | #slowlog_timeout: 5
23 |
24 | replication:
25 | binlog: yes
26 | # Limit sync speed to *MB/s, -1: no limit
27 | sync_speed: -1
28 | slaveof:
29 | # to identify a master even if it moved(ip, port changed)
30 | # if set to empty or not defined, ip:port will be used.
31 | #id: svc_2
32 | # sync|mirror, default is sync
33 | #type: sync
34 | #host: localhost
35 | #port: 8889
36 |
37 | logger:
38 | level: info
39 | output: /mt/web/log/ssdb_log.txt
40 | rotate:
41 | size: 1000000000
42 |
43 | leveldb:
44 | # in MB
45 | cache_size: 500
46 | # in MB
47 | write_buffer_size: 24
48 | # in MB/s
49 | compaction_speed: 1000
50 | # yes|no
51 | compression: yes
52 |
53 | # compression 10 times?
54 | # normally, cache_size + write_buffer_size*4 + 32 = 628 MB, about 1GB in fact
55 | # max in short time, cache_size + 10*write_buffer_size*66 + 32 = 16 GB
56 |
--------------------------------------------------------------------------------
/farbox_bucket/deploy/run/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | docker run -d \
3 | -p 7788:80 -p 443:443 -p 80:80 \
4 | -v /home/run/$name$/configs:/mt/web/configs \
5 | -v /data/log/$name$:/mt/web/log \
6 | -v /data/$name$:/mt/web/data \
7 | -v /data/$name$_ssdb:/mt/ssdb/data \
8 | -v /static/$name$:/mt/web/static \
9 | -v /log/docker:/mt/docker/log \
10 | hepochen/farbox_bucket:latest
--------------------------------------------------------------------------------
/farbox_bucket/for_dev/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/for_dev/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/for_dev/check_alipay.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils.pay.alipay_api import AlipayAPI
3 |
4 | def check_qrcode_alipay(app_id, private_key):
5 | alipay = AlipayAPI(app_id=app_id, private_key=private_key)
6 | info = alipay.pay(0.01, 'hello', 'world', qrcode=True)
7 | print(info)
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/farbox_bucket/for_dev/check_encrypt_performance.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils.encrypt.des_encrypt import encrypt_des, decrypt_des
3 | from farbox_bucket.utils.encrypt.aes_encrypt import encrypt_aes, decrypt_aes
4 | import time
5 |
6 | content = 'hello world this is test'
7 | password = 'passwordhere'
8 |
9 | def check_encrypt_performance():
10 | t1 = time.time()
11 | for i in range(10000):
12 | c = encrypt_aes(content, password, encode_type='raw')
13 | d = decrypt_aes(c, password, encode_type='raw')
14 | print("original_size is %s, encrypted_content size is %s, is equal: %s" % (len(content), len(c), d==content))
15 | print("encrypt & decrypt costs %s seconds" % (time.time() - t1))
16 |
17 |
18 |
19 | t1 = time.time()
20 | for i in range(10000):
21 | c = encrypt_des(content, password, )
22 | d = decrypt_des(c, password, )
23 | print("encrypt & decrypt costs %s seconds, in base64 " % (time.time() - t1))
24 |
25 |
26 |
27 | if __name__ == "__main__":
28 | check_encrypt_performance()
--------------------------------------------------------------------------------
/farbox_bucket/for_dev/jinja_template_source.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from jinja2.sandbox import SandboxedEnvironment
3 | from farbox_bucket.utils.convert.jade2jinja import convert_jade_to_html
4 |
5 | def get_jinja_source_code_from_jade(jade_content, with_lines=True):
6 | source_code_lines = []
7 | html_content = convert_jade_to_html(jade_content)
8 | env = SandboxedEnvironment()
9 | #env.compile(html_content)
10 | source = env._parse(html_content, None, None)
11 | python_code = env._generate(source, None, None, False)
12 | python_lines = python_code.split("\n")
13 | for (i, python_line) in enumerate(python_lines):
14 | if with_lines:
15 | source_code_lines.append("%s:%s" % (i+1, python_line))
16 | else:
17 | source_code_lines.append(python_line)
18 | return "\n".join(source_code_lines)
19 |
20 |
21 | def print_jinja_source_code_from_jade_file(jade_filepath):
22 | with open(jade_filepath) as f:
23 | jade_content = f.read()
24 | source_code = get_jinja_source_code_from_jade(jade_content, with_lines=True)
25 | print(source_code)
--------------------------------------------------------------------------------
/farbox_bucket/for_dev/markdown_post_compile_info.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | import os
3 | from farbox_bucket.settings import MAX_RECORD_SIZE
4 | from farbox_bucket.client.sync.compiler_worker import get_compiler_data_directly
5 | from farbox_bucket.utils.data import json_dumps
6 |
7 | def get_markdown_post_compiled_info(md_filepath, content_times = 1):
8 | with open(md_filepath, "rb") as f:
9 | raw_content = f.read()
10 | content = raw_content * content_times
11 | if len(content) > MAX_RECORD_SIZE:
12 | print("content size too big")
13 | filename = os.path.split(md_filepath)[-1]
14 | compiled_data = get_compiler_data_directly(filename, content=content)
15 | record_size = len(json_dumps(compiled_data))
16 | print("file_type: %s, zipped:%s, file_size:%s, record_size:%s" %(compiled_data.get("type"),
17 | compiled_data.get("_zipped"),
18 | compiled_data.get("size"),
19 | record_size))
20 |
21 |
22 |
--------------------------------------------------------------------------------
/farbox_bucket/i18n/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import zh_cn
3 |
4 |
5 | default_i18n_data = {
6 | 'zh_cn': zh_cn.data,
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/farbox_bucket/server/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/avatar.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import requests
3 | from farbox_bucket.utils import get_md5, string_types
4 | from farbox_bucket.utils.ssdb_utils import hexists
5 |
6 |
7 | def get_avatar_id(email): # 根据邮件地址,或者对应的m5值作为avatar_id
8 | if isinstance(email, string_types) and email:
9 | email = email.lower().strip()
10 | if '@' in email:
11 | return get_md5(email)
12 | else:
13 | return email
14 | return None # if not
15 |
16 |
17 |
18 | def get_gavatar_image_content(email):
19 | avatar_id = get_avatar_id(email)
20 | gravatar_url = 'https://en.gravatar.com/%s.json' % avatar_id
21 | response = requests.get(gravatar_url, verify=False, timeout=10)
22 | if response.status_code != 200:
23 | return ''
24 | response_info = response.json()
25 | gravatar_image_url = response_info['entry'][0]['thumbnailUrl']
26 | if gravatar_image_url:
27 | try:
28 | image_response = requests.get(gravatar_image_url, timeout=10, verify=False)
29 | if image_response.status_code > 300:
30 | return '' # ignore
31 | else:
32 | return image_response.content
33 | except:
34 | return ''
35 |
36 | def has_avatar(email_md5):
37 | if '@' in email_md5:
38 | email_md5 = get_avatar_id(email_md5)
39 | if not isinstance(email_md5, string_types):
40 | return False
41 | if len(email_md5) > 64:
42 | return False
43 | email_md5 = email_md5.lower().strip()
44 | return hexists('_avatar', email_md5)
45 |
46 |
47 | def get_avatar_url(email):
48 | avatar_id = get_avatar_id(email)
49 | url = '/service/avatar/%s' % avatar_id
50 | return url
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/farbox_bucket/server/backend/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/backend/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/backend/backend_jobs.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | from farbox_bucket.utils.env import get_env
4 | from farbox_bucket.server.backend.service import keep_watch_nginx, restart_backend_per_day, keep_watch_memcache, run_logrotate
5 |
6 | should_sync_buckets = get_env("should_sync_buckets_in_backend")
7 | if should_sync_buckets == "no":
8 | should_sync_buckets = False
9 |
10 | backend_jobs = [
11 | keep_watch_nginx,
12 | keep_watch_memcache,
13 | restart_backend_per_day,
14 | run_logrotate,
15 | ]
16 |
17 | if should_sync_buckets:
18 | # 减少 backend 的内存占用,如果只是守护性质的话
19 | from farbox_bucket.server.backend.sync.buckets import sync_buckets_from_remote_marked, sync_buckets_from_remote_nodes
20 | backend_jobs.append(sync_buckets_from_remote_marked)
21 | backend_jobs.append(sync_buckets_from_remote_nodes)
--------------------------------------------------------------------------------
/farbox_bucket/server/backend/status/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/backend/status/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/backend/sync/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/backend/sync/buckets.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
4 | from farbox_bucket.utils.gevent_run import run_long_time
5 |
6 | from farbox_bucket.bucket.sync.node import sync_buckets_from_remote_nodes_by_gevent
7 | from farbox_bucket.bucket.sync.remote import sync_buckets_from_remote_marked_by_gevent
8 |
9 |
10 |
11 | @run_long_time(wait=10, sleep_at_end=10*60, log='sync from remote nodes')
12 | def sync_buckets_from_remote_nodes():
13 | sync_buckets_from_remote_nodes_by_gevent(pool_size=20)
14 |
15 |
16 |
17 |
18 | @run_long_time(wait=10, sleep_at_end=60, log='sync buckets marked from remote')
19 | def sync_buckets_from_remote_marked():
20 | sync_buckets_from_remote_marked_by_gevent(pool_size=30)
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/farbox_bucket/server/backend/sync/utils.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | import os
4 |
5 |
6 | def get_node_url(node, route='farbox_bucket_message_api'):
7 | node = node or ''
8 | if '://' in node:
9 | node = node.split('://')[-1]
10 | node = node.strip().strip('/').strip()
11 | if not node:
12 | node = os.environ.get('DEFAULT_NODE') or '127.0.0.1:7788'
13 | if ':' not in node:
14 | node = '%s:7788' % node
15 | node_url = 'http://%s/%s' % (node, route.lstrip('/'))
16 | return node_url
--------------------------------------------------------------------------------
/farbox_bucket/server/bucket_render/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/bucket_render/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/bucket_render/builtin_theme/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/bucket_render/builtin_theme/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/bucket_render/builtin_theme/_render.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 | from .wiki import show_wiki_as_sub_site, show_wiki_nodes_as_sub_site
4 | from .album import show_albums_as_sub_site
5 |
6 |
7 | sub_site_funcs = [
8 | show_albums_as_sub_site,
9 | show_wiki_as_sub_site,
10 | show_wiki_nodes_as_sub_site,
11 | ]
12 |
13 | def show_builtin_theme_as_sub_site():
14 | for sub_site_func in sub_site_funcs:
15 | sub_site_html = sub_site_func()
16 | if sub_site_html:
17 | return sub_site_html
18 |
--------------------------------------------------------------------------------
/farbox_bucket/server/comments/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/comments/contacts.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from farbox_bucket.utils import smart_unicode, get_value_from_data
3 | from farbox_bucket.server.comments.utils import get_comments
4 |
5 |
6 |
7 | def get_contacts_from_comments(comments):
8 | # 从评论中获取name + email的字典 unicode
9 | # comments 是一个 dict 类型组成的 list
10 | contacts = dict()
11 | for comment in comments:
12 | if not isinstance(comment, dict):
13 | continue
14 | author = comment.get('author')
15 | email = comment.get('email')
16 | if author and email:
17 | contacts[smart_unicode(author)] = email.lower()
18 | return contacts
19 |
20 |
21 |
22 | def get_default_contacts_from_post(post):
23 | contacts = {}
24 | if isinstance(post, dict) and post.get('type') == 'post':
25 | from_address = get_value_from_data(post, 'metadata.from')
26 | from_author_name = get_value_from_data(post, 'metadata.author')
27 | if from_address and from_author_name:
28 | contacts[from_author_name] = from_address
29 | return contacts
30 |
31 |
32 | def get_all_contacts_from_post(post, comments=None):
33 | if not post:
34 | return {}
35 | if comments is None:
36 | comments = get_comments(post)
37 |
38 | contacts = get_contacts_from_comments(comments) # it's a dict
39 |
40 |
41 | # 从 post 的 meta中处理, 一般都是 Bitcron Mail 产生的post,才有这样的属性
42 | contacts.update(get_default_contacts_from_post(post))
43 |
44 | # name 全部 lower 化,这样才能@的时候,不敏感
45 | lower_name_contacts = {smart_unicode(k).lower():v for k, v in contacts.items()}
46 | return lower_name_contacts
47 |
48 |
49 |
50 | def get_contacts_from_new_comment(new_comment):
51 | # new_comment 是 web.utils.comment.add.NewComment 的实例化对象
52 | return get_all_contacts_from_post(new_comment.parent_obj)
53 |
54 |
55 |
--------------------------------------------------------------------------------
/farbox_bucket/server/dangerous/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/dangerous/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/dangerous/install_py_package.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import os
3 | import re
4 | from gevent import spawn_later
5 |
6 |
7 | def restart_web_service():
8 | try:
9 | with os.popen("kill -HUP `cat /tmp/web_server.pid`") as f:
10 | f.read()
11 | except:
12 | pass
13 |
14 | def install_py_package_by_web(url):
15 | if not "://" in url:
16 | return
17 | # https://files.pythonhosted.org/packages/57/43/8d7120e714fbaa6d44ab381333f8b3a2960f2bdfebe3091c68c42d89ee14/farbox_bucket-0.1880.tar.gz
18 | if not re.match("[:/a-z0-9\-_.]+$", url):
19 | return "this url is invalid"
20 | try:
21 | with os.popen("pip install %s" % url) as f:
22 | result = f.read()
23 | except:
24 | result = ""
25 | spawn_later(3, restart_web_service)
26 | return result
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/farbox_bucket/server/dangerous/log_rotate.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import os
3 |
4 | def do_install_project_log_rotate(force=False):
5 | config_folder = "/etc/logrotate.d"
6 | if not os.path.isdir(config_folder):
7 | return
8 | project_log_rotate_config_filepath = os.path.join(config_folder, "farbox_bucket")
9 | if not force and os.path.isfile(project_log_rotate_config_filepath):
10 | return
11 | project_log_rotate_content = """/mt/web/log/nginx_web_server.access.log {
12 | rotate 7
13 | size 5k
14 | dateext
15 | dateformat -%Y-%m-%d
16 | missingok
17 | compress
18 | sharedscripts
19 | postrotate
20 | test -r /var/run/nginx.pid && kill -USR1 `cat /var/run/nginx.pid`
21 | endscript
22 | }
23 | """
24 | with open(project_log_rotate_config_filepath, "wb") as f:
25 | f.write(project_log_rotate_content)
26 |
27 |
28 | def install_project_log_rotate(force=False):
29 | try:
30 | do_install_project_log_rotate(force=force)
31 | except:
32 | pass
--------------------------------------------------------------------------------
/farbox_bucket/server/dangerous/restart.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import os
3 | from .log_rotate import install_project_log_rotate
4 |
5 | def try_to_reload_web_app(restart_backend=False):
6 | install_project_log_rotate(force=True)
7 | if not os.path.isfile("/tmp/web_server.pid"):
8 | return
9 | try:
10 | with os.popen("kill -HUP `cat /tmp/web_server.pid`") as f:
11 | f.read()
12 | except:
13 | pass
14 |
15 | if restart_backend:
16 | try:
17 | with os.popen("/usr/local/bin/supervisorctl restart farbox_bucket_backend") as f:
18 | f.read()
19 | except:
20 | pass
--------------------------------------------------------------------------------
/farbox_bucket/server/es/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/es/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/es/es_status.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.bucket.utils import get_bucket_last_record_id
3 | from .es_client import get_es_client, doc_fields_in_es, make_sure_es_indexes
4 | from .es_utils import get_es_index_doc, search_es
5 |
6 |
7 |
8 |
9 | def get_es_status_for_bucket(bucket):
10 | es = get_es_client()
11 | status = dict(
12 | db_last_id = get_bucket_last_record_id(bucket),
13 | es_is_valid = False if not es else True,
14 | )
15 | if not es:
16 | return status
17 | es_info = get_es_index_doc('info', bucket)
18 | if es_info:
19 | status["es_cursor"] = es_info.get("cursor")
20 | try:
21 | es_count_result = es.count(q='bucket:"%s"' % bucket, routing=bucket)
22 | es_count = es_count_result.get("count") or 0
23 | except:
24 | es_count = 0
25 | status["es_count"] = es_count
26 | status["es_indexes_ok"] = es.indices.exists("info") and es.indices.exists("doc")
27 |
28 | return status
--------------------------------------------------------------------------------
/farbox_bucket/server/helpers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/helpers/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/realtime/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | # 不能把app变量放到这里来,因为app本身会开启一些loop的命令,会导致其它地方调用websocket_server.xxx下的utils,会强启app内的命令
--------------------------------------------------------------------------------
/farbox_bucket/server/static/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/auto_toc/auto_toc.coffee:
--------------------------------------------------------------------------------
1 |
2 | get_toc_default_top = ->
3 | return $('.doc_toc').offset().top or 0
4 |
5 | $(document).ready =>
6 | toc_selector = '.doc_toc'
7 | current_active_class = 'current_active'
8 | toc_element = $(toc_selector)
9 |
10 | $('.doc_toc a').click ->
11 | toc_content_dom_id = $(this).attr('href').slice(1)
12 | if toc_content_dom_id
13 | toc_content_dom = $('#'+toc_content_dom_id)
14 | y = toc_content_dom.offset().top
15 | scroll_to_y = y
16 | if scroll_to_y < 0
17 | scroll_to_y = 0
18 | $('body,html').animate {scrollTop: scroll_to_y }, 800
19 | new_hash_name = '#'+toc_content_dom_id
20 | if history.pushState
21 | history.pushState(null, null, new_hash_name);
22 | else
23 | window.location.hash = new_hash_name
24 | return false
25 |
26 | remove_current_toc_active_class = ->
27 | $(toc_selector+' .'+current_active_class).removeClass(current_active_class)
28 |
29 | toc_element.on 'activate.bs.scrollspy', ->
30 | current_active_element = $(toc_selector+' .active').last()
31 | remove_current_toc_active_class()
32 | current_active_element.addClass(current_active_class)
33 |
34 | toc_element.on 'clear.bs.scrollspy', remove_current_toc_active_class
35 |
36 |
37 | $('.doc_toc_container').affix({
38 | offset: {
39 | top: (toc_offset_top if toc_offset_top?) or get_toc_default_top(),
40 | bottom: (toc_offset_bottom if toc_offset_bottom?) or 0
41 | }
42 | });
43 |
44 | $(document).on 'affixed.bs.affix', ->
45 | height = (document.body.clientHeight - 100) or 'auto'
46 | $('.doc_toc').css('max-height', height)
47 |
48 |
49 | $('body').scrollspy({target: toc_selector})
50 |
51 | if $(window).width()< 480
52 | $('.doc_toc').css('display', 'none')
53 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/auto_toc/auto_toc.css:
--------------------------------------------------------------------------------
1 | .doc_toc {
2 | position: static;
3 | font-size: 12px; }
4 | .doc_toc a {
5 | text-decoration: none;
6 | line-height: 1.1;
7 | color: #555555; }
8 | .doc_toc ul {
9 | line-height: 1.8em;
10 | list-style: none;
11 | padding-left: 20px; }
12 | .doc_toc ul li {
13 | list-style: none; }
14 | .doc_toc ul ul {
15 | padding-left: 16px; }
16 | .doc_toc ul ul ul {
17 | padding-left: 12px; }
18 | .doc_toc li {
19 | margin: 0.5em auto; }
20 | .doc_toc li ul {
21 | padding: 0 0 0 1em; }
22 | .doc_toc li > ul {
23 | margin-top: -5px;
24 | margin-bottom: 6px; }
25 | .doc_toc .active > a {
26 | color: #000000;
27 | font-weight: bold; }
28 |
29 | .affix {
30 | position: fixed !important; }
31 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/auto_toc/auto_toc.scss:
--------------------------------------------------------------------------------
1 | $link_color: #555555;
2 | $active_color: #000000;
3 |
4 |
5 | .doc_toc{
6 | position: static;
7 | font-size:12px;
8 | // width: 200px;
9 |
10 | a{
11 | text-decoration: none;
12 | line-height: 1.1;
13 | color: $link_color;
14 | }
15 |
16 |
17 | ul {
18 | line-height: 1.8em;
19 | list-style: none;
20 | padding-left: 20px;
21 | li {
22 | list-style: none;
23 | }
24 |
25 | ul{
26 | padding-left: 16px;
27 | }
28 | ul ul{
29 | padding-left: 12px;
30 | }
31 | }
32 |
33 |
34 | li{
35 | margin: 0.5em auto;
36 |
37 | ul{
38 | padding: 0 0 0 1em;
39 | }
40 |
41 | & > ul{
42 | margin-top: -5px;
43 | margin-bottom: 6px;
44 | }
45 | }
46 |
47 | .active{
48 | & > a{
49 | color: $active_color;
50 | font-weight: bold;
51 | }
52 | }
53 |
54 | }
55 |
56 | .affix {
57 | position: fixed !important;
58 | }
59 |
60 |
61 |
62 | /*
63 | @media screen and (max-width: 680px) {
64 | .toc_container{
65 | display: none;
66 | }
67 | }
68 | */
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/form/ajax.coffee:
--------------------------------------------------------------------------------
1 | @run_ajax_backend = (url, method, callback_func, data)->
2 | if typeof(data)=='string'
3 | data = $.parseJSON(data)
4 | if typeof(callback_func)=='string'
5 | callback_func = window[callback_func]
6 | ajax_data =
7 | url: url
8 | method: method
9 | success: (response_data)->
10 | if callback_func
11 | callback_func(true, response_data)
12 | error: (response_data)->
13 | if callback_func
14 | callback_func(false, response_data)
15 | if data
16 | $.extend(ajax_data, data)
17 | $.ajax(ajax_data)
18 | return false
19 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/form/ajax.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | this.run_ajax_backend = function(url, method, callback_func, data) {
4 | var ajax_data;
5 | if (typeof data === 'string') {
6 | data = $.parseJSON(data);
7 | }
8 | if (typeof callback_func === 'string') {
9 | callback_func = window[callback_func];
10 | }
11 | ajax_data = {
12 | url: url,
13 | method: method,
14 | success: function(response_data) {
15 | if (callback_func) {
16 | return callback_func(true, response_data);
17 | }
18 | },
19 | error: function(response_data) {
20 | if (callback_func) {
21 | return callback_func(false, response_data);
22 | }
23 | }
24 | };
25 | if (data) {
26 | $.extend(ajax_data, data);
27 | }
28 | $.ajax(ajax_data);
29 | return false;
30 | };
31 |
32 | }).call(this);
33 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/form/fields/color.coffee:
--------------------------------------------------------------------------------
1 |
2 | @when_mini_colors_show = ->
3 | if after_mini_colors_show?
4 | after_mini_colors_show()
5 |
6 | @when_mini_colors_hide = ->
7 | if after_mini_colors_hide?
8 | after_mini_colors_hide()
9 |
10 |
11 | @install_mini_colors = ->
12 | $('.color_input').minicolors({show:when_mini_colors_show, hide: when_mini_colors_hide})
13 |
14 | $(document).ready ->
15 | install_mini_colors()
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/form/fields/color.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | this.when_mini_colors_show = function() {
4 | if (typeof after_mini_colors_show !== "undefined" && after_mini_colors_show !== null) {
5 | return after_mini_colors_show();
6 | }
7 | };
8 |
9 | this.when_mini_colors_hide = function() {
10 | if (typeof after_mini_colors_hide !== "undefined" && after_mini_colors_hide !== null) {
11 | return after_mini_colors_hide();
12 | }
13 | };
14 |
15 | this.install_mini_colors = function() {
16 | return $('.color_input').minicolors({
17 | show: when_mini_colors_show,
18 | hide: when_mini_colors_hide
19 | });
20 | };
21 |
22 | $(document).ready(function() {
23 | return install_mini_colors();
24 | });
25 |
26 | }).call(this);
27 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/form/fields/icon.coffee:
--------------------------------------------------------------------------------
1 |
2 |
3 | @pick_icon_for_field = (click_dom)->
4 | parent_dom = $(click_dom).parent()
5 | icon_input_dom = parent_dom.find('.icon_input')
6 | icon_input_dom.inputIconSelector()
7 |
8 | @when_icon_inserted = (icon_input_dom)->
9 | if icon_input_dom.hasClass('icon_input')
10 | field_dom = icon_input_dom.parent()
11 | i_dom = field_dom.find('span i')
12 | i_dom.html('')
13 | i_dom.attr('class', icon_input_dom.val())
14 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/form/fields/icon.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | this.pick_icon_for_field = function(click_dom) {
4 | var icon_input_dom, parent_dom;
5 | parent_dom = $(click_dom).parent();
6 | icon_input_dom = parent_dom.find('.icon_input');
7 | return icon_input_dom.inputIconSelector();
8 | };
9 |
10 | this.when_icon_inserted = function(icon_input_dom) {
11 | var field_dom, i_dom;
12 | if (icon_input_dom.hasClass('icon_input')) {
13 | field_dom = icon_input_dom.parent();
14 | i_dom = field_dom.find('span i');
15 | i_dom.html('');
16 | return i_dom.attr('class', icon_input_dom.val());
17 | }
18 | };
19 |
20 | }).call(this);
21 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/js_view/images/border1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/api/html/js_view/images/border1.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/js_view/images/border2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/api/html/js_view/images/border2.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/js_view/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/api/html/js_view/images/loading.gif
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/html/js_view/images/readme.txt:
--------------------------------------------------------------------------------
1 | for color box mainly
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/modal.coffee:
--------------------------------------------------------------------------------
1 | g = this
2 | @current_modal_click_button_value = null
3 | @current_modal_click_button_value2 = null
4 | @current_modal_click_button_value3 = null
5 |
6 | $(document).ready ->
7 | $(document).on 'modal:close', (event, modal)->
8 | try Essage.hide()
9 |
10 |
11 | $('input.modal_with_selector').each (i,dom)->
12 | dom = $(dom)
13 | modal_dom = $(dom.attr('data-modal-dom'))
14 | click_dom = $(dom.attr('data-click-dom'))
15 | click_dom.click ->
16 | modal_dom.modal()
17 | current_click_dom = $(this)
18 | g.current_modal_click_button_value = current_click_dom.attr('data-value')
19 | g.current_modal_click_button_value2 = current_click_dom.attr('data-value2')
20 | g.current_modal_click_button_value3 = current_click_dom.attr('data-value3')
21 | if after_modal_display?
22 | try after_modal_display(current_click_dom, modal_dom)
23 | return false
24 |
25 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/modal.css:
--------------------------------------------------------------------------------
1 | .modal_wrap {
2 | width: 70%; }
3 |
4 | .modal_container {
5 | max-height: 550px;
6 | overflow-y: auto;
7 | overflow-x: hidden;
8 | color: #333;
9 | font-size: 14px; }
10 |
11 | .modal_wrap ::-webkit-scrollbar {
12 | width: 4px;
13 | margin: 0 1px;
14 | background: #fdfdfd; }
15 | .modal_wrap ::-webkit-scrollbar:horizontal {
16 | height: 4px; }
17 | .modal_wrap ::-webkit-scrollbar-button {
18 | height: 0; }
19 | .modal_wrap ::-webkit-scrollbar-track {
20 | border-radius: 2px; }
21 | .modal_wrap ::-webkit-scrollbar-track-piece {
22 | background-color: #fdfdfd;
23 | border-radius: 2px; }
24 | .modal_wrap ::-webkit-scrollbar-thumb {
25 | width: 8px;
26 | margin: 0 1px;
27 | border-radius: 2px;
28 | background: #c4c4c4; }
29 | .modal_wrap ::-webkit-scrollbar-thumb:hover {
30 | background: #909090; }
31 |
32 | .modal {
33 | font-size: 14px; }
34 | .modal form {
35 | color: #555; }
36 | .modal form h2 {
37 | color: #111;
38 | margin-top: 1em !important; }
39 | .modal form .fields .field {
40 | margin: 0.8em auto 1.2em auto !important; }
41 |
42 | @media screen and (min-width: 48em) {
43 | .modal .pure-u-md-1-3, .modal .pure-u-md-8-24 {
44 | width: 50%; }
45 | .modal .pure-u-lg-1-3, .modal .pure-u-lg-8-24 {
46 | width: 50%; }
47 | }
48 |
49 | @media screen and (max-width: 48em) {
50 | .modal {
51 | width: auto !important; }
52 | form .field {
53 | margin: 0.5em auto !important;
54 | padding-right: 0 !important; }
55 | }
56 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/modal.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | var g;
4 |
5 | g = this;
6 |
7 | this.current_modal_click_button_value = null;
8 |
9 | this.current_modal_click_button_value2 = null;
10 |
11 | this.current_modal_click_button_value3 = null;
12 |
13 | $(document).ready(function() {
14 | $(document).on('modal:close', function(event, modal) {
15 | try {
16 | return Essage.hide();
17 | } catch (_error) {}
18 | });
19 | return $('input.modal_with_selector').each(function(i, dom) {
20 | var click_dom, modal_dom;
21 | dom = $(dom);
22 | modal_dom = $(dom.attr('data-modal-dom'));
23 | click_dom = $(dom.attr('data-click-dom'));
24 | return click_dom.click(function() {
25 | var current_click_dom;
26 | modal_dom.modal();
27 | current_click_dom = $(this);
28 | g.current_modal_click_button_value = current_click_dom.attr('data-value');
29 | g.current_modal_click_button_value2 = current_click_dom.attr('data-value2');
30 | g.current_modal_click_button_value3 = current_click_dom.attr('data-value3');
31 | if (typeof after_modal_display !== "undefined" && after_modal_display !== null) {
32 | try {
33 | after_modal_display(current_click_dom, modal_dom);
34 | } catch (_error) {}
35 | }
36 | return false;
37 | });
38 | });
39 | });
40 |
41 | }).call(this);
42 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/modal.scss:
--------------------------------------------------------------------------------
1 | .modal_wrap{
2 | width: 70%;
3 | }
4 | .modal_container{
5 | max-height: 550px;
6 | overflow-y: auto;
7 | overflow-x: hidden;
8 | color: #333;
9 | font-size: 14px;
10 | }
11 |
12 |
13 | .modal_wrap{
14 | ::-webkit-scrollbar {
15 | width:4px;
16 | margin:0 1px;
17 | background: #fdfdfd;
18 | }
19 | ::-webkit-scrollbar:horizontal{
20 | height: 4px;
21 | }
22 |
23 | ::-webkit-scrollbar-button{
24 | height: 0;
25 | }
26 |
27 | ::-webkit-scrollbar-track {
28 | border-radius: 2px;
29 | }
30 | ::-webkit-scrollbar-track-piece {
31 | background-color: #fdfdfd;
32 | border-radius: 2px;
33 | }
34 | ::-webkit-scrollbar-thumb {
35 | width:8px;
36 | margin: 0 1px;
37 | border-radius: 2px;
38 | background: #c4c4c4;
39 | }
40 | ::-webkit-scrollbar-thumb:hover {
41 | background: #909090;
42 | }
43 | }
44 |
45 |
46 | .modal{
47 | font-size: 14px;
48 |
49 |
50 |
51 | form{
52 | color: #555;
53 | h2{
54 | color: #111;
55 | margin-top: 1em !important;
56 | }
57 |
58 | .fields .field {
59 | margin: 0.8em auto 1.2em auto !important;
60 | }
61 | }
62 | }
63 |
64 |
65 | @media screen and (min-width: 48em){
66 | .modal{
67 | .pure-u-md-1-3, .pure-u-md-8-24 {
68 | width: 50%;
69 | }
70 | .pure-u-lg-1-3, .pure-u-lg-8-24{
71 | width: 50%;
72 | }
73 | }
74 | }
75 |
76 | @media screen and (max-width: 48em){
77 | .modal{
78 | width: auto !important;
79 | }
80 | form .field {
81 | margin: 0.5em auto !important;
82 | padding-right: 0 !important;
83 | }
84 |
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/page/load_pages.coffee:
--------------------------------------------------------------------------------
1 | on_page_loading = false
2 | finish_page_loading = false
3 | next_page_number = 2
4 |
5 | load_next_page = (container_id, loading_id, callback)=>
6 | container_dom_id = '#' + container_id
7 | loading_dom_id = '#' + loading_id
8 | on_page_loading = true
9 | $(loading_dom_id).css('display', 'block')
10 | url = location.pathname+'/page/'+next_page_number+location.search
11 | url = url.replace(/\/{2,}/g, '/')
12 |
13 | if auto_load_page_callback? and not callback
14 | callback = auto_load_page_callback
15 |
16 | $.get url, {pjax: true}, (data)->
17 | $(loading_dom_id).css('display', 'none')
18 | if data.length < 20
19 | finish_page_loading = true
20 | else
21 | try
22 | $(container_dom_id).append(data)
23 | next_page_number += 1
24 | on_page_loading = false
25 | if callback
26 | callback()
27 |
28 | auto_load_pages = (container_id, loading_id, callback)->
29 | bottom_diff = $(document).height() - $(window).height() - $(window).scrollTop()
30 | if bottom_diff < 80 and not on_page_loading and not finish_page_loading and location.search.indexOf('?s=') == -1
31 | load_next_page(container_id, loading_id, callback)
32 |
33 | load_more = ->
34 | if auto_load_page_container_id?
35 | dom_id = auto_load_page_container_id or 'list_container'
36 | else
37 | dom_id = 'list_container'
38 | auto_load_pages(dom_id, 'on_loading')
39 |
40 | $(document).ready ->
41 | $(window).scroll(load_more)
42 | load_more()
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/slider/slider.coffee:
--------------------------------------------------------------------------------
1 | @install_sliders = ->
2 | $('.bitcron_slider').each ->
3 | slider_dom = $(this)
4 | autoplay = if slider_dom.attr('data-autoplay')=='true' then true else false
5 | show_arrows = if slider_dom.attr('data-show-arrows')=='true' then true else false
6 | animation = slider_dom.attr('data-animation') or 'horizontal'
7 | unslider_configs = {autoplay:autoplay, arrows:show_arrows, animation:animation}
8 | slider_dom.unslider(unslider_configs)
9 |
10 | $(document).ready ->
11 | install_sliders()
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/slider/slider.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | this.install_sliders = function() {
4 | return $('.bitcron_slider').each(function() {
5 | var animation, autoplay, show_arrows, slider_dom, unslider_configs;
6 | slider_dom = $(this);
7 | autoplay = slider_dom.attr('data-autoplay') === 'true' ? true : false;
8 | show_arrows = slider_dom.attr('data-show-arrows') === 'true' ? true : false;
9 | animation = slider_dom.attr('data-animation') || 'horizontal';
10 | unslider_configs = {
11 | autoplay: autoplay,
12 | arrows: show_arrows,
13 | animation: animation
14 | };
15 | return slider_dom.unslider(unslider_configs);
16 | });
17 | };
18 |
19 | $(document).ready(function() {
20 | return install_sliders();
21 | });
22 |
23 | }).call(this);
24 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/tab.css:
--------------------------------------------------------------------------------
1 | .tabs_set{margin-top: 50px;}
2 | .tabs_set a {
3 | text-decoration: none; }
4 | .tabs_set .tab_item {
5 | display: none; }
6 | .tabs_set .tab_item:first-child {
7 | display: block; }
8 | .tabs_set ul.horizontal {
9 | list-style: none;
10 | text-align: center;
11 | margin-top: 0;
12 | padding: 0 0 0 0;
13 | border-bottom: 1px solid #eee;
14 | line-height: 25px; }
15 | .tabs_set ul.horizontal li {
16 | display: inline;
17 | margin: 0 10px; }
18 | .tabs_set ul.horizontal li a {
19 | font-size: 14px;
20 | padding: 5px 10px;
21 | color: #666;
22 | bottom: 1px;
23 | position: relative;
24 | border: 1px solid #eee;
25 | }
26 | .tabs_set ul.horizontal li.active a, .tabs_set ul.horizontal li a:hover {
27 | color: #4296DB; border-bottom: 2px solid white;}
28 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/api/syntax/tab.scss:
--------------------------------------------------------------------------------
1 | $high_color: #e7645c;
2 | $high_color2: #4296DB;
3 |
4 |
5 | .tabs_set{
6 | margin-top: 50px;
7 | a{
8 | text-decoration: none;
9 | }
10 |
11 | .tab_item{
12 | display: none;
13 | }
14 |
15 | .tab_item:first-child{
16 | display: block;
17 | }
18 |
19 | ul.horizontal{
20 | list-style: none;
21 | text-align: center;
22 | margin-top: 0;
23 | padding: 0 0 0 0;
24 | border-bottom: 1px solid #eee;
25 | line-height: 25px;
26 |
27 | li{
28 | display: inline;
29 | margin: 0 10px;
30 |
31 | a{
32 | font-size: 14px;
33 | padding: 5px 10px;
34 | color: #666;
35 | bottom: 1px;
36 | position: relative;
37 | border: 1px solid #eee;
38 | }
39 |
40 | &.active a, a:hover{
41 | color: $high_color2;
42 | border-bottom: 2px solid white;
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/basic/footer.css:
--------------------------------------------------------------------------------
1 | .site_footer_wrap .site_footer {
2 | clear: both;
3 | margin: 50px 0 15px 0;
4 | padding-top: 15px;
5 | border-top: 1px solid #eee;
6 | text-align: center;
7 | color: #999;
8 | font-size: 12px;
9 | font-family: "Hiragino Sans GB", "STHeiti", "Microsoft YaHei", "WenQuanYi Micro Hei",
10 | SimSun, sans-serif; }
11 | .site_footer_wrap .site_footer a {
12 | font-size: 12px;
13 | margin: 0 12px;
14 | color: #999; }
15 | .site_footer_wrap .site_footer a:hover {
16 | color: #333;
17 | border-bottom: 1px dashed #ccc; }
18 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/basic/footer.scss:
--------------------------------------------------------------------------------
1 | .site_footer_wrap{
2 | .site_footer{
3 | clear: both;
4 | margin: 50px 0 15px 0;
5 | padding-top: 15px;
6 | border-top: 1px solid #eee;
7 | text-align: center;
8 |
9 | color: #999;
10 | font-size: 12px;
11 | font-family: "Hiragino Sans GB", "STHeiti", "Microsoft YaHei", "WenQuanYi Micro Hei", SimSun, sans-serif;
12 |
13 | a{
14 | font-size: 12px;
15 | margin: 0 12px;
16 | color: #999;
17 | &:hover{
18 | color: #333;
19 | border-bottom: 1px dashed #ccc;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/basic/post_preview.css:
--------------------------------------------------------------------------------
1 | .post_preview {
2 | position: relative;
3 | display: flex;
4 | background: #fff;
5 | border-radius: 2px;
6 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
7 | margin-bottom: 15px;
8 | }
9 | .post_preview .post_preview__meta {
10 | width: 100%;
11 | padding: 25px;
12 | }
13 | .post_preview .post_preview__meta .post-preview__middle {
14 | position: relative;
15 | top: 50%;
16 | transform: translateY(-50%);
17 | }
18 | .post_preview .post_preview__meta .post_preview__title {
19 | font-size: 16px;
20 | margin: 0 0 10px 0;
21 | }
22 | .post_preview .post_preview__meta .post_preview__title a {
23 | text-decoration: none;
24 | }
25 | .post_preview .post_preview__meta .post_preview__date {
26 | font-size: 14px;
27 | color: #999;
28 | margin: 0 0 8px 0;
29 | display: block;
30 | }
31 | .post_preview .post_preview__meta.with_bg {
32 | width: 75%;
33 | }
34 | .post_preview .post_preview__summary {
35 | font-size: 14px;
36 | line-height: 1.825;
37 | }
38 | .post_preview .post_preview__summary p {
39 | margin-bottom: 0;
40 | }
41 | .post_preview .post_preview__image {
42 | width: 25%;
43 | float: right;
44 | background-size: cover;
45 | background-position: center center;
46 | border-top-right-radius: 2px;
47 | border-bottom-right-radius: 2px;
48 | }
49 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/basic/post_preview.scss:
--------------------------------------------------------------------------------
1 | .post_preview {
2 | position: relative;
3 | display: flex;
4 | background: #fff;
5 | border-radius: 2px;
6 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
7 | margin-bottom: 15px;
8 |
9 | .post_preview__meta {
10 | width: 100%;
11 | padding: 25px;
12 |
13 | .post-preview__middle {
14 | position: relative;
15 | top: 50%;
16 | transform: translateY(-50%);
17 | }
18 |
19 | .post_preview__title {
20 | font-size: 16px;
21 | margin: 0 0 10px 0;
22 | a {
23 | text-decoration: none;
24 | }
25 | }
26 |
27 | .post_preview__date {
28 | font-size: 14px;
29 | color: #999;
30 | margin: 0 0 8px 0;
31 | display: block;
32 | }
33 |
34 | &.with_bg{
35 | width: 75%;
36 | }
37 | }
38 |
39 | .post_preview__summary {
40 | font-size: 14px;
41 | line-height: 1.825;
42 | p{
43 | margin-bottom: 0;
44 | }
45 | }
46 |
47 | .post_preview__image {
48 | width: 25%;
49 | float: right;
50 | background-size: cover;
51 | background-position: center center;
52 | border-top-right-radius: 2px;
53 | border-bottom-right-radius: 2px;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/builtin_themes/waterfall/script.coffee:
--------------------------------------------------------------------------------
1 |
2 |
3 | waterfall = new Waterfall({
4 | containerSelector: '#waterfall',
5 | boxSelector: '.item',
6 | minBoxWidth: 250
7 | })
8 |
9 | @auto_load_page_callback = ->
10 | new_items = $('#waterfall > .item')
11 | for item in new_items
12 | waterfall.addBox(item)
--------------------------------------------------------------------------------
/farbox_bucket/server/static/builtin_themes/waterfall/script.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | var waterfall;
4 |
5 | waterfall = new Waterfall({
6 | containerSelector: '#waterfall',
7 | boxSelector: '.item',
8 | minBoxWidth: 250
9 | });
10 |
11 | this.auto_load_page_callback = function() {
12 | var item, new_items, _i, _len, _results;
13 | new_items = $('#waterfall > .item');
14 | _results = [];
15 | for (_i = 0, _len = new_items.length; _i < _len; _i++) {
16 | item = new_items[_i];
17 | _results.push(waterfall.addBox(item));
18 | }
19 | return _results;
20 | };
21 |
22 | }).call(this);
23 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_asc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_asc.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_asc_disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_asc_disabled.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_both.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_both.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_desc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_desc.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_desc_disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/datatables/DataTables-1.10.20/images/sort_desc_disabled.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/defaults/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/defaults/admin.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/defaults/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/defaults/avatar.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/defaults/drop_image_here.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/defaults/drop_image_here.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/defaults/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/defaults/favicon.ico
--------------------------------------------------------------------------------
/farbox_bucket/server/static/defaults/site_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/defaults/site_avatar.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/defaults/visitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/defaults/visitor.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/donate/alipay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/donate/alipay.jpg
--------------------------------------------------------------------------------
/farbox_bucket/server/static/donate/wechat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/donate/wechat.jpg
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/Josefin+Sans_400_normal.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/Josefin+Sans_400_normal.ttf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/Josefin+Sans_400_normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/Josefin+Sans_400_normal.woff
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/Julius+Sans+One_400_normal.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/Julius+Sans+One_400_normal.ttf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/Julius+Sans+One_400_normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/Julius+Sans+One_400_normal.woff
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/Lato_400_normal.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/Lato_400_normal.ttf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/Lato_400_normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/Lato_400_normal.woff
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.eot
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.ttf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.woff
--------------------------------------------------------------------------------
/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/gfonts/calligraffitti-regular-webfont.woff2
--------------------------------------------------------------------------------
/farbox_bucket/server/static/images/border1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/images/border1.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/images/border2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/images/border2.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/images/loading.gif
--------------------------------------------------------------------------------
/farbox_bucket/server/static/images/readme.txt:
--------------------------------------------------------------------------------
1 | for color box mainly
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/essage/essage.css:
--------------------------------------------------------------------------------
1 | /* Essage - a more elegant way to show message
2 | * https://github.com/sofish/Essage
3 | */
4 | .essage{font-size:16px;position:fixed;_position:absolute;z-index:100010;background:#fff;background:rgba(255,255,255,0.9);color:#666;text-align:center;line-height:1.8;padding:10px 20px;*padding:10px 0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;top:9999em;left:0;width:100%;border-bottom:1px solid #ddd;border-top:1px solid #ddd;}
5 | .essage-success{background:#eafbe3;background:rgba(221, 242, 210, 0.9);border-bottom-color:#bfd5a9;border-top-color:#bfd5a9;color:#3fb16f;}
6 | .essage-error{background:#f2e1e4;background:rgba(242, 225, 228, 0.9);border-bottom-color:#e0cdcd;border-top-color:#e0cdcd;color:#dc584b;}
7 | .essage-warning{background:#fcf8e3;background:rgba(252, 248, 227, 0.9);border-bottom-color:#fbeed5;border-top-color:#fbeed5;color:#c09853;}
8 | .essage .close{font:400 normal 22px/1.3 arial, sans-serif;float:right;*margin-right:15px;display:inline;color:#e74c3c;opacity:0.6;cursor:pointer;}
9 | .essage .close:hover{opacity:1;}
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fontawesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fontawesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fontawesome/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fonts/merriweather.css:
--------------------------------------------------------------------------------
1 | /* cyrillic-ext */
2 | @font-face {
3 | font-family: 'Merriweather';
4 | font-style: normal;
5 | font-weight: 300;
6 | src: local('Merriweather Light'), local('Merriweather-Light'), url(merriweather/1.woff2) format('woff2');
7 | unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
8 | }
9 | /* cyrillic */
10 | @font-face {
11 | font-family: 'Merriweather';
12 | font-style: normal;
13 | font-weight: 300;
14 | src: local('Merriweather Light'), local('Merriweather-Light'), url(merriweather/2.woff2) format('woff2');
15 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
16 | }
17 | /* latin-ext */
18 | @font-face {
19 | font-family: 'Merriweather';
20 | font-style: normal;
21 | font-weight: 300;
22 | src: local('Merriweather Light'), local('Merriweather-Light'), url(merriweather/3.woff2) format('woff2');
23 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
24 | }
25 | /* latin */
26 | @font-face {
27 | font-family: 'Merriweather';
28 | font-style: normal;
29 | font-weight: 300;
30 | src: local('Merriweather Light'), local('Merriweather-Light'), url(merriweather/4.woff2) format('woff2');
31 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
32 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fonts/merriweather/1.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fonts/merriweather/1.woff2
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fonts/merriweather/2.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fonts/merriweather/2.woff2
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fonts/merriweather/3.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fonts/merriweather/3.woff2
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/fonts/merriweather/4.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/fonts/merriweather/4.woff2
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/jquery-linedtextarea.css:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery Lined Textarea Plugin
3 | * http://alan.blog-city.com/jquerylinedtextarea.htm
4 | *
5 | * Copyright (c) 2010 Alan Williamson
6 | *
7 | * Released under the MIT License:
8 | * http://www.opensource.org/licenses/mit-license.php
9 | *
10 | * Usage:
11 | * Displays a line number count column to the left of the textarea
12 | *
13 | * Class up your textarea with a given class, or target it directly
14 | * with JQuery Selectors
15 | *
16 | * $(".lined").linedtextarea({
17 | * selectedLine: 10,
18 | * selectedClass: 'lineselect'
19 | * });
20 | *
21 | */
22 |
23 | .linedwrap {
24 | border: 1px solid #c0c0c0;
25 | padding: 3px;
26 | }
27 |
28 | .linedtextarea {
29 | padding: 0px;
30 | margin: 0px;
31 | }
32 |
33 | .linedtextarea textarea, .linedwrap .codelines .lineno {
34 | font-size: 10pt;
35 | font-family: monospace;
36 | line-height: normal !important;
37 | }
38 |
39 | .linedtextarea textarea {
40 | padding-right:0.3em;
41 | padding-top:0.3em;
42 | border: 0;
43 | }
44 |
45 | .linedwrap .lines {
46 | margin-top: 0px;
47 | width: 50px;
48 | float: left;
49 | overflow: hidden;
50 | border-right: 1px solid #c0c0c0;
51 | margin-right: 10px;
52 | }
53 |
54 | .linedwrap .codelines {
55 | padding-top: 5px;
56 | }
57 |
58 | .linedwrap .codelines .lineno {
59 | color:#AAAAAA;
60 | padding-right: 0.5em;
61 | padding-top: 0.0em;
62 | text-align: right;
63 | white-space: nowrap;
64 | }
65 |
66 | .linedwrap .codelines .lineselect {
67 | color: red;
68 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/jstree/themes/default-dark/32px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/jstree/themes/default-dark/32px.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/jstree/themes/default-dark/40px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/jstree/themes/default-dark/40px.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/jstree/themes/default-dark/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/jstree/themes/default-dark/throbber.gif
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/jstree/themes/default/32px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/jstree/themes/default/32px.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/jstree/themes/default/40px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/jstree/themes/default/40px.png
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/jstree/themes/default/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/jstree/themes/default/throbber.gif
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/markdown_js/mindmap/d3_LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2010-2017 Mike Bostock
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of the author nor the names of contributors may be used to
15 | endorse or promote products derived from this software without specific prior
16 | written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/markdown_js/mindmap/markmap_LICENSE.txt:
--------------------------------------------------------------------------------
1 | https://github.com/dundalek/markmap
2 |
3 | Copyright 2015 Jakub Dundalek
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/markdown_js/mindmap/readme.txt:
--------------------------------------------------------------------------------
1 | https://github.com/dundalek/markmap
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/markdown_js/mindmap/view.mindmap.css:
--------------------------------------------------------------------------------
1 | html {
2 | margin: 0;
3 | padding: 0;
4 | height: 100%;
5 | }
6 |
7 | body {
8 | position: absolute;
9 | top: 0;
10 | bottom: 0;
11 | right: 0;
12 | left: 0;
13 | }
14 |
15 | .mindmap_container{
16 | margin: 0 auto;
17 | }
18 |
19 | svg#mindmap {
20 | width: 100%;
21 | height: 100%;
22 |
23 | display: block;
24 | margin: 0 auto;
25 | padding: 20px;
26 | }
27 | .markmap-node {
28 | cursor: pointer;
29 | }
30 |
31 | .markmap-node-circle {
32 | fill: #fff;
33 | stroke-width: 1.5px;
34 | }
35 |
36 | .markmap-node-text {
37 | fill: #333;
38 | font: 16px sans-serif;
39 | }
40 |
41 | .markmap-link {
42 | fill: none;
43 | }
44 |
45 |
46 |
47 |
48 | .d3-tip {
49 | line-height: 1.35;
50 | font-weight: bold;
51 | padding: 12px;
52 | background: rgba(247, 245, 233, 0.9);
53 | color: #eee;
54 | min-width: 300px;
55 | max-width: 600px;
56 | border-radius: 8px;
57 | border: 1px solid #dfdfdf;
58 | }
59 |
60 | .d3_tip_header{
61 | font-weight: bold;
62 | color: indianred;
63 | font-size: 14px;
64 | }
65 |
66 | /* Creates a small triangle extender for the tooltip */
67 | .d3-tip:after {
68 | box-sizing: border-box;
69 | display: inline;
70 | font-size: 10px;
71 | width: 100%;
72 | line-height: 10px;
73 | color: rgba(0, 0, 0, 0.8);
74 | content: "\25BC";
75 | position: absolute;
76 | text-align: center;
77 | }
78 |
79 | /* Style northward tooltips differently */
80 | .d3-tip.n:after {
81 | margin: -1px 0 0 0;
82 | top: 100%;
83 | left: 0;
84 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/menu/smartmenu/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) Vasil Dinkov, Vadikom Web Ltd.
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/menu/smartmenu/css/sm-core-css.css:
--------------------------------------------------------------------------------
1 | /* Mobile first layout SmartMenus Core CSS (it's not recommended editing these rules)
2 | You need this once per page no matter how many menu trees or different themes you use.
3 | -------------------------------------------------------------------------------------------*/
4 |
5 | .sm{position:relative;z-index:9999;}
6 | .sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0);}
7 | .sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right;}
8 | .sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0;}
9 | .sm ul{display:none;}
10 | .sm li,.sm a{position:relative;}
11 | .sm a{display:block;}
12 | .sm a.disabled{cursor:not-allowed;}
13 | .sm:after{content:"\00a0";display:block;height:0;font:0px/0 serif;clear:both;visibility:hidden;overflow:hidden;}
14 | .sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;}
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/pure_patch.css:
--------------------------------------------------------------------------------
1 | @media screen and (max-width: 35.5em) {
2 | .pure-u-0-24 {
3 | display: none; }
4 | }
5 |
6 | @media screen and (max-width: 48em) {
7 | .pure-u-sm-0-24 {
8 | display: none; }
9 | }
10 |
11 | @media screen and (max-width: 64em) {
12 | .pure-u-md-0-24 {
13 | display: none; }
14 | }
15 |
16 | @media screen and (max-width: 80em) {
17 | .pure-u-lg-0-24 {
18 | display: none; }
19 | }
20 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/pure_patch.scss:
--------------------------------------------------------------------------------
1 | // sm
2 | @media screen and (max-width: 35.5em){
3 | .pure-u-0-24{
4 | display: none;
5 | }
6 | }
7 |
8 | // md
9 | @media screen and (max-width: 48em){
10 | .pure-u-sm-0-24{
11 | display: none;
12 | }
13 | }
14 |
15 | // lg
16 | @media screen and (max-width: 64em){
17 | .pure-u-md-0-24{
18 | display: none;
19 | }
20 | }
21 |
22 |
23 | // xl
24 | @media screen and (max-width: 80em){
25 | .pure-u-lg-0-24{
26 | display: none;
27 | }
28 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/unslider/css/unslider-dots.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Here's where everything gets included. You don't need
3 | * to change anything here, and doing so might break
4 | * stuff. Here be dragons and all that.
5 | */
6 | /**
7 | * Default variables
8 | *
9 | * While these can be set with JavaScript, it's probably
10 | * better and faster to just set them here, compile to
11 | * CSS and include that instead to use some of that
12 | * hardware-accelerated goodness.
13 | */
14 | .unslider-nav ol {
15 | list-style: none;
16 | text-align: center;
17 | }
18 | .unslider-nav ol li {
19 | display: inline-block;
20 | width: 6px;
21 | height: 6px;
22 | margin: 0 4px;
23 | background: transparent;
24 | border-radius: 5px;
25 | overflow: hidden;
26 | text-indent: -999em;
27 | border: 2px solid #fff;
28 | cursor: pointer;
29 | }
30 | .unslider-nav ol li.unslider-active {
31 | background: #fff;
32 | cursor: default;
33 | }
34 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/unslider/css/unslider.css:
--------------------------------------------------------------------------------
1 | .unslider {
2 | overflow: auto;
3 | margin: 0;
4 | padding: 0
5 | }
6 |
7 | .unslider-wrap {
8 | position: relative
9 | }
10 |
11 | .unslider-wrap.unslider-carousel > li {
12 | float: left
13 | }
14 |
15 | .unslider-vertical > ul {
16 | height: 100%
17 | }
18 |
19 | .unslider-vertical li {
20 | float: none;
21 | width: 100%
22 | }
23 |
24 | .unslider-fade {
25 | position: relative
26 | }
27 |
28 | .unslider-fade .unslider-wrap li {
29 | position: absolute;
30 | left: 0;
31 | top: 0;
32 | right: 0;
33 | z-index: 8
34 | }
35 |
36 | .unslider-fade .unslider-wrap li.unslider-active {
37 | z-index: 10
38 | }
39 |
40 | .unslider li, .unslider ol, .unslider ul {
41 | list-style: none;
42 | margin: 0;
43 | padding: 0;
44 | border: none
45 | }
46 |
47 | .unslider-arrow {
48 | position: absolute;
49 | left: 10px;
50 | z-index: 2;
51 | cursor: pointer
52 | }
53 |
54 | .unslider-arrow.next {
55 | left: auto;
56 | right: 10px
57 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/video-js/font/VideoJS.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/video-js/font/VideoJS.eot
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/video-js/font/VideoJS.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/video-js/font/VideoJS.ttf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/video-js/font/VideoJS.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/video-js/font/VideoJS.woff
--------------------------------------------------------------------------------
/farbox_bucket/server/static/lib/video-js/video-js.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/lib/video-js/video-js.swf
--------------------------------------------------------------------------------
/farbox_bucket/server/static/nav/menu/smartmenu/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) Vasil Dinkov, Vadikom Web Ltd.
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/nav/menu/smartmenu/css/sm-core-css.css:
--------------------------------------------------------------------------------
1 | /* Mobile first layout SmartMenus Core CSS (it's not recommended editing these rules)
2 | You need this once per page no matter how many menu trees or different themes you use.
3 | -------------------------------------------------------------------------------------------*/
4 |
5 | .sm{position:relative;z-index:9999;}
6 | .sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0);}
7 | .sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right;}
8 | .sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0;}
9 | .sm ul{display:none;}
10 | .sm li,.sm a{position:relative;}
11 | .sm a{display:block;}
12 | .sm a.disabled{cursor:not-allowed;}
13 | .sm:after{content:"\00a0";display:block;height:0;font:0px/0 serif;clear:both;visibility:hidden;overflow:hidden;}
14 | .sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;}
--------------------------------------------------------------------------------
/farbox_bucket/server/static/nav/run_menu.coffee:
--------------------------------------------------------------------------------
1 | @run_menu = =>
2 | $('.farbox_nav .sm').smartmenus
3 | markCurrentItem: true,
4 | subMenusSubOffsetX: 1,
5 | subMenusSubOffsetY: -8
6 |
7 | $('.farbox_nav').each ->
8 | nav_dom = $(this)
9 | pre_dom = nav_dom.prev()
10 | if not pre_dom.hasClass('menu_toggle')
11 | return false
12 | menu = pre_dom.find('.menu_state')
13 | if menu.length
14 | menu.change (e)->
15 | if this.checked
16 | nav_dom.hide().slideDown 250, ->
17 | nav_dom.css('display', 'block')
18 | nav_dom.find('.site_nav_wrap').css('padding-right', '40px')
19 | else
20 | nav_dom.show().slideUp 250, ->
21 | nav_dom.css('display', '')
22 | nav_dom.find('.site_nav_wrap').css('padding-right', '0')
23 |
24 |
25 | $(document).ready ->
26 | try run_menu()
27 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/nav/run_menu.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | this.run_menu = (function(_this) {
4 | return function() {
5 | $('.farbox_nav .sm').smartmenus({
6 | markCurrentItem: true,
7 | subMenusSubOffsetX: 1,
8 | subMenusSubOffsetY: -8
9 | });
10 | return $('.farbox_nav').each(function() {
11 | var menu, nav_dom, pre_dom;
12 | nav_dom = $(this);
13 | pre_dom = nav_dom.prev();
14 | if (!pre_dom.hasClass('menu_toggle')) {
15 | return false;
16 | }
17 | menu = pre_dom.find('.menu_state');
18 | if (menu.length) {
19 | return menu.change(function(e) {
20 | if (this.checked) {
21 | nav_dom.hide().slideDown(250, function() {
22 | return nav_dom.css('display', 'block');
23 | });
24 | return nav_dom.find('.site_nav_wrap').css('padding-right', '40px');
25 | } else {
26 | nav_dom.show().slideUp(250, function() {
27 | return nav_dom.css('display', '');
28 | });
29 | return nav_dom.find('.site_nav_wrap').css('padding-right', '0');
30 | }
31 | });
32 | }
33 | });
34 | };
35 | })(this);
36 |
37 | $(document).ready(function() {
38 | try {
39 | return run_menu();
40 | } catch (_error) {}
41 | });
42 |
43 | }).call(this);
44 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/nav/sm-core-css.css:
--------------------------------------------------------------------------------
1 | /* Mobile first layout SmartMenus Core CSS (it's not recommended editing these rules)
2 | You need this once per page no matter how many menu trees or different themes you use.
3 | -------------------------------------------------------------------------------------------*/
4 |
5 | .sm{position:relative;z-index:9999;}
6 | .sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0);}
7 | .sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right;}
8 | .sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0;}
9 | .sm ul{display:none;}
10 | .sm li,.sm a{position:relative;}
11 | .sm a{display:block;}
12 | .sm a.disabled{cursor:not-allowed;}
13 | .sm:after{content:"\00a0";display:block;height:0;font:0px/0 serif;clear:both;visibility:hidden;overflow:hidden;}
14 | .sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;}
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/code_editor/editor.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 12px;
3 | width: 100%;
4 | overflow: hidden;
5 | background: #fbfbfb; }
6 |
7 | #editor .CodeMirror {
8 | position: absolute;
9 | right: 0;
10 | top: 0;
11 | z-index: 9;
12 | padding: 0;
13 | height: 100%;
14 | width: 100%;
15 | font-family: Verdana, Arial, sans-serif;
16 | font-size: 14px;
17 | line-height: 2.1em;
18 | border: none; }
19 |
20 | #save_button {
21 | position: fixed;
22 | top: 6px;
23 | right: 2px;
24 | z-index: 10000; }
25 | #save_button a {
26 | text-decoration: none;
27 | padding: 5px 20px;
28 | background: #b4b4b4;
29 | border-radius: 2px;
30 | color: #fff; }
31 | #save_button a:hover {
32 | background: #d42128; }
33 | #save_button .precess {
34 | position: absolute;
35 | left: 0;
36 | bottom: -5px;
37 | background: #d42128;
38 | height: 2px; }
39 |
40 | .cm-s-solarized .CodeMirror-gutters {
41 | border-right: 1px solid #ddd !important;
42 | background: #fdfdfd !important; }
43 |
44 | .cm-s-solarized .cm-strong {
45 | color: indianred !important; }
46 |
47 | .CodeMirror-linenumber {
48 | text-align: center !important; }
49 |
50 | .CodeMirror-cursor {
51 | border-left: 2px solid #16b0ff !important;
52 | z-index: 3; }
53 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/code_editor/editor.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 12px;
3 | width: 100%;
4 | overflow: hidden;
5 | background: #fbfbfb;
6 | }
7 |
8 |
9 | #editor {
10 |
11 | .CodeMirror{
12 | position: absolute;
13 | right: 0;
14 | top: 0;
15 | z-index: 9;
16 | padding: 0;
17 | height: 100%;
18 | width: 100%;
19 | font-family: Verdana, Arial, sans-serif;
20 | font-size: 14px;
21 | line-height: 2.1em;
22 | border: none;
23 |
24 |
25 | }
26 | }
27 |
28 |
29 | #save_button{
30 | position: fixed;
31 | top: 6px;
32 | right: 2px;
33 | z-index: 10000;
34 |
35 | a{
36 | text-decoration: none;
37 | padding: 5px 20px;
38 | background: #b4b4b4;
39 | border-radius: 2px;
40 | color: #fff;
41 |
42 | &:hover{
43 | background: #d42128;
44 | }
45 | }
46 |
47 | .precess{
48 | position: absolute;
49 | left: 0;
50 | bottom: -5px;
51 | background: #d42128;
52 | height: 2px;
53 |
54 | }
55 | }
56 |
57 |
58 |
59 |
60 | .cm-s-solarized .CodeMirror-gutters{
61 | border-right: 1px solid #ddd !important;
62 | background: #fdfdfd !important;
63 | }
64 |
65 | .cm-s-solarized .cm-strong {
66 | color: indianred !important;
67 | }
68 |
69 | .CodeMirror-linenumber{
70 | text-align: center !important;
71 | }
72 |
73 | /* CURSOR */
74 |
75 | .CodeMirror-cursor {
76 | border-left: 2px solid #16b0ff !important;
77 | z-index: 3;
78 | }
79 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/default_homepage/markdown@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/pages/default_homepage/markdown@2x.jpg
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/site/menu/run.coffee:
--------------------------------------------------------------------------------
1 | @run_menu = =>
2 | $('.bitcron_nav .sm').smartmenus
3 | markCurrentItem: true,
4 | subMenusSubOffsetX: 1,
5 | subMenusSubOffsetY: -8
6 |
7 | $('.bitcron_nav').each ->
8 | nav_dom = $(this)
9 | pre_dom = nav_dom.prev()
10 | if not pre_dom.hasClass('menu_toggle')
11 | return false
12 | menu = pre_dom.find('.menu_state')
13 | if menu.length
14 | menu.change (e)->
15 | if this.checked
16 | nav_dom.hide().slideDown 250, ->
17 | nav_dom.css('display', 'block')
18 | nav_dom.find('.site_nav_wrap').css('padding-right', '40px')
19 | else
20 | nav_dom.show().slideUp 250, ->
21 | nav_dom.css('display', '')
22 | nav_dom.find('.site_nav_wrap').css('padding-right', '0')
23 |
24 |
25 | $(document).ready ->
26 | try run_menu()
27 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/site/menu/run.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | this.run_menu = (function(_this) {
4 | return function() {
5 | $('.bitcron_nav .sm').smartmenus({
6 | markCurrentItem: true,
7 | subMenusSubOffsetX: 1,
8 | subMenusSubOffsetY: -8
9 | });
10 | return $('.bitcron_nav').each(function() {
11 | var menu, nav_dom, pre_dom;
12 | nav_dom = $(this);
13 | pre_dom = nav_dom.prev();
14 | if (!pre_dom.hasClass('menu_toggle')) {
15 | return false;
16 | }
17 | menu = pre_dom.find('.menu_state');
18 | if (menu.length) {
19 | return menu.change(function(e) {
20 | if (this.checked) {
21 | nav_dom.hide().slideDown(250, function() {
22 | return nav_dom.css('display', 'block');
23 | });
24 | return nav_dom.find('.site_nav_wrap').css('padding-right', '40px');
25 | } else {
26 | nav_dom.show().slideUp(250, function() {
27 | return nav_dom.css('display', '');
28 | });
29 | return nav_dom.find('.site_nav_wrap').css('padding-right', '0');
30 | }
31 | });
32 | }
33 | });
34 | };
35 | })(this);
36 |
37 | $(document).ready(function() {
38 | try {
39 | return run_menu();
40 | } catch (_error) {}
41 | });
42 |
43 | }).call(this);
44 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/table.css:
--------------------------------------------------------------------------------
1 | table {
2 | -moz-box-sizing: border-box;
3 | box-sizing: border-box;
4 | margin: 1em 0;
5 | width: 100%;
6 | max-width: 100%;
7 | border-width: 1px;
8 | border-style: solid;
9 | background-color: transparent; }
10 | table img {
11 | max-width: 100%; }
12 |
13 | table, table tr, table tr td, table tr th {
14 | border-color: #e5e5e5; }
15 |
16 | table th {
17 | color: #666666;
18 | background-color: #fdfdfd; }
19 |
20 | tr th {
21 | border-bottom-width: 1px;
22 | border-bottom-style: solid;
23 | text-align: left; }
24 |
25 | tr th, tr td {
26 | padding: 5px 20px;
27 | border-right: 1px solid;
28 | font-size: 1rem; }
29 |
30 | tr th:last-child, tr td:last-child {
31 | border-right: 0px; }
32 |
33 | table th {
34 | font-weight: bold;
35 | font-size: 85%;
36 | color: #000; }
37 |
38 | table tbody > tr:nth-child(odd) > td, table tbody > tr:nth-child(odd) > th {
39 | background-color: #f9f9f9; }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/table.scss:
--------------------------------------------------------------------------------
1 |
2 | table {
3 | -moz-box-sizing: border-box;
4 | box-sizing: border-box;
5 | margin: 1em 0;
6 | width: 100%;
7 | max-width: 100%;
8 | border-width: 1px; border-style: solid;
9 | background-color: transparent;
10 |
11 | img{
12 | max-width: 100%;
13 | }
14 | }
15 |
16 | table, table tr, table tr td, table tr th {
17 | border-color: #e5e5e5;
18 | }
19 |
20 | table th {
21 | color: #666666;
22 | background-color: #fdfdfd;
23 | }
24 |
25 | tr th {
26 | border-bottom-width: 1px;
27 | border-bottom-style: solid;
28 | text-align: left;
29 | }
30 |
31 | tr th, tr td {
32 | padding: 5px 20px;
33 | border-right: 1px solid;
34 | font-size: 1rem;
35 | }
36 |
37 | tr th:last-child, tr td:last-child {
38 | border-right: 0px;
39 | }
40 |
41 | table th {
42 | font-weight: bold;
43 | font-size: 85%;
44 | color: #000;
45 | }
46 |
47 | table tbody > tr:nth-child(odd) > td,
48 | table tbody > tr:nth-child(odd) > th {
49 | background-color: #f9f9f9;
50 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/text_editor/text_editor.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 14px;
3 | font-family: 'Georgia', "Hiragino Sans GB", serif;
4 | width: 100%;
5 | overflow: hidden; }
6 |
7 | #main {
8 | height: 100%; }
9 |
10 | #save_button {
11 | position: fixed;
12 | top: 6px;
13 | right: 2px;
14 | z-index: 10000; }
15 | #save_button a {
16 | text-decoration: none;
17 | padding: 5px 20px;
18 | background: #b4b4b4;
19 | border-radius: 2px;
20 | color: #fff; }
21 | #save_button a:hover {
22 | background: #d42128; }
23 | #save_button .precess {
24 | position: absolute;
25 | left: 0;
26 | bottom: -5px;
27 | background: #d42128;
28 | height: 2px; }
29 |
30 | #editor textarea {
31 | background: #fbfbfb;
32 | position: absolute;
33 | right: 0;
34 | top: 0;
35 | padding-top: 10px;
36 | padding-left: 15px;
37 | padding-right: 15px;
38 | z-index: 9;
39 | height: 100%;
40 | width: 100%;
41 | font-family: "Hiragino Sans GB", "Microsoft Yahei", Verdana, Arial, sans-serif;
42 | font-size: 13pt;
43 | line-height: 1.8em;
44 | resize: none;
45 | outline: none;
46 | display: block;
47 | border: none;
48 | white-space: pre-wrap;
49 | word-wrap: break-word;
50 | box-sizing: border-box; }
51 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/pages/text_editor/text_editor.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 14px;
3 | font-family: 'Georgia', "Hiragino Sans GB", serif;
4 | width: 100%;
5 | overflow: hidden;
6 | }
7 |
8 | #main {
9 | height: 100%;
10 | }
11 |
12 |
13 | #save_button{
14 | position: fixed;
15 | top: 6px;
16 | right: 2px;
17 | z-index: 10000;
18 |
19 | a{
20 | text-decoration: none;
21 | padding: 5px 20px;
22 | background: #b4b4b4;
23 | border-radius: 2px;
24 | color: #fff;
25 |
26 | &:hover{
27 | background: #d42128;
28 | }
29 | }
30 |
31 | .precess{
32 | position: absolute;
33 | left: 0;
34 | bottom: -5px;
35 | background: #d42128;
36 | height: 2px;
37 |
38 | }
39 | }
40 |
41 |
42 |
43 | #editor {
44 | textarea {
45 | background: #fbfbfb;
46 | position: absolute;
47 | right: 0;
48 | top: 0;
49 | padding-top: 10px;
50 | padding-left: 15px;
51 | padding-right: 15px;
52 |
53 | z-index: 9;
54 | height: 100%;
55 | width: 100%;
56 | font-family: "Hiragino Sans GB", "Microsoft Yahei", Verdana, Arial, sans-serif;
57 | font-size: 13pt;
58 | line-height: 1.8em;
59 |
60 | resize: none;
61 | outline: none;
62 | display: block;
63 |
64 | border: none;
65 |
66 | white-space: pre-wrap;
67 | word-wrap: break-word;
68 | box-sizing: border-box;
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/farbox_bucket/server/static/unsplash/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/unsplash/2.jpg
--------------------------------------------------------------------------------
/farbox_bucket/server/static/unsplash/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/unsplash/5.jpg
--------------------------------------------------------------------------------
/farbox_bucket/server/static/unsplash/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/static/unsplash/6.jpg
--------------------------------------------------------------------------------
/farbox_bucket/server/statistics/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/statistics/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/statistics/after_request.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from gevent import spawn
3 | from farbox_bucket.settings import sentry_client
4 | from .post_visits import update_post_visits_for_response
5 | from .usage_collect import update_usage_statistics
6 |
7 | def after_request_func_for_statistics(response):
8 | try:
9 | update_post_visits_for_response(response) # 因为调用了 request/g,不能放在 spawn 中处理
10 | except:
11 | if sentry_client: sentry_client.captureException()
12 |
13 | update_usage_statistics(response)
14 |
15 | return response
16 |
17 |
--------------------------------------------------------------------------------
/farbox_bucket/server/statistics/usage_collect.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from flask import Response
3 | from gevent import spawn
4 | from farbox_bucket.bucket.utils import get_bucket_in_request_context
5 | from farbox_bucket.bucket.usage.bucket_usage_utils import increase_request_for_bucket, increase_bandwidth_for_bucket
6 |
7 |
8 | def update_usage_statistics(response):
9 | bucket = get_bucket_in_request_context()
10 | if not bucket:
11 | return
12 |
13 | if not isinstance(response, Response):
14 | return
15 | # requests + 1
16 | spawn(increase_request_for_bucket, bucket)
17 |
18 | if response.status_code not in [301, 302, ]:
19 | bandwidth = response.content_length
20 | if bandwidth:
21 | spawn(increase_bandwidth_for_bucket, bucket, bandwidth)
22 |
23 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/app_functions/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/app_functions/after_request/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/app_functions/before_and_after_request/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/app_functions/before_and_after_request/time_cost.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | from flask import request
4 | import time
5 |
6 | def time_cost_handler(response=None):
7 | if not response: # before request
8 | request.environ['request_at'] = time.time()
9 | else: # after request
10 | request_at = request.environ.get('request_at')
11 | if request_at:
12 | time_cost = time.time() - request_at
13 | response.headers['x-render-time'] = str(time_cost) # 渲染消耗的时间,单位秒
14 | return response
15 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/app_functions/before_request/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/app_functions/before_request/basic.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from flask import request
3 |
4 | def basic_before_request():
5 | if request.environ.get('HTTP_X_PROTOCOL') == 'https': # ssl
6 | request.url = request.url.replace('http://', 'https://', 1)
7 | request.url_root = request.url_root.replace('http://', 'https://', 1)
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/app_functions/utils.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
4 | def apply_middleware(app, middleware):
5 | # 处理中间件 & before_request & after_request
6 | app.wsgi_app = middleware(app.wsgi_app)
7 | before_request = getattr(middleware, 'before_request',None)
8 | after_request = getattr(middleware, 'after_request',None)
9 | if before_request:
10 | app.before_request_funcs.setdefault(None,[]).append(before_request)
11 | if after_request:
12 | app.after_request_funcs.setdefault(None, []).append(after_request)
13 |
14 |
15 |
16 | def apply_before_request(app, func):
17 | app.before_request_funcs.setdefault(None,[]).append(func)
18 |
19 | def apply_after_request(app, func):
20 | app.after_request_funcs.setdefault(None,[]).append(func)
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/attr_patch/fake_fields.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 |
4 |
5 | def get_value_for_fake_field_for_doc(obj, attr):
6 |
7 | return None # by default
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/exceptions.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 |
4 | class TemplateDebugException(Exception):
5 | pass
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/helper/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/template_system/helper/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/model/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/template_system/model/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/namespace/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | from farbox_bucket.server.utils.cache_for_function import cache_result
4 | from .data import data, paginator, get_data
5 | from .request import request
6 | from .html import html, Html
7 | from .post import posts, post
8 | from .site import site
9 | from .response import response
10 | from .bucket import bucket
11 |
12 | namespace_functions = {
13 | 'd': data,
14 | 'data': data,
15 | 'request': request,
16 | 'html': html,
17 | 'h': html,
18 | 'paginator': paginator,
19 | 'post': post,
20 | 'posts': posts,
21 | 'p': posts,
22 | 'site': site,
23 | 'response': response,
24 | 'bucket': bucket,
25 | 'b': bucket,
26 | }
27 |
28 |
29 |
30 | # shortcuts
31 |
32 |
33 | @cache_result
34 | def i18n(key, *args): # i18n 专用函数名
35 | return Html.i18n(key, *args)
36 |
37 |
38 | namespace_shortcuts = {
39 | "_": i18n,
40 | "i18n": i18n,
41 | "get_data": get_data,
42 | "load": Html.load
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/namespace/built_in.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 | import re
4 |
5 | # 必须要有的一个系统公共函数
6 |
7 | def set_property(parent, property_name, value):
8 | # 这个函数很重要,是在 jade 模板中被调用的,不能孔雀
9 | # 这里要隔绝 parent,不能传递特别的东西,不然会有安全隐患
10 | if hasattr(value, 'core'): # 可能某些 model 处理过的,比如Text
11 | value = value.core
12 | if parent is not None and isinstance(property_name, (str, unicode)) and re.match('[a-z_]\w*$', property_name, re.I):
13 | if isinstance(parent, dict): # 字典的处理
14 | parent[property_name] = value
15 | if getattr(parent, 'set_property_allowed', None) and not hasattr(value, '__call__'):
16 | # 不能赋函数值
17 | setattr(parent, property_name, value)
18 | return ''
19 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/namespace/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/template_system/namespace/utils/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/namespace/utils/post_utils.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/syntax_block/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from .pure import pure
3 | from .lazy_html import tab
4 | from .refer import refer
5 | from .compatibility import syntax_block_compatibility
6 | from .page import page
7 |
8 | syntax_blocks = {
9 | 'pure': pure,
10 | 'tab': tab,
11 | "refer": refer,
12 | "page": page,
13 |
14 | # compatibility for Bitcron
15 | "footer": syntax_block_compatibility,
16 | "browser": syntax_block_compatibility,
17 | "font": syntax_block_compatibility,
18 | }
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/syntax_block/compatibility.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 | #+font
4 |
5 |
6 | def syntax_block_compatibility(**kwargs):
7 | caller = kwargs.pop('caller', None)
8 | if not caller or not hasattr(caller, '__call__'):
9 | return ""
10 | else:
11 | try:
12 | return caller()
13 | except:
14 | return ""
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/syntax_block/lazy_html.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import re
3 | import uuid
4 | from farbox_bucket.server.utils.cache_for_function import cache_result
5 | from farbox_bucket.server.template_system.api_template_render import render_api_template
6 | from farbox_bucket.utils import get_random_html_dom_id
7 |
8 |
9 |
10 | def tab(keys, active=1, **kwargs):
11 | # +tab(keys=[a, b, c], active=1)
12 | # #tab
13 | # #tab
14 | # #tab.etc
15 |
16 | caller = kwargs.pop('caller', None)
17 | if not caller or not hasattr(caller, '__call__'):
18 | return ''
19 | if not isinstance(keys, (list, tuple)) or not keys:
20 | return ''
21 | dom_id = get_random_html_dom_id()
22 | inner_html = caller()
23 | real_tabs_count = inner_html.count('')
24 | keys = keys[:real_tabs_count]
25 | if len(keys) <=1: # 只有一个,没有处理为tab的需要
26 | return inner_html
27 | for i in range(len(keys)):
28 | tab_dom_id = '%s-%s' % (dom_id, i)
29 | # 替换模板默认的tab id
30 | inner_html = re.sub(r'(
]*?id=[\'"])(tab\d*)([\'"])', '\g<1> class=tab_item \g<2>%s\g<4>'%tab_dom_id, inner_html, count=1)
31 | html = render_api_template('api_tab.jade',
32 | keys=keys, dom_id=dom_id, active=active, inner_html=inner_html,
33 | return_html=True, **kwargs)
34 |
35 | return html
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/syntax_block/modal.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils import get_random_html_dom_id
3 | from farbox_bucket.server.utils.cache_for_function import cache_result
4 | from farbox_bucket.server.template_system.api_template_render import render_api_template
5 |
6 |
7 | def modal(trigger='', *args, **kwargs):
8 | # trigger 如果是对innerHTML的处理,就是一个click_dom_id(selector), 如果是一个url,则是超级链接的title
9 | caller = kwargs.pop('caller', None)
10 | if not caller or not hasattr(caller, '__call__'):
11 | # 不是作为block模式,而是直接调用,可能是GET方式打开一个URL
12 | url = kwargs.get('url') or ''
13 | if not url and args:
14 | url = args[0]
15 | title = trigger
16 | if isinstance(url, (str, unicode)): # 创建一个GET模式的modal的a元素
17 | dom_id = kwargs.get('id')
18 | return render_api_template('api_syntax_modal.jade', ajax=True, return_html=True, url=url, title=title,
19 | dom_id=dom_id, **kwargs)
20 | return ''
21 | inner_html = caller()
22 | dom_id = get_random_html_dom_id()
23 | if trigger and not trigger.startswith('#') and not trigger.startswith('.'): # id 类型的补足
24 | trigger = '#' + trigger
25 | html = render_api_template('api_syntax_modal.jade', inner_html=inner_html, dom_id=dom_id, selector=trigger,
26 | return_html=True, **kwargs)
27 | return html
28 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/syntax_block/page.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from flask import request
3 | from farbox_bucket.server.utils.cache_for_function import cache_result
4 | from farbox_bucket.server.utils.response import force_response
5 | from farbox_bucket.server.template_system.api_template_render import render_api_template
6 |
7 |
8 |
9 |
10 | def page(*sub_args, **kwargs):
11 | caller = kwargs.pop('caller', None)
12 | if caller and request.args.get('pjax', '').lower() == 'true' and hasattr(caller, '__call__'):
13 | # pjax 下的时候,仅仅处理 caller 下的内容,这样就不会引入冗余的 html,从而直接 ajax append 即可
14 | return force_response(caller())
15 | html = render_api_template('api_syntax_page.jade', caller=caller, return_html=True, **kwargs)
16 | return html
17 |
--------------------------------------------------------------------------------
/farbox_bucket/server/template_system/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/template_system/templates/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/utils/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/utils/lazy.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 |
4 | class LazyDict(dict):
5 | # 非常有用的一个处理,可以让dict 之类的数据,可以直接调用 property 的写法
6 | def __getitem__(self, item):
7 | try:
8 | value = dict.__getitem__(self, item)
9 | except:
10 | value = LazyDict()
11 | return value
12 |
13 | def __getattr__(self, item):
14 | return self.__getitem__(item)
15 |
16 | def __repr__(self):
17 | return ''
18 |
19 | def __nonzero__(self):
20 | return 0
21 |
--------------------------------------------------------------------------------
/farbox_bucket/server/utils/record_and_paginator/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/server/utils/record_and_paginator/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/server/utils/response_html.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import re
3 | from farbox_bucket.utils import get_value_from_data, str_type, unicode_type, string_types, to_bytes, to_unicode
4 | from farbox_bucket.server.utils.request_context_vars import get_no_html_inject_in_request
5 |
6 |
7 | def insert_into_footer(to_insert, html, force=False):
8 | # 插入到 html 页面的尾部
9 | if not force and get_no_html_inject_in_request():
10 | return html
11 | if not to_insert:
12 | return html
13 | if isinstance(html, str_type) and isinstance(to_insert, unicode_type):
14 | to_insert = to_bytes(to_insert)
15 | if isinstance(to_insert, string_types):
16 | # 会放在
\n', methods=['POST', 'GET'])
14 | def install_ssl(domain=''):
15 | set_not_cache_current_request()
16 | domain = domain or request.values.get('domain', '').lower().strip()
17 | if ':' in domain:
18 | domain = domain.split(':')[0]
19 | if not request.host.startswith('127.0.0.1'):
20 | abort(404, 'should be localhost')
21 | if request.remote_addr and request.remote_addr != '127.0.0.1':
22 | abort(404, 'outside error')
23 |
24 | bucket = get_bucket_from_domain(domain)
25 | if not bucket:
26 | abort(404, 'bucket is not found')
27 |
28 | cert_doc = get_ssl_cert_for_domain(domain)
29 |
30 | ssl_key = cert_doc.get('ssl_key')
31 | ssl_cert = cert_doc.get('ssl_cert')
32 | if ssl_key and ssl_cert:
33 | return send_plain_text('%s,%s' % (ssl_key, ssl_cert))
34 | else:
35 | return ','
36 |
37 |
38 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Cais/archive.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 |
3 | block content
4 | .content: .list_with_title
5 | entries = d.get_data(type='post',limit=300, sort='desc', status='public').group('-date:year')
6 | for year, posts in entries
7 | div.listing_title= year
8 | .listing: for post in posts: .listing-item
9 | .listing_post
10 | a(href=post.url, title=post.title)= post.title
11 | div.post_date: span.date= post.date("%m-%d")
12 | +h.paginator(pre_label='Prev', next_label='Next')
13 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Cais/base.jade:
--------------------------------------------------------------------------------
1 | html
2 | +h.i18n('Home', '首页', 'zh_cn')
3 | +h.i18n('Categories', '分类', 'zh_cn')
4 | +h.i18n('Archive', '归档', 'zh_cn')
5 | +h.i18n('Tags', '标签', 'zh_cn')
6 | +h.i18n('About', '关于', 'zh_cn')
7 | +h.i18n('Links', '友链', 'zh_cn')
8 |
9 | head
10 | +h.headers
11 |
12 | block title
13 | title= posts.post.title or site.title
14 |
15 | +h.load('/template/css/markdown.scss')
16 | +h.load('/template/css/style.scss')
17 |
18 | body
19 |
20 | .sidebar: .sidebar_body
21 | nav_data = (['首页', '/'], ['归档', '/archive'],['订阅', '/feed'])
22 | //+h.get_nav(nav_data, load_front_sources=False)
23 | +site.just_nav
24 |
25 | .header
26 | .logo_title
27 | .title.animated.fadeInDown
28 | h1(title="")
29 | a(href=h.url("/")) {{ site.title }}
30 | if site.raw_content
31 | .description.animated.fadeInDown
32 | p= '♥ %s ♥' % site.raw_content[:100]
33 |
34 | +site.socials
35 |
36 |
37 | block content
38 |
39 |
40 | .footer
41 | a(target="_blank", href="{{request.url_root}}")
42 | span All content copyright {{site.title}} © 2015 • All rights reserved.
43 | span Designed by
44 | a(href="https://www.caicai.me") CaiCai
45 | .by
46 | a(href="https://farBox.com/?s=f", target="_blank") Proudly published with FarBox!
47 |
48 | +h.auto_sidebar('right')
49 | +h.load('font')
50 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Cais/feed.jade:
--------------------------------------------------------------------------------
1 | doctype xml
2 | +response.set_content_type('application/xml')
3 | feed(xmlns="http://www.w3.org/2005/Atom")
4 | title= site.title
5 | description= site.description.escaped
6 | link(href="http://{{ request.host }}/")
7 | link(ref="self", href="http://{{ request.host }}/feed")
8 | id= site._id
9 | feed_posts = d.get_data(type='post', limit=10)
10 | if feed_posts
11 | updated= feed_posts[0]['date'].strftime('%Y-%m-%dT%H:%M:%SZ')
12 | for post in feed_posts
13 | entry
14 | post_url = 'http://' + request.host + post.url.escaped
15 | title= post.title.escaped
16 | link(href=post_url, rel="alternate")
17 | updated= post.date.strftime('%Y-%m-%dT%H:%M:%SZ')
18 | id= post.url_path.escaped
19 | author
20 | name= site.author or site.admin_name or site.title
21 | summary(type="html")= post.content.escaped
--------------------------------------------------------------------------------
/farbox_bucket/themes/Cais/index+tag.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 |
3 | mixin make_post(post)
4 | .post
5 | .post_title: h2
6 | a(href=post.url)= post.title
7 |
8 | .post_content.markdown= post.content.opening or post.content.limit(200, keep_images=True)
9 |
10 | .post_footer
11 | if post.tags: .tags: for tag in post.tags
12 | a.btn(role="tags", href=posts.get_tag_url(tag))= tag
13 |
14 | .info
15 | i.fa.fa-clock-o
16 | span.date= post.date("%Y-%m-%d %H:%M")
17 |
18 | i.fa.fa-comment-o
19 | a(href="{{post.url}}#comments")= '%s Comments'%(post.comments_count or 0)
20 |
21 |
22 | block content
23 | .content: .post_list
24 | for post in posts
25 | +make_post(post)
26 | +h.paginator(pre_label='Newer Posts', next_label='Older Posts')
27 |
28 |
29 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Cais/post.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 |
3 |
4 | block content
5 | .content
6 | .post_page: .post
7 | .post_title: h2
8 | a= post.title
9 | .post_content.markdown= post.content
10 | .post_footer
11 | if post.tags: .tags: for tag in post.tags
12 | a.btn(role="tags", href=posts.get_tag_url(tag))= tag
13 | .info
14 | i.fa.fa-clock-o
15 | span.date= post.date("%Y-%m-%d %H:%M")
16 |
17 | i.fa.fa-comment-o
18 | a(href="#comments")= '%s Comments'%(post.comments_count or 0)
19 |
20 | +post.comments_as_html()
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Cais/readme.txt:
--------------------------------------------------------------------------------
1 |
2 | [CaiCai (target=_blank)](http://blog.caicai.me/) 是我们的老朋友,作为一名出道不算久的设计师,但是涉猎的知识很广,写代码、策划、测试。
3 |
4 |
5 | CaiCai的进步速度非常快,最开始的时候,他想重新设计FarBox的后台管理,除了UI稿,然后被我们“友好”地驳回了;如果现在他还有时间重新设计的话,恐怕我们就没有这么容易驳回了……
6 |
7 |
8 | 除了网页界面外,CaiCai还参与了FarBox Editor的界面自定义模块的工作,这是他的一个[repo (target=_blank)](https://github.com/hi-caicai/Farbox-Editor-)。
9 |
10 |
11 | 最近,他开始创作一款新的FarBox模板。对,我们看了一个初始的模样,很值得期待。
12 |
13 |
14 | 有时,也会怀疑,CaiCai的时间怎么如此充裕,虽然有几次大半夜时分联系,他说`正在外面Happy呢`。
15 |
16 |
17 | 对,就是这样一个人的一个作品。希望你会喜欢。
18 |
19 |
20 | 2017-4-16 update: Cais 的模板来自原来的 FarBox 系统,上文这段介绍已经是许多年前的了,如今的 CaiCai 同学也更加的优秀,保留这个介绍,好像还是蛮有趣的事情。 :)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Classify/archive.jade:
--------------------------------------------------------------------------------
1 | extends base
2 |
3 | block content
4 | group_type = 'tags' if request.path.strip('/')=='tags' else '-date:year'
5 | entries = d.get_data(type='post',limit=50, sort='desc', status='public').group(group_type)
6 | for sub_title, posts in entries: .archive
7 | h1= sub_title
8 | ul: for post in posts: li
9 | a(href=post.url, title=post.title)= post.title
10 | span.date= post.date.format("%Y-%m-%d")
11 |
12 | if paginator.has_pre or paginator.has_next: .pager
13 | if paginator.has_pre
14 | a.round.pre(href=paginator.pre_url) ← Newer
15 | if paginator.has_next
16 | a.round.next(href=paginator.next_url) Older →
--------------------------------------------------------------------------------
/farbox_bucket/themes/Classify/base.jade:
--------------------------------------------------------------------------------
1 | html
2 | head
3 | +h.headers
4 |
5 | block title
6 | title= request.args.s or site.title
7 | +h.load('markdown')
8 | +h.load('pure')
9 | +h.load('/template/css/style.scss')
10 | body
11 | #header
12 | nav_data = (['首页', '/'], ['归档', '/archive'],['订阅', '/feed'])
13 | //+h.get_nav(nav_data, toggle_menu=True)
14 | +site.nav
15 |
16 | #layout
17 | block content
18 |
19 | #footer= site.footer
--------------------------------------------------------------------------------
/farbox_bucket/themes/Classify/category.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 |
3 | category = d.get_doc(path=request.offset_path1, type='folder')
4 |
5 | block title
6 | if category
7 | title = category.title
8 | else
9 | +response.raise_404()
10 |
11 | title= title
12 |
13 | block content
14 | category_posts = d.get_data(type='post', status='public', limit=10, path=request.offset_path1)
15 |
16 | .posts_in_list
17 | h1= category.title
18 | ul: for post in category_posts: li
19 | a(href=post.url)= post.title
20 | span.date= post.date('%d %b %Y')
21 |
22 | if paginator.has_pre or paginator.has_next: .pager
23 | if paginator.has_pre
24 | a.round.pre(href=paginator.pre_url) ← Newer
25 | if paginator.has_next
26 | a.round.next(href=paginator.next_url) Older →
--------------------------------------------------------------------------------
/farbox_bucket/themes/Classify/feed.jade:
--------------------------------------------------------------------------------
1 | doctype xml
2 | +response.set_content_type('application/xml')
3 | feed(xmlns="http://www.w3.org/2005/Atom")
4 | title= site.title
5 | description= site.description.escaped
6 | link(href="http://{{ request.host }}/")
7 | link(ref="self", href="http://{{ request.host }}/feed")
8 | id= site._id
9 | feed_posts = d.get_data(type='post', limit=10)
10 | if feed_posts
11 | updated= feed_posts[0]['date'].strftime('%Y-%m-%dT%H:%M:%SZ')
12 | for post in feed_posts
13 | entry
14 | post_url = 'http://' + request.host + post.url.escaped
15 | title= post.title.escaped
16 | link(href=post_url, rel="alternate")
17 | updated= post.date.strftime('%Y-%m-%dT%H:%M:%SZ')
18 | id= post.url_path.escaped
19 | author
20 | name= site.author or site.admin_name or site.title
21 | summary(type="html")= post.content.escaped
--------------------------------------------------------------------------------
/farbox_bucket/themes/Classify/index.jade:
--------------------------------------------------------------------------------
1 | extends base
2 |
3 | block content
4 | newest_posts = d.get_data(type='post', limit=10, with_page=False, status='public')
5 | if newest_posts
6 | newest_post = newest_posts[0]
7 | if newest_post: .newest_post
8 | h2
9 | a(href=newest_post.url)= newest_post.title
10 | a.summary(href=newest_post.url)
11 | .content.markdown
12 | if newest_post.metadata.refer
13 | refer_doc = d.get_doc(newest_post.metadata.refer)
14 | if refer_doc and refer_doc.type == 'post'
15 | blockquote.refer= refer_doc.content.limit(180)
16 | div= newest_post.content.opening or newest_post.content.limit(180)
17 |
18 | .pure-g#categories
19 | categories = d.get_data(type='folder', limit=100, level=1, sort='position')
20 | for category in categories
21 | .pure-u-1.pure-u-sm-1-2.pure-u-lg-1-3.pure-u-lg-1-4: .category
22 | a(href=h.url('/category/%s'%category.path))
23 | h3= category.title
24 | posts_count = site.count_folder(category.path, 'posts')
25 | span {{ posts_count }} posts
--------------------------------------------------------------------------------
/farbox_bucket/themes/Classify/post.jade:
--------------------------------------------------------------------------------
1 | extends base
2 |
3 | block title
4 | title= post.title
5 |
6 | block content
7 | .post.post_page
8 | h1.title= post.title
9 | .content
10 | .post_content.markdown
11 | if post.metadata.refer
12 | refer_doc = d.get_doc(post.metadata.refer)
13 | if refer_doc and refer_doc.type == 'post'
14 | blockquote.refer= refer_doc.content.plain_html
15 | div= post.content
16 | .info
17 | if post.tags: .tags: for tag in post.tags
18 | a(href=posts.get_tag_url(tag))= tag
19 | .date @{{post.date}}
20 |
21 | +post.comments_as_html()
22 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Esta/archive.jade:
--------------------------------------------------------------------------------
1 | extends base
2 | block content
3 | .autopagerize_page_element:.content
4 | .archive: ul.list_with_title
5 | entries = d.get_data(type='post',limit=300, sort='desc').group('-date:year')
6 | for year, posts in entries
7 | div.listing_title= year
8 | ul.listing
9 | for post in posts: .listing_item: .listing_post
10 | a(href=post.url, title=post.title)= post.title
11 | div.post_time
12 | span.date= post.date("%m-%d")
13 | +h.paginator()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Esta/base.jade:
--------------------------------------------------------------------------------
1 | html
2 | +h.i18n('Home', '首页', 'zh_cn')
3 | +h.i18n('Categories', '分类', 'zh_cn')
4 | +h.i18n('Archive', '归档', 'zh_cn')
5 | +h.i18n('Tags', '标签', 'zh_cn')
6 | +h.i18n('About', '关于', 'zh_cn')
7 | +h.i18n('Links', '友链', 'zh_cn')
8 | head
9 | block title
10 | title= post.title or site.title
11 | +h.headers
12 | +h.load('markdown')
13 | +h.load('/template/style.scss')
14 |
15 | body
16 | .sidebar
17 | .logo_title
18 | .title
19 | a(href=h.url('/'))
20 | img(src=site.site_avatar,style="width:127px;")
21 | h3(title="")
22 | a(href=h.url("/"))= site.title
23 | if site.sub_title
24 | .sub_title: p=site.sub_title
25 |
26 | +site.socials
27 |
28 | .footer
29 | a(target="_blank", href="http://{{request.domain}}")
30 | span Designed by
31 | a(href="https://www.caicai.me") CaiCai
32 | .by_farbox
33 | a(href="https://www.farBox.com", target="_blank") Proudly published with FarBox!
34 |
35 | .main
36 | .page_top
37 | +site.get_nav(align="right", toggle_menu=True)
38 |
39 | block content
40 |
41 | +h.load('font')
42 | +h.load('/fb_static/lib/fonts/open_sans.css')
43 |
44 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Esta/index+tag.jade:
--------------------------------------------------------------------------------
1 | from mixins import make_post
2 | extends base.jade
3 | block content
4 | .autopagerize_page_element:.content
5 | for post in posts
6 | +make_post(post, is_detail=False)
7 | +h.paginator(pre_label="Newer Posts", next_label="Older Posts")
8 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Esta/mixins.jade:
--------------------------------------------------------------------------------
1 | mixin make_post(post, is_detail=False)
2 | .post
3 | .post_title: h2
4 | if is_detail
5 | a.detail_title= post.title
6 | else
7 | a(href=post.url)= post.title
8 | if is_detail
9 | .post_content.markdown= post.content
10 | else
11 | .post_content.markdown= post.content.opening or post.content.limit(200, keep_images=False)
12 | .post_footer: .meta: .info
13 | i.fa.fa-calendar
14 | span.date= post.date("%Y-%m-%d")
15 | span.comments_count
16 | i.fa.fa-comment-o
17 | a(href="{{post.url}}#comments")= '%s Comments' % (post.comments_count or 0)
18 |
19 | if post.tags
20 | i.fa.fa-tag
21 | for tag in post.tags
22 | a.tag(href=posts.get_tag_url(tag))= tag
23 |
24 | if is_detail
25 | +post.comments_as_html()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Esta/post.jade:
--------------------------------------------------------------------------------
1 | from mixins import make_post
2 |
3 | extends base.jade
4 | block content
5 | .content: .post-page
6 | +make_post(post, is_detail=True)
--------------------------------------------------------------------------------
/farbox_bucket/themes/Fexo/base.jade:
--------------------------------------------------------------------------------
1 | html
2 | head
3 | +h.headers
4 | block title
5 | title= post.title or site.title
6 | +h.load('/fb_static/lib/pure.css')
7 | +h.load('/fb_static/lib/markdown/basic.css')
8 | +h.load("/template/static/style.scss")
9 | body
10 | block header
11 | #nav_header
12 | +site.get_nav(align="right", toggle_menu=True)
13 |
14 | block content
15 |
16 |
17 |
18 | +h.back_to_top()
19 |
20 | +h.load("/fb_static/lib/jquery.js")
21 | +h.load('font')
22 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Fexo/category+categories.jade:
--------------------------------------------------------------------------------
1 | from mixins import make_timeline
2 | extends base.jade
3 | block content
4 | .content
5 | .page-header
6 | .box-blog-info
7 | a.avatar(href='/')
8 | img(src=site.site_avatar)
9 | .info
10 | h3.name= site.title
11 | .slogan= site.sub_title
12 |
13 | if posts.category
14 | all_posts = posts.list_obj
15 | else
16 | all_posts = get_data(type='post',limit=300, sort='desc')
17 | entries = all_posts.group('path:parent_path')
18 | +make_timeline(entries)
19 |
20 | +h.paginator()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Fexo/index.jade:
--------------------------------------------------------------------------------
1 | from mixins import make_timeline
2 | extends base.jade
3 |
4 | block content
5 | .content
6 | .page-header: .box-blog-info
7 | a.avatar(href='/')
8 | img(src=site.site_avatar)
9 | .info
10 | h3.name= site.title
11 | .slogan= site.sub_title
12 |
13 | entries = d.get_data(type='post',limit=300, sort='desc').group('-date:year')
14 | +make_timeline(entries)
15 |
16 | +h.paginator()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Fexo/license.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 forsigner
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/farbox_bucket/themes/Fexo/mixins.jade:
--------------------------------------------------------------------------------
1 | mixin make_timeline(cated_posts)
2 | ul.post_list: for category, posts in cated_posts
3 | li.item_title
4 | dot_class = 'dot dot_%s'%loop.index
5 | span(style="background: {{h.get_a_color()}}", class=dot_class)
6 | category_title = category or 'UnCategory'
7 | span.category_title(id=h.get_dom_id(category_title))= category_title
8 | for post in posts
9 | li.item_post.item
10 | span.dot(style="background: {{h.get_a_color()}}")
11 | span.post_date= post.date.format('%m-%d')
12 | a.post_title(href=post.url)= post.title
13 |
14 |
15 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Fexo/post.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 |
3 | +h.i18n("Post TOC", "文章目录", "zh_cn")
4 |
5 | block content
6 | use_toc = post.toc and post.metadata.get('toc', True)
7 | .post: div(class="post_with_toc" if use_toc else "post_without_toc")
8 | .header
9 | h1.title= post.title
10 | .info
11 | span.date= post.date('%Y-%m-%d')
12 | if post.category
13 | a.category(href=post.category.url)= post.category.filename or post.category.title
14 |
15 | if use_toc
16 | .post_container: .pure-g
17 | .pure-u-1.pure-u-md-2-3.pure-u-lg-4-5
18 | .post_content.markdown= post.content
19 | .pure-u-1.pure-u-md-1-3.pure-u-lg-1-5: .toc_container
20 | toc_header = '%s
'%_("Post TOC")
21 | +h.auto_toc(post, toc_header=toc_header)
22 | else
23 | .post_container
24 | .post_content.markdown= post.content
25 |
26 | +post.comments_as_html()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Puti/License.txt:
--------------------------------------------------------------------------------
1 | 此模板运行于 FarBox 之上, 如果需要应用到其它平台上, 请先联系原作者获得许可。
2 |
3 | 另外, 此主题为付费主题, 付费之后可以获取、修改源码, 但不可以任何方式公开、开源此源码, 以及其衍生版本的源码。
--------------------------------------------------------------------------------
/farbox_bucket/themes/Puti/archive.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 | block content
3 | .autopagerize_page_element:.content
4 | ul.list_with_title
5 | entries = d.get_data(type='post',limit=300, sort='desc').group('-date:year')
6 | for year, posts in entries
7 | div.listing_title= year
8 | ul.listing
9 | for post in posts
10 | .listing_item
11 | .listing_post
12 | a(href=post.url, title=post.title)= post.title
13 | div.post_time
14 | span.date= post.date("%m-%d")
15 | +h.paginator(pre_label=_('Prev'), next_label=_('Next'))
--------------------------------------------------------------------------------
/farbox_bucket/themes/Puti/base.jade:
--------------------------------------------------------------------------------
1 | html
2 |
3 | head
4 | +h.headers
5 | block title
6 | title= posts.post.title or site.title
7 | +h.load('font')
8 | +h.load('/template/css/markdown.scss')
9 | +h.load('/template/css/animate.3.5.2.min.css')
10 | +h.load('/template/css/style.scss')
11 | body
12 | .main.animated
13 | .header.animated.fadeInDown
14 | .site_title_container
15 | .site_title
16 | if site.title.length > 6
17 | a_class = 'long_long'
18 | elif site.title.length > 4
19 | a_class = 'long'
20 | else
21 | a_class = ''
22 | h1
23 | a(class=a_class, href=h.url('/'))= site.title
24 |
25 | .description
26 | p.sub_title= site.sub_title
27 | //+h.nav(['首页', '/'], ['订阅', '/feed'])
28 | +site.nav
29 | block content
30 |
31 | .footer
32 |
33 | .powered_by
34 | a(href="https://www.caicai.me") Designed by CaiCai,
35 | a(href="https://www.farBox.com", target="_blank") Proudly published with FarBox!
36 |
37 | .footer_slogan
38 | span= site.configs.footer_slogan or '重拾写作的乐趣'
39 |
40 |
--------------------------------------------------------------------------------
/farbox_bucket/themes/Puti/feed.jade:
--------------------------------------------------------------------------------
1 | doctype xml
2 | +response.set_content_type('application/xml')
3 | feed(xmlns="http://www.w3.org/2005/Atom")
4 | title= site.title
5 | description= site.description.escaped
6 | link(href="http://{{ request.host }}/")
7 | link(ref="self", href="http://{{ request.host }}/feed")
8 | id= site._id
9 | feed_posts = d.get_data(type='post', limit=10)
10 | if feed_posts
11 | updated= feed_posts[0]['date'].strftime('%Y-%m-%dT%H:%M:%SZ')
12 | for post in feed_posts
13 | entry
14 | post_url = 'http://' + request.host + post.url.escaped
15 | title= post.title.escaped
16 | link(href=post_url, rel="alternate")
17 | updated= post.date.strftime('%Y-%m-%dT%H:%M:%SZ')
18 | id= post.url_path.escaped
19 | author
20 | name= site.author or site.admin_name or site.title
21 | summary(type="html")= post.content.escaped
--------------------------------------------------------------------------------
/farbox_bucket/themes/Puti/index+tag.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 | block content
3 | .autopagerize_page_element:.content
4 | for post in posts: .post.animated.fadeInDown
5 | .post_title
6 | h2: a(href=post.url)= post.title
7 | .list
8 | .post_content
9 | p= post.content.limit(words=90).no_pic.plain
10 |
11 | .post_footer: .meta: .info
12 | span.field
13 | i.fa.fa-sun-o
14 | span.date= post.date.format("%Y.%m.%d")
15 | span.field
16 | i.fa.fa-comment-o
17 | span= "%s Comments" % (post.comments_count or 0)
18 | if post.tags: span.field.tags
19 | i.fa.fa-flask
20 | for tag in post.tags
21 | a.tag(href=posts.get_tag_url(tag))= tag
22 |
23 | +h.paginator(pre_label='返回上一页', next_label='阅读更多文章')
--------------------------------------------------------------------------------
/farbox_bucket/themes/Puti/post.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 |
3 | block content
4 | .autopagerize_page_element: .content: .post_page
5 | .post.animated.fadeInDown
6 | .post_title.post_detail_title
7 | h2: a= post.title
8 | span.date= post.date("%Y.%m.%d %H:%M")
9 |
10 | .post_content.markdown= post.content
11 |
12 | .post_footer:.meta: .info
13 | if post.tags: span.field.tags
14 | i.fa.fa-flask
15 | for tag in post.tags
16 | a.tag(href=posts.get_tag_url(tag))= tag
17 | +post.comments_as_html()
18 | +h.back_to_top()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Puti/readme.txt:
--------------------------------------------------------------------------------
1 | price: 10
2 |
3 | 这个模板简洁而极具设计感,在模板应用后,网站对应的设置 (Dashboard) 内会多出几个字体相关的设置。
4 |
5 | **但请注意:**
6 | 1,Puti 这个主题更适用于中文的内容。
7 | 2,网站的标题应该是中文的、没有标点符号、不超过8字,最好是偶数,比如 4 字 或 6 字。
8 | 3,网站的副标题也不宜过长。
--------------------------------------------------------------------------------
/farbox_bucket/themes/Sollrei/archive.jade:
--------------------------------------------------------------------------------
1 | extends base
2 |
3 | block content
4 | h2.archive-title 归档
5 | entries = data.get_data(type='post', limit=300, sort='-date', pager_name='archive').group('date:year', reverse=True)
6 | .mod-archive:.archive
7 | for year, posts in entries
8 | .archive-year= year
9 | ul.archive-list
10 | for post in posts: li.post-item
11 | span.date= post.date('%Y-%m-%d')
12 | a(href=post.url, title=post.title)= post.title
13 |
14 | +h.paginator()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Sollrei/base.jade:
--------------------------------------------------------------------------------
1 | html
2 | head
3 | +h.headers
4 | block title
5 | title= site.title
6 | +h.load('/template/css/reset.scss')
7 | +h.load('font', 'pure', 'markdown')
8 | +h.load('/template/css/style.scss')
9 | +h.load("/template/css/fonts.css")
10 | body.page-home
11 | #header.mod-header
12 | h1.site-title:a(href=h.url('/?status=loaded'))= site.title
13 | nav_items = [('Home', '/')]
14 | for category in posts.categories
15 | +nav_items.append([category.title, category.url])
16 | +nav_items.append(['Archive', '/archive'])
17 | .mod-nav
18 | +h.get_nav(nav_items, toggle_menu=True)
19 |
20 | block banner
21 |
22 | #main.main
23 | .pure-g
24 | .pure-u-23-24.pure-u-md-17-24.layout
25 | block content
26 | footer#footer.mod-footer
27 | .contact= site.socials
28 | .copyright
29 | span Powered by
30 | a(href="https://www.farBox.com", target="_blank") FarBox
31 | span Theme by
32 | a(href="https://www.sollrei.me") Sollrei
33 | +h.load('jquery')
34 | +h.load('/template/js/particles.js')
35 | +h.load('/template/js/index.js')
--------------------------------------------------------------------------------
/farbox_bucket/themes/Sollrei/index+category+tag.jade:
--------------------------------------------------------------------------------
1 | extends base
2 |
3 | is_not_homepage = request.path.startswith('/tag/') or request.path.startswith('/category/')
4 |
5 | block title
6 | title= posts.category.title or posts.tags.join("+") or site.title
7 |
8 | block banner
9 | .mod-banner
10 | bg = site.real_background_image or '/fb_static/unsplash/5.jpg'
11 | .banner(style='background-image: url(%s)'%bg, id='' if is_not_homepage else 'particles-js')
12 | if is_not_homepage: .banner-title
13 | h3= posts.category.title or posts.tags.join('+')
14 | posts_count = posts.category.posts_count or posts.length
15 | p= posts_count
16 | span= 'posts' if posts_count !=1 else 'post'
17 |
18 |
19 | block content
20 |
21 | .post-list:for post in posts: .mod-post
22 | .post-meta
23 | time.post-date(datetime=post.date('%B %d, %Y'), pubdate="pubdate")
24 | span.post-m= post.date('%b')
25 | span.post-d= post.date('%d')
26 | span.post-y= post.date('%Y')
27 | .post-main
28 | h3.post-title
29 | a(href=post.url)= post.title
30 | .post-content.markdown= post.content.opening or post.content.limit(150)
31 | .post-info
32 | if post.tags
33 | for tag in post.tags
34 | a.tag(href=posts.get_tag_url(tag))= tag
35 | span.count
36 | i.fa.fa-book
37 | span= post.visits or 0
38 | +h.paginator()
--------------------------------------------------------------------------------
/farbox_bucket/themes/Sollrei/post.jade:
--------------------------------------------------------------------------------
1 | extends base.jade
2 | block title
3 | title= post.title
4 | block content
5 | .detail-page
6 | .mod-article.mod-post
7 | .post-meta
8 | time.post-date(datetime=post.date('%B %d, %Y'), pubdate="pubdate")
9 | span.post-m= post.date('%b')
10 | span.post-d= post.date('%d')
11 | span.post-y= post.date('%Y')
12 | .post-main
13 | h2.article-title= post.title
14 | .post-metas
15 | if post.tags: span
16 | i.fa.fa-tags
17 | for tag in post.tags
18 | a.tag(href="/tag/{{tag}}") {{tag}}
19 | span.count
20 | i.fa.fa-book
21 | span= post.visits or 0
22 | .entry.markdown= post.content
23 |
24 |
25 | +post.comments_as_html()
--------------------------------------------------------------------------------
/farbox_bucket/themes/build_themes.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import os
3 | from farbox_bucket.client.dump_template import get_template_info
4 | from farbox_bucket.utils import to_bytes
5 |
6 | root = os.path.abspath(os.path.dirname(__file__))
7 |
8 | themes_py_file = os.path.join(root, '__init__.py')
9 |
10 |
11 | templates = {}
12 |
13 | for name in os.listdir(root):
14 | folder_path = os.path.join(root, name)
15 | if not os.path.isdir(folder_path):
16 | continue
17 | template_key = name.lower().strip()
18 | template_info = get_template_info(folder_path)
19 | template_info['_theme_key'] = template_key
20 | templates[template_key] = template_info
21 |
22 |
23 | py_file_content = '#coding: utf8\nthemes = %s' % templates
24 | with open(themes_py_file, 'wb') as f:
25 | f.write(to_bytes(py_file_content))
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/async_block.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 | from flask import request
4 | from gevent.event import Event
5 | import gevent
6 |
7 |
8 | async_website_blocks = {}
9 |
10 |
11 | def run_in_website_with_block(func):
12 | def _func(*args, **kwargs):
13 | host = request.host
14 | block_event = async_website_blocks.setdefault(host, Event())
15 | while block_event.is_set():
16 | gevent.sleep(0.01)
17 | block_event.set()
18 | try:
19 | result = func(*args, **kwargs)
20 | block_event.clear()
21 | return result
22 | except Exception as e:
23 | block_event.clear()
24 | raise e
25 | return _func
26 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/cli_color.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import, print_function
3 |
4 | #CSI="\x1B["
5 | #RED = CSI+"31;40m"
6 | #GREEN = CSI+'32;40m'
7 | #RESET =CSI+"m"
8 |
9 |
10 | FLAGS = dict(
11 | RESET = "\x1B[0m",
12 | BOLD = "\x1B[1m",
13 | DIM = "\x1B[2m",
14 | UNDER = "\x1B[4m",
15 | REVERSE = "\x1B[7m",
16 | HIDE = "\x1B[8m",
17 | CLEARSCREEN = "\x1B[2J",
18 | CLEARLINE = "\x1B[2K",
19 | BLACK = "\x1B[30m",
20 | RED = "\x1B[31m",
21 | GREEN = "\x1B[32m",
22 | YELLOW = "\x1B[33m",
23 | BLUE = "\x1B[34m",
24 | MAGENTA = "\x1B[35m",
25 | CYAN = "\x1B[36m",
26 | WHITE = "\x1B[37m",
27 | BBLACK = "\x1B[40m",
28 | BRED = "\x1B[41m",
29 | BGREEN = "\x1B[42m",
30 | BYELLOW = "\x1B[43m",
31 | BBLUE = "\x1B[44m",
32 | BMAGENTA = "\x1B[45m",
33 | BCYAN = "\x1B[46m",
34 | BWHITE = "\x1B[47m",
35 | NEWLINE = "\r\n\x1B[0m",
36 | )
37 |
38 | def print_with_color(strings, color='red', end='\r\n'):
39 | color = FLAGS.get(color.upper())
40 | if color:
41 | print(color + strings + FLAGS['RESET'], end=end)
42 | else:
43 | print(strings)
44 |
45 |
46 | def print_colorful_parts(string_parts, end=''):
47 | for strings, color in string_parts:
48 | print_with_color(strings, color, end)
49 | print(FLAGS['NEWLINE'], end='')
50 |
51 |
52 | if __name__ == '__main__':
53 | print_with_color('hello', 'green', end=' ')
54 | print_with_color('hello', 'blue')
55 |
56 | print_colorful_parts(
57 | [('hello', 'magenta'),
58 | ('world', 'yellow'),
59 | ('hello', 'red'),
60 | ('world', 'cyan')],
61 | end=' '
62 | )
63 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/client_sync/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/client_sync/log.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import, print_function
3 | import datetime
4 | from farbox_bucket.utils import smart_str, string_types
5 | from farbox_bucket.utils.path import write_file
6 | from .sync_utils import make_sure_sync_log_path
7 |
8 |
9 |
10 | def write_logs(logs, app_name, filepath=None, root=None,):
11 | # filepath: logs for which file, root: under which root
12 | if isinstance(logs, string_types):
13 | logs = [logs]
14 | if not logs:
15 | return # ignore
16 | if not root:
17 | return # ignore
18 | now = datetime.datetime.now()
19 | now_str = now.strftime('%Y-%m-%d %H:%M:%S')
20 | log_path = make_sure_sync_log_path(root, app_name)
21 | with open(log_path, 'a') as f:
22 | for log in logs:
23 | log = raw_log = smart_str(log)
24 | if filepath:
25 | filepath = smart_str(filepath)
26 | log = '%s: %s %s\n' %(now_str, filepath, log)
27 | else:
28 | log = '%s %s\n' %(now_str, smart_str(log))
29 | write_file(f, log)
30 |
31 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/console_utils.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | import sys, getopt
4 |
5 |
6 |
7 | # getopt.getopt(['--file=error.txt', '-h', '-v', '6', '--version', '9'], 'hv:', ['file=', 'version'])
8 | #getopt.getopt([ 'farbox', '--file=error.txt', '--version','-h', '-v', '6'], 'hv:', ['file=', 'version'])
9 | # getopt.getopt(['--file=error.txt', '--version','-h', '-v', '6', '9'], 'hv:', ['file=', 'version'])
10 | # ([('--file', 'error.txt'), ('-h', ''), ('-v', '6'), ('--version', '')], ['9'])
11 |
12 | def get_args_from_console(raw_args=None, short_opts='', long_opts=None):
13 | if raw_args is None:
14 | raw_args = sys.argv[1:]
15 | long_opts = long_opts or []
16 | opts, args = getopt.getopt(raw_args, short_opts, long_opts)
17 | kwargs = {}
18 | for k, v in opts:
19 | k = k.strip('-')
20 | kwargs[k] = v
21 | return kwargs, args
22 |
23 |
24 | def get_first_arg_from_console():
25 | raw_args = sys.argv[1:]
26 | if raw_args:
27 | return raw_args[0]
28 | else:
29 | return None
--------------------------------------------------------------------------------
/farbox_bucket/utils/convert/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/utils/convert/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/utils/convert/coffee2js.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | import os, subprocess, tempfile
3 | try:
4 | import gevent
5 | except:
6 | gevent = None
7 |
8 | def get_bin_script():
9 | scripts = [
10 | '/usr/local/bin/coffee',
11 | '/usr/bin/coffee',
12 | '/usr/local/share/npm/bin/coffee'
13 | ]
14 | for bin_script in scripts:
15 | if os.path.isfile(bin_script):
16 | return bin_script
17 |
18 | COFFEE_SCRIPT = get_bin_script()
19 |
20 |
21 | def compile_coffee(raw_content):
22 | if isinstance(raw_content, unicode):
23 | raw_content = raw_content.encode('utf8')
24 | temp = tempfile.NamedTemporaryFile()
25 | temp.file.write(raw_content)
26 | temp.file.close()
27 |
28 | command = 'cat %s | %s -sc' % (temp.name, COFFEE_SCRIPT)
29 | try:
30 | js_content = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
31 | except:
32 | js_content = raw_content
33 | temp.close()
34 | return js_content
35 |
36 | def is_coffee_valid():
37 | if 'call(this)' in compile_coffee('number = -42 if opposite'):
38 | return True
39 | else:
40 | return False
41 |
42 |
43 | def compile_coffee_with_timeout(raw_content, timeout=2):
44 | if not gevent:
45 | return
46 | gevent_job = gevent.spawn(compile_coffee, raw_content)
47 | try:
48 | content = gevent_job.get(block=True, timeout=timeout)
49 | except:
50 | content = ''
51 | gevent_job.kill(block=False)
52 | return content
53 |
54 |
55 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/convert/utils.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from farbox_bucket.utils.convert.coffee2js import compile_coffee
3 | from farbox_bucket.utils.convert.css import compile_css
4 | from farbox_bucket.utils.convert.jade2jinja import convert_jade_to_html
5 |
6 |
7 | def compile_frontend_resource(ext, raw_content):
8 | ext = ext.lower().strip('.')
9 | if ext in ['less', 'scss', 'sass']:
10 | func = compile_css
11 | compiled_type = 'text/css'
12 | elif ext in ['coffee']:
13 | func = compile_coffee
14 | compiled_type = 'text/javascript'
15 | elif ext in ['jade']:
16 | func = convert_jade_to_html
17 | compiled_type = 'text/html'
18 | else:
19 | func = ''
20 | compiled_type = ''
21 | if func:
22 | try:
23 | compiled_content = func(raw_content)
24 | except:
25 | compiled_content = ''
26 | else:
27 | compiled_content = ''
28 | return compiled_type, compiled_content
--------------------------------------------------------------------------------
/farbox_bucket/utils/encrypt/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/utils/encrypt/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/utils/error.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import traceback, sys
3 |
4 |
5 |
6 |
7 |
8 | def print_error(exc_info=None): # 本身不要再引发错误
9 | f = None
10 | try:
11 | error_info = exc_info or sys.exc_info()
12 | if error_info:
13 | e_type, value, tb = error_info[:3]
14 | try:
15 | traceback.print_exception(e_type, value, tb)
16 | except:
17 | pass
18 | except:
19 | pass
--------------------------------------------------------------------------------
/farbox_bucket/utils/functional.py:
--------------------------------------------------------------------------------
1 |
2 | # You can't trivially replace this `functools.partial` because this binds to
3 | # classes and returns bound instances, whereas functools.partial (on CPython)
4 | # is a type and its instances don't bind.
5 | def curry(_curried_func, *args, **kwargs):
6 | def _curried(*moreargs, **morekwargs):
7 | return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
8 | _curried.__name__ = _curried_func.__name__
9 | _curried.func_name = _curried_func.func_name
10 | _curried.original_func = _curried_func
11 | return _curried
12 |
13 |
14 |
15 | class cached_property(object):
16 | """
17 | Decorator that creates converts a method with a single
18 | self argument into a property cached on the instance.
19 | """
20 | def __init__(self, func):
21 | self.func = func
22 |
23 | def __get__(self, instance, type):
24 | res = instance.__dict__[self.func.__name__] = self.func(instance)
25 | return res
26 |
27 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/gzip_content.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 | from io import BytesIO
4 | import zlib
5 | #from gzip import GzipFile
6 | from base64 import b64decode, b64encode
7 |
8 |
9 | def gzip_content(content, base64=False):
10 | if isinstance(content, unicode):
11 | content = content.encode('utf8')
12 | zipped_content = zlib.compress(content)
13 | if base64:
14 | zipped_content = b64encode(zipped_content)
15 | return zipped_content
16 |
17 |
18 | def ungzip_content(raw_content, base64=False):
19 | if base64:
20 | raw_content = b64decode(raw_content)
21 | if isinstance(raw_content, unicode):
22 | raw_content = raw_content.encode('utf8')
23 | original_size = len(raw_content)
24 | f = BytesIO(raw_content)
25 | #z = zlib.decompressobj(15 + 16) # zlib.MAX_WBITS == 15
26 | z = zlib.decompressobj()
27 | total_size = 0
28 | content = ''
29 | while True:
30 | buf = z.unconsumed_tail
31 | if buf == "":
32 | buf = f.read(1024)
33 | if buf == "":
34 | break
35 | got = z.decompress(buf, 4096)
36 | if got == "":
37 | break
38 | content += got
39 | total_size += len(got)
40 | if total_size > 50*original_size:
41 | # this is boom
42 | return ''
43 | return content
--------------------------------------------------------------------------------
/farbox_bucket/utils/image/__init__.py:
--------------------------------------------------------------------------------
1 | #coding:utf8
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/ip/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/utils/ip/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/utils/logger.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | import logging
4 |
5 |
6 | cached_file_loggers = {}
7 |
8 | def get_file_logger(name):
9 | cached_logger = cached_file_loggers.get(name)
10 | if cached_logger:
11 | return cached_logger
12 | logger = logging.getLogger(name)
13 | logger.setLevel(logging.INFO)
14 | # create a file handler
15 | try:
16 | handler = logging.FileHandler('/var/log/%s.log'%name)
17 | except:
18 | handler = logging.FileHandler('/tmp/log_%s.log' % name)
19 | handler.setLevel(logging.INFO)
20 | # create a logging format
21 | formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
22 | handler.setFormatter(formatter)
23 | # add the handlers to the logger
24 | logger.addHandler(handler)
25 | cached_file_loggers[name] = logger
26 | return logger
--------------------------------------------------------------------------------
/farbox_bucket/utils/mail/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
--------------------------------------------------------------------------------
/farbox_bucket/utils/mail/basic_utils.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | from farbox_bucket.utils import email_re, string_types
4 |
5 | def pure_email_address(address, check=False):
6 | #name -> xxxx & 小写处理
7 | if not address:
8 | return
9 | if isinstance(address, (list, tuple)) and len(address) == 1:
10 | address = address[0]
11 | if isinstance(address, string_types):
12 | address = address.split('<', 1)[-1].strip('<>').strip().lower()
13 | address = address.replace('%40', '@') # for URL
14 | if check:
15 | if not is_email_address(address):
16 | return
17 | return address
18 |
19 |
20 | def is_email_address(email):
21 | if isinstance(email, string_types):
22 | email = email.strip()
23 | if email:
24 | return bool(email_re.match(email))
25 | return False
26 |
27 |
28 | def get_valid_addresses(addresses, max_size=None):
29 | if isinstance(addresses, string_types): # 单一的一个邮箱地址
30 | return pure_email_address(addresses)
31 | if not isinstance(addresses, (tuple, list)): # 不支持的类型
32 | return []
33 | result = []
34 | for address in addresses:
35 | if is_email_address(address):
36 | address = pure_email_address(address)
37 | if address not in result:
38 | result.append(address)
39 | if max_size and isinstance(max_size, int):
40 | result = result[:max_size]
41 | return result
42 |
43 |
44 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/mail/system.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | import datetime
3 | from farbox_bucket.settings import SES_ID, SES_KEY, SES_SENDER
4 | from farbox_bucket.utils.ssdb_utils import qpush_back
5 | from .utils import send_email_by_amazon
6 |
7 |
8 |
9 |
10 | def send_mail_by_system(to_address, content, subject=None, raw=False):
11 | if not SES_KEY or not SES_ID:
12 | return False
13 | if len(content) > 1024*1024: # 内容过大了
14 | return False
15 | ses_id, ses_key = SES_ID, SES_KEY
16 | message_id = send_email_by_amazon(to_address=to_address, content=content, subject=subject, raw=raw,
17 | from_address=SES_SENDER, ses_id = ses_id, ses_key=ses_key)
18 | if not message_id:
19 | return False
20 | else:
21 | log_doc = dict(
22 | message_id = message_id,
23 | to_address = to_address,
24 | sent_at = datetime.datetime.utcnow(),
25 | subject = subject,
26 | raw = raw,
27 | content = content,
28 | )
29 | qpush_back('_system_mail_sender', log_doc) # 记录日志
30 | return True
31 |
32 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/md_related/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/utils/md_related/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/utils/memcache_block.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from farbox_bucket.utils.memcache import cache_client
3 |
4 |
5 |
6 | def is_blocked(block_id, ttl=60):
7 | cache_key = "mblock_%s" % block_id
8 | if cache_client.get(cache_key):
9 | return True
10 | else:
11 | cache_client.set(cache_key, "y", expiration=ttl)
12 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/monkey/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/monkey/http.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from httplib import HTTPConnection
3 | from urllib3 import PoolManager
4 |
5 | _get_response = HTTPConnection.getresponse
6 | _pool_manager_init = PoolManager.__init__
7 |
8 | def http_connection_get_response(self, buffering=False):
9 | response = _get_response(self, buffering)
10 | if response.status == 206: # 不是200, 像Dropbox的API就会报错
11 | response.status = 200
12 | return response
13 |
14 |
15 | def pool_manger_init(self, num_pools=10, headers=None, **connection_pool_kw):
16 | connection_pool_kw['block'] = True
17 | connection_pool_kw['maxsize'] = 500
18 | _pool_manager_init(self, num_pools, headers, **connection_pool_kw)
19 |
20 |
21 | PoolManager.__init__ = pool_manger_init
22 | HTTPConnection.getresponse = http_connection_get_response
23 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/pay/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hepochen/FarBox/daeda4f5080467f1ddf4b60424b8562f914756bd/farbox_bucket/utils/pay/__init__.py
--------------------------------------------------------------------------------
/farbox_bucket/utils/simple_encrypt.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | import base64
4 | from Crypto.Cipher import DES
5 | from farbox_bucket.utils import to_bytes
6 |
7 |
8 | def simple_encrypt(key, text):
9 | key = key[:8]
10 | text = to_bytes(text)
11 | des = DES.new(key, DES.MODE_ECB)
12 | reminder = len(text)%8
13 | if reminder == 0: # pad 8 bytes
14 | text += '\x08'*8
15 | else:
16 | text += chr(8-reminder) * (8-reminder)
17 | return base64.b64encode(des.encrypt(text))
18 |
19 |
20 | def simple_decrypt(key,text):
21 | key = key[:8]
22 | text = base64.b64decode(text)
23 | des = DES.new(key, DES.MODE_ECB)
24 | text = des.decrypt(text)
25 | pad = ord(text[-1])
26 | if pad == '\x08':
27 | return text[:-8]
28 | return text[:-pad]
29 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/system_status_recorder.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 | from __future__ import absolute_import
3 | from farbox_bucket.utils.ssdb_utils import hset, hget, hscan
4 | import datetime
5 | import time
6 |
7 |
8 |
9 |
10 | class record_system_timed_status(object):
11 | """
12 | @record_system_timed_status(field='??')
13 | """
14 | def __init__(self, field):
15 | self.field = field
16 |
17 | def __call__(self, func):
18 | def _func(*args, **kwargs):
19 | t1 = time.time()
20 | result = func(*args, **kwargs)
21 | try:
22 | seconds_cost = str(time.time() - t1)
23 | key = '%s_%s' % (int(t1*1000), self.field)
24 | hset('_system_recorder', key=key, value=seconds_cost)
25 | except:
26 | pass
27 | return result
28 | return _func
29 |
30 |
31 |
32 | def get_system_timed_records():
33 | raw_records = hscan('_system_recorder', limit=1000, reverse_scan=True)
34 | records = []
35 | for record_id, seconds_cost in raw_records:
36 | if '_' not in record_id:
37 | continue
38 | timestamp, action_name = record_id.split('_', 1)
39 | try:
40 | timestamp = int(timestamp)/1000.
41 | except:
42 | continue
43 | date = datetime.datetime.utcfromtimestamp(timestamp)
44 | date = date.strftime('%Y-%m-%d %H:%M:%S')
45 | record = '%s UTC %s costs %s' % (date, action_name, seconds_cost)
46 | records.append(record)
47 | return records
48 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/web_utils/__init__.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/web_utils/request.py:
--------------------------------------------------------------------------------
1 | # coding: utf8
2 |
3 |
4 | def to_per_page(per_page, new_per_page=None, min_per_page=1, max_per_page=1000):
5 | if new_per_page:
6 | # 如果有设定 new_per_page, 会尝试以其为高优先级
7 | try: per_page = int(new_per_page)
8 | except: pass
9 | if per_page < min_per_page:
10 | per_page = min_per_page
11 | if per_page > max_per_page:
12 | per_page = max_per_page
13 | return per_page
14 |
--------------------------------------------------------------------------------
/farbox_bucket/utils/web_utils/response.py:
--------------------------------------------------------------------------------
1 | #coding: utf8
2 | from __future__ import absolute_import
3 | from flask import make_response, Response
4 | from farbox_bucket.utils.data import json_dumps
5 |
6 | STATUS_MESSAGES = {
7 | 200: 'ok',
8 | 500: 'Server Error',
9 | 503: 'Wait for a Moment, and Try Again.',
10 | 400: 'Bad Request',
11 | 401: 'Auth error.',
12 | 404: 'Page not Found or this Request is not Allowed',
13 | }
14 |
15 |
16 | def jsonify(data):
17 | try:
18 | data = json_dumps(data, indent=4)
19 | except:
20 | data = json_dumps(dict(error='json_error'))
21 | response = Response(data, mimetype='application/json')
22 | return response
23 |
24 |
25 |
26 | def json_with_status_code(code, message=''):
27 | message = message or STATUS_MESSAGES.get(code, '')
28 | result = dict(code=code, message=message)
29 | response = make_response(jsonify(result))
30 | response.status_code = code
31 | return response
32 |
--------------------------------------------------------------------------------