├── .dockerignore ├── .gitattributes ├── .github └── workflows │ └── dockerimage.yml ├── .gitignore ├── Dockerfile ├── Dockerfile-slim ├── LICENSE ├── README.md ├── apps ├── api │ ├── __init__.py │ ├── permissions.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── blog │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── context_processors.py │ ├── feeds.py │ ├── management │ │ └── commands │ │ │ └── clear_cache.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_article_is_publish.py │ │ ├── 0003_auto_20230702_1043.py │ │ ├── 0004_auto_20230702_1134.py │ │ ├── 0005_auto_20230702_1623.py │ │ ├── 0006_auto_20230708_0641.py │ │ ├── 0007_auto_20230709_1237.py │ │ ├── 0008_auto_20230710_1613.py │ │ ├── 0009_auto_20230713_1223.py │ │ ├── 0010_auto_20230715_1407.py │ │ ├── 0011_auto_20230715_1443.py │ │ ├── 0012_auto_20230727_1929.py │ │ ├── 0013_articleview.py │ │ ├── 0014_auto_20231208_1310.py │ │ ├── 0015_pageview.py │ │ ├── 0016_pageview_is_compute.py │ │ ├── 0017_feedhub.py │ │ ├── 0018_auto_20240101_1903.py │ │ ├── 0019_menulink.py │ │ ├── 0020_auto_20240409_1309.py │ │ └── __init__.py │ ├── models.py │ ├── search_indexes.py │ ├── signals.py │ ├── sitemaps.py │ ├── static │ │ └── blog │ │ │ ├── bootstrap │ │ │ ├── 3.0.2 │ │ │ │ └── css │ │ │ │ │ └── bootstrap.min.css │ │ │ ├── 3.3.1 │ │ │ │ └── js │ │ │ │ │ └── bootstrap.min.js │ │ │ ├── 3.3.7 │ │ │ │ ├── css │ │ │ │ │ └── bootstrap.min.css │ │ │ │ ├── fonts │ │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ │ └── js │ │ │ │ │ └── bootstrap.min.js │ │ │ └── 4.3.1 │ │ │ │ ├── css │ │ │ │ └── bootstrap.min.css │ │ │ │ └── js │ │ │ │ └── bootstrap.min.js │ │ │ ├── css │ │ │ ├── account.css │ │ │ ├── base.css │ │ │ ├── detail.css │ │ │ ├── monokai-2.css │ │ │ ├── monokai.css │ │ │ ├── night.css │ │ │ └── timeline.css │ │ │ ├── font-awesome │ │ │ └── 4.7.0 │ │ │ │ ├── css │ │ │ │ └── font-awesome.min.css │ │ │ │ └── fonts │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ ├── img │ │ │ ├── 404.png │ │ │ ├── TOP.png │ │ │ ├── baidu-2.png │ │ │ ├── blog.png │ │ │ ├── chrome.png │ │ │ ├── docker.png │ │ │ ├── favicon.ico │ │ │ ├── friend.png │ │ │ ├── github.png │ │ │ ├── html.png │ │ │ ├── map.png │ │ │ ├── nav-logo.png │ │ │ ├── regex.png │ │ │ ├── reward_wx.png │ │ │ ├── reward_zfb.png │ │ │ ├── rss.png │ │ │ ├── summary.png │ │ │ ├── toggle-dark.png │ │ │ ├── toggle-light.png │ │ │ └── word-cloud.png │ │ │ ├── js │ │ │ ├── article.js │ │ │ ├── base.js │ │ │ ├── code.js │ │ │ ├── echarts │ │ │ │ └── 5.4.3 │ │ │ │ │ └── echarts.min.js │ │ │ ├── headroom.min.js │ │ │ ├── html5shiv │ │ │ │ └── 3.7.2 │ │ │ │ │ └── html5shiv.min.js │ │ │ ├── jq │ │ │ │ ├── 1.11.1 │ │ │ │ │ └── jquery.min.js │ │ │ │ └── 3.3.1 │ │ │ │ │ └── jquery.min.js │ │ │ ├── js.cookie.min.js │ │ │ ├── popper.min.js │ │ │ └── respond │ │ │ │ └── 1.4.2 │ │ │ │ └── respond.min.js │ │ │ └── simplemde │ │ │ └── 1.11.2 │ │ │ ├── simplemde.min.css │ │ │ └── simplemde.min.js │ ├── templates │ │ └── blog │ │ │ ├── about.html │ │ │ ├── archive.html │ │ │ ├── articleEdit.html │ │ │ ├── base.html │ │ │ ├── category.html │ │ │ ├── dashboard.html │ │ │ ├── detail.html │ │ │ ├── feedhub.html │ │ │ ├── friend.html │ │ │ ├── friendAdd.html │ │ │ ├── index.html │ │ │ ├── silian.xml │ │ │ ├── subject.html │ │ │ ├── subjectDetail.html │ │ │ ├── subjectIndex.html │ │ │ ├── tag.html │ │ │ ├── tags │ │ │ ├── article_list.html │ │ │ ├── base_right.html │ │ │ ├── carousel.html │ │ │ ├── menulink.html │ │ │ ├── navbar.html │ │ │ ├── pagecut.html │ │ │ └── reward.html │ │ │ └── timeline.html │ ├── templatetags │ │ ├── __init__.py │ │ ├── blog_tags.py │ │ └── dashboard.py │ ├── tests.py │ ├── urls.py │ ├── utils.py │ ├── views.py │ └── whoosh_cn_backend.py ├── comment │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_systemnotification.py │ │ ├── 0003_auto_20230708_0641.py │ │ └── __init__.py │ ├── models.py │ ├── signals.py │ ├── static │ │ └── comment │ │ │ ├── css │ │ │ ├── base_comment.css │ │ │ └── notification.css │ │ │ ├── emoji │ │ │ ├── +1.png │ │ │ ├── angry.png │ │ │ ├── anguished.png │ │ │ ├── blush.png │ │ │ ├── broken_heart.png │ │ │ ├── clap.png │ │ │ ├── cold_sweat.png │ │ │ ├── confounded.png │ │ │ ├── cry.png │ │ │ ├── disappointed_relieved.png │ │ │ ├── dizzy_face.png │ │ │ ├── dog.png │ │ │ ├── fearful.png │ │ │ ├── fist.png │ │ │ ├── flushed.png │ │ │ ├── frowning.png │ │ │ ├── grin.png │ │ │ ├── heart.png │ │ │ ├── heart_eyes.png │ │ │ ├── heartbeat.png │ │ │ ├── hushed.png │ │ │ ├── innocent.png │ │ │ ├── joy.png │ │ │ ├── kissing_closed_eyes.png │ │ │ ├── kissing_heart.png │ │ │ ├── mask.png │ │ │ ├── no_mouth.png │ │ │ ├── pensive.png │ │ │ ├── persevere.png │ │ │ ├── pray.png │ │ │ ├── relieved.png │ │ │ ├── scream.png │ │ │ ├── sleepy.png │ │ │ ├── smile.png │ │ │ ├── smiley.png │ │ │ ├── smirk.png │ │ │ ├── sob.png │ │ │ ├── sparkling_heart.png │ │ │ ├── stuck_out_tongue.png │ │ │ ├── stuck_out_tongue_closed_eyes.png │ │ │ ├── stuck_out_tongue_winking_eye.png │ │ │ ├── sunglasses.png │ │ │ ├── sweat.png │ │ │ ├── sweat_smile.png │ │ │ ├── unamused.png │ │ │ ├── v.png │ │ │ ├── worried.png │ │ │ └── yum.png │ │ │ ├── js │ │ │ ├── activate-power.js │ │ │ ├── editor.js │ │ │ └── notification.js │ │ │ └── weibo │ │ │ ├── aini_org.png │ │ │ ├── baibai_thumb.png │ │ │ ├── baobao_thumb.png │ │ │ ├── beishang_org.png │ │ │ ├── bingbujiandan_thumb.png │ │ │ ├── bishi_org.png │ │ │ ├── bizui_org.png │ │ │ ├── chanzui_org.png │ │ │ ├── chigua_thumb.png │ │ │ ├── chongjing_org.png │ │ │ ├── dahaqian_org.png │ │ │ ├── dalian_org.png │ │ │ ├── ding_org.png │ │ │ ├── doge02_org.png │ │ │ ├── erha_org.png │ │ │ ├── gui_org.png │ │ │ ├── guzhang_thumb.png │ │ │ ├── haha_thumb.png │ │ │ ├── heng_thumb.png │ │ │ ├── huaixiao_org.png │ │ │ ├── huaxin_org.png │ │ │ ├── jiyan_org.png │ │ │ ├── kelian_org.png │ │ │ ├── ku_org.png │ │ │ ├── kuxiao_org.png │ │ │ ├── leimu_org.png │ │ │ ├── miaomiao_thumb.png │ │ │ ├── ningwen_org.png │ │ │ ├── nu_thumb.png │ │ │ ├── qian_thumb.png │ │ │ ├── sikao_org.png │ │ │ ├── taikaixin_org.png │ │ │ ├── tanshou_org.png │ │ │ ├── tianping_thumb.png │ │ │ ├── touxiao_org.png │ │ │ ├── tu_org.png │ │ │ ├── wabi_thumb.png │ │ │ ├── weiqu_thumb.png │ │ │ ├── wenhao_thumb.png │ │ │ ├── wosuanle_thumb.png │ │ │ ├── wu_thumb.png │ │ │ ├── xiaoerbuyu_org.png │ │ │ ├── xiaoku_thumb.png │ │ │ ├── xixi_thumb.png │ │ │ ├── yinxian_org.png │ │ │ ├── yun_thumb.png │ │ │ ├── zhouma_thumb.png │ │ │ └── zhuakuang_org.png │ ├── templates │ │ └── comment │ │ │ ├── comment_form.html │ │ │ ├── comment_list.html │ │ │ └── notification.html │ ├── templatetags │ │ ├── __init__.py │ │ └── comment_tags.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── easytask │ ├── __init__.py │ ├── actions.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tasks.py │ ├── tests.py │ ├── utils.py │ └── views.py ├── monitor │ ├── __init__.py │ ├── actions.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_monitorserver_active.py │ │ ├── 0003_monitorserver_alarm.py │ │ └── __init__.py │ ├── models.py │ ├── static │ │ └── monitor │ │ │ ├── css │ │ │ └── monitor.css │ │ │ ├── img │ │ │ ├── DSM.svg │ │ │ ├── centos.svg │ │ │ ├── debian.svg │ │ │ ├── linux.svg │ │ │ ├── mac-os.svg │ │ │ ├── redhat.svg │ │ │ ├── ubuntu.svg │ │ │ └── windows.svg │ │ │ └── js │ │ │ └── monitor.js │ ├── templates │ │ └── monitor │ │ │ ├── base.html │ │ │ ├── demo.html │ │ │ └── index.html │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── oauth │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── forms.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_auto_20230423_1145.py │ │ ├── 0003_auto_20230709_1237.py │ │ └── __init__.py │ ├── models.py │ ├── signals.py │ ├── templates │ │ └── oauth │ │ │ ├── change_profile.html │ │ │ ├── profile.html │ │ │ └── tags │ │ │ └── user_avatar.html │ ├── templatetags │ │ ├── __init__.py │ │ └── oauth_tags.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── portinfo │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── management │ │ └── commands │ │ │ ├── load_initial_data.py │ │ │ └── ports.json │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_auto_20240615_1412.py │ │ └── __init__.py │ ├── models.py │ ├── static │ │ └── portinfo │ │ │ ├── css │ │ │ └── dataTables.bootstrap4.min.css │ │ │ └── js │ │ │ ├── dataTables.bootstrap4.min.js │ │ │ └── dataTables.min.js │ ├── templates │ │ └── portinfo │ │ │ └── index.html │ ├── tests.py │ ├── urls.py │ └── views.py ├── resume │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ ├── models.py │ ├── static │ │ └── resume │ │ │ └── css │ │ │ └── detail.css │ ├── templates │ │ └── resume │ │ │ ├── base.html │ │ │ └── detail.html │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── rsshub │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── templates │ │ └── rsshub │ │ │ └── rss.xml │ ├── templatetags │ │ └── __init__.py │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py └── tool │ ├── __init__.py │ ├── admin.py │ ├── apis │ ├── __init__.py │ ├── bd_push.py │ ├── common.py │ ├── docker_search.py │ ├── stopwords │ │ └── ChineseStopWords.txt │ ├── useragent.py │ └── word_cloud.py │ ├── apps.py │ ├── migrations │ ├── 0001_initial.py │ └── __init__.py │ ├── models.py │ ├── static │ ├── editor │ │ ├── css │ │ │ └── editormd.min.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── editormd-logo.eot │ │ │ ├── editormd-logo.svg │ │ │ ├── editormd-logo.ttf │ │ │ ├── editormd-logo.woff │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ ├── images │ │ │ ├── loading.gif │ │ │ ├── loading@2x.gif │ │ │ └── logos │ │ │ │ ├── editormd-favicon-16x16.ico │ │ │ │ └── editormd-logo-96x96.png │ │ ├── js │ │ │ └── editormd.min.js │ │ ├── languages │ │ │ ├── en.js │ │ │ └── zh-tw.js │ │ ├── lib │ │ │ ├── codemirror │ │ │ │ ├── AUTHORS │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── addon │ │ │ │ │ ├── dialog │ │ │ │ │ │ ├── dialog.css │ │ │ │ │ │ └── dialog.js │ │ │ │ │ └── search │ │ │ │ │ │ ├── match-highlighter.js │ │ │ │ │ │ ├── matchesonscrollbar.css │ │ │ │ │ │ ├── matchesonscrollbar.js │ │ │ │ │ │ ├── search.js │ │ │ │ │ │ └── searchcursor.js │ │ │ │ ├── addons.min.js │ │ │ │ ├── bower.json │ │ │ │ ├── codemirror.min.css │ │ │ │ ├── codemirror.min.js │ │ │ │ ├── lib │ │ │ │ │ ├── codemirror.css │ │ │ │ │ └── codemirror.js │ │ │ │ ├── modes.min.js │ │ │ │ └── package.json │ │ │ ├── marked.min.js │ │ │ └── prettify.min.js │ │ └── plugins │ │ │ ├── code-block-dialog │ │ │ └── code-block-dialog.js │ │ │ ├── emoji-dialog │ │ │ ├── emoji-dialog.js │ │ │ └── emoji.json │ │ │ ├── goto-line-dialog │ │ │ └── goto-line-dialog.js │ │ │ ├── help-dialog │ │ │ ├── help-dialog.js │ │ │ └── help.md │ │ │ ├── html-entities-dialog │ │ │ ├── html-entities-dialog.js │ │ │ └── html-entities.json │ │ │ ├── image-dialog │ │ │ └── image-dialog.js │ │ │ ├── link-dialog │ │ │ └── link-dialog.js │ │ │ ├── preformatted-text-dialog │ │ │ └── preformatted-text-dialog.js │ │ │ ├── reference-link-dialog │ │ │ └── reference-link-dialog.js │ │ │ ├── table-dialog │ │ │ └── table-dialog.js │ │ │ └── test-plugin │ │ │ └── test-plugin.js │ └── tool │ │ ├── css │ │ ├── json2go │ │ │ ├── common.css │ │ │ └── tomorrow.highlight.css │ │ └── tool.css │ │ ├── img │ │ ├── HTML5.png │ │ ├── go.ico │ │ ├── golang.png │ │ ├── linux.png │ │ ├── query_ip.png │ │ └── tax128.png │ │ └── js │ │ ├── json2go │ │ ├── common.js │ │ ├── gofmt.js │ │ ├── highlight.min.js │ │ └── json-to-go.js │ │ ├── tax │ │ └── tax.js │ │ └── tool.js │ ├── templates │ └── tool │ │ ├── base_tool.html │ │ ├── bd_push.html │ │ ├── bd_push_site.html │ │ ├── characters.html │ │ ├── docker_search.html │ │ ├── editor.html │ │ ├── json2go.html │ │ ├── linux_timeline.html │ │ ├── query_ip.html │ │ ├── regex.html │ │ ├── tags │ │ ├── github_corners.html │ │ ├── ldt.html │ │ ├── tool_item.html │ │ └── tool_list.html │ │ ├── tax.html │ │ ├── tool.html │ │ ├── useragent.html │ │ └── word_cloud.html │ ├── templatetags │ ├── __init__.py │ └── tool_tags.py │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── izone ├── __init__.py ├── celery.py ├── settings.py ├── urls.py └── wsgi.py ├── log └── .gitkeep ├── manage.py ├── media ├── article │ └── default │ │ └── default.png ├── avatar │ └── default │ │ ├── default.png │ │ ├── default1.png │ │ ├── default10.png │ │ ├── default2.png │ │ ├── default3.png │ │ ├── default4.png │ │ ├── default5.png │ │ ├── default6.png │ │ ├── default7.png │ │ ├── default8.png │ │ └── default9.png ├── friend │ └── default │ │ └── default.png └── subject │ └── default │ └── default.png ├── requirements.txt ├── supervisord.conf ├── templates ├── 403.html ├── 404.html ├── 500.html ├── account │ ├── account_inactive.html │ ├── base.html │ ├── email.html │ ├── email │ │ └── password_reset_key_message.txt │ ├── email_confirm.html │ ├── login.html │ ├── logout.html │ ├── password_change.html │ ├── password_reset.html │ ├── password_reset_done.html │ ├── password_reset_from_key.html │ ├── password_reset_from_key_done.html │ ├── password_set.html │ ├── signup.html │ ├── signup_closed.html │ ├── verification_sent.html │ └── verified_email_required.html ├── admin │ └── base.html ├── robots.txt ├── search │ ├── blog │ │ └── search.html │ └── indexes │ │ └── blog │ │ └── article_text.txt └── webstack │ ├── base.html │ └── index.html └── utils ├── __init__.py └── markdown_ext.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=python 2 | *.css linguist-language=python 3 | *.html linguist-language=python -------------------------------------------------------------------------------- /.github/workflows/dockerimage.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Build the Docker image 13 | run: docker build -f ./Dockerfile-slim -t izone-master:$(date +%s) . 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # 忽略网站个人信息,这些信息需要单独设置,不共享 98 | .idea 99 | whoosh_index/ 100 | *.env 101 | # 禁用上传目录 102 | upload/ 103 | 104 | # jieba 105 | .DS_Store 106 | 107 | # celery 108 | *.pid 109 | 110 | # templates test html 111 | templates/test*.html 112 | 113 | # log 114 | log/*.log* -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | # 国内用户构建命令参考 4 | # DOCKER_BUILDKIT=0 docker build --build-arg pip_index_url=http://mirrors.aliyun.com/pypi/simple/ --build-arg pip_trusted_host=mirrors.aliyun.com -t hopetree/izone:lts . 5 | 6 | ARG pip_index_url=https://pypi.org/simple 7 | ARG pip_trusted_host=pypi.org 8 | ENV PYTHONUNBUFFERED=1 9 | WORKDIR /opt/cloud/izone 10 | 11 | RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 12 | COPY requirements.txt requirements.txt 13 | RUN pip install --no-cache-dir setuptools==68.0.0 --index-url $pip_index_url --trusted-host $pip_trusted_host 14 | RUN pip install --no-cache-dir -r requirements.txt --index-url $pip_index_url --trusted-host $pip_trusted_host 15 | RUN mkdir -p log && chmod -R 755 log 16 | 17 | COPY . . 18 | 19 | # 设置镜像的创建时间,当做网站更新时间 20 | RUN sed -i "s/web_update_time=\"\"/web_update_time=\"$(date +'%Y-%m-%d %H:%M')\"/g" ./apps/blog/templates/blog/base.html 21 | 22 | CMD ["supervisord", "-n", "-c", "supervisord.conf"] 23 | -------------------------------------------------------------------------------- /Dockerfile-slim: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | # 国内用户构建命令参考 4 | # DOCKER_BUILDKIT=0 docker build --build-arg pip_index_url=http://mirrors.aliyun.com/pypi/simple/ --build-arg pip_trusted_host=mirrors.aliyun.com --build-arg debian_host=mirrors.ustc.edu.cn -f Dockerfile-slim -t hopetree/izone:lts . 5 | 6 | # 默认的系统源和pypi源都使用国外的,国内构建的时候可以用命令行参数替换成国内源 7 | ARG debian_host=deb.debian.org 8 | ARG pip_index_url=https://pypi.org/simple 9 | ARG pip_trusted_host=pypi.org 10 | 11 | 12 | ENV PYTHONUNBUFFERED=1 13 | WORKDIR /opt/cloud/izone 14 | 15 | # 替换系统源,要注意这里不同版本的debian源文件不同 16 | RUN sed -i "s/deb.debian.org/${debian_host}/g" /etc/apt/sources.list.d/debian.sources 17 | 18 | # 安装sqlclient的依赖,slim镜像中缺少 19 | RUN apt-get update && apt-get install -y \ 20 | default-libmysqlclient-dev \ 21 | build-essential \ 22 | && rm -rf /var/lib/apt/lists/* 23 | 24 | RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 25 | COPY requirements.txt requirements.txt 26 | RUN pip install --no-cache-dir setuptools==68.0.0 --index-url $pip_index_url --trusted-host $pip_trusted_host 27 | RUN pip install --no-cache-dir -r requirements.txt --index-url $pip_index_url --trusted-host $pip_trusted_host 28 | RUN mkdir -p log && chmod -R 755 log 29 | 30 | COPY . . 31 | 32 | # 设置镜像的创建时间,当做网站更新时间 33 | RUN sed -i "s/web_update_time=\"\"/web_update_time=\"$(date +'%Y-%m-%d %H:%M')\"/g" ./apps/blog/templates/blog/base.html 34 | 35 | CMD ["supervisord", "-n", "-c", "supervisord.conf"] 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Hopetree 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 一个以 Django 作为框架搭建的个人博客。 2 | 3 | 博客效果: https://tendcode.com/ 4 | 5 | ## 功能介绍 6 | - Django 自带的后台管理系统,方便对于文章、用户及其他动态内容的管理 7 | - 文章分类、标签、浏览量统计以及规范的 SEO 设置 8 | - 用户认证系统,在 Django 自带的用户系统的基础上扩展 Oauth 认证,支持微博、Github 等第三方认证 9 | - 文章评论系统,炫酷的输入框特效,支持 markdown 语法,二级评论结构和回复功能 10 | - 信息提醒功能,登录和退出提醒,收到评论和回复提醒,信息管理 11 | - 强大的全文搜索功能,只需要输入关键词就能展现全站与之关联的文章 12 | - RSS 博客订阅功能及规范的 Sitemap 网站地图 13 | - 实用的在线工具 14 | - 友情链接和推荐工具网站的展示 15 | - 缓存系统,遵循缓存原则,加速网站打开速度 16 | - RESTful API 风格的 API 接口 17 | 18 | ## 博客页面效果(响应式) 19 | - PC 页面效果 20 | 21 | ![PC首页](https://github.com/Hopetree/izone/assets/30201215/e221d09b-9921-4707-977d-95c263d282b6) 22 | 23 | - PC 暗色主题效果 24 | 25 | ![PC首页暗色主题](https://github.com/Hopetree/izone/assets/30201215/ca505bfc-e5d0-40a1-b501-946975c03f73) 26 | 27 | - PC 文章详情页,左边显示专题目录,右边显示文章目录,支持代码高亮 28 | 29 | ![PC文章页面](https://github.com/Hopetree/izone/assets/30201215/0c219bbd-6f29-4866-a827-6e98536f689a) 30 | 31 | - PC 专题页,按文章归类 32 | 33 | ![PC 专题页,按文章归类](https://github.com/Hopetree/izone/assets/30201215/c0a828cc-2201-438b-a983-0c6c04a429c4) 34 | 35 | - 云监控服务,提供服务器的监控能力,客户端提供 Golang 版本,也可以自行编写 Python 版本的客户端用来上报数据 36 | 37 | ![20240404_232431 (1)](https://github.com/Hopetree/izone/assets/30201215/038200c3-1ada-4ab2-9ac5-42848a80ee21) 38 | 39 | - PC 友情链接页,定时任务自动校验网址有效性 40 | 41 | ![PC 友情链接页](https://github.com/Hopetree/izone/assets/30201215/033cdd61-75cf-41b4-bb45-9b45948daf3a) 42 | 43 | - PC 在线工具,平台自带工具 44 | 45 | ![PC 在线工具](https://github.com/Hopetree/izone/assets/30201215/8336fd89-916b-49e5-94f2-a5a72e990158) 46 | 47 | - ipad 效果 48 | 49 | ![ipad](https://user-images.githubusercontent.com/30201215/60588800-7e558800-9dca-11e9-8beb-5d2dcf01b869.jpg) 50 | 51 | - 手机效果 52 | 53 | ![iphone](https://user-images.githubusercontent.com/30201215/60588832-8e6d6780-9dca-11e9-84fa-f1d71510c81e.jpg) 54 | 55 | ## 运行指导 56 | - 由于本项目分为几个不同的分支,每个分支的功能是一样的,但是运行的方式不同,所以需要根据分支查看对应的运行wiki 57 | - 指导 wiki:https://github.com/Hopetree/izone/wiki 58 | - 部署指导完整步骤:https://tendcode.com/subject/article/izone-install-docs/ 59 | -------------------------------------------------------------------------------- /apps/api/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- -------------------------------------------------------------------------------- /apps/api/permissions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import permissions 3 | 4 | 5 | class IsAdminUserOrReadOnly(permissions.BasePermission): 6 | def has_permission(self, request, view): 7 | if request.method in permissions.SAFE_METHODS: 8 | return True 9 | return request.user and request.user.is_staff -------------------------------------------------------------------------------- /apps/api/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from oauth.models import Ouser 3 | from rest_framework import serializers 4 | from blog.models import Article, Tag, Category, Timeline 5 | from tool.models import ToolLink, ToolCategory 6 | 7 | 8 | class UserSerializer(serializers.ModelSerializer): 9 | class Meta: 10 | model = Ouser 11 | fields = ('id', 'username', 'first_name', 'link', 'avatar') 12 | # fields = '__all__' 13 | # exclude = ('password','email') 14 | 15 | 16 | class TagSerializer(serializers.ModelSerializer): 17 | class Meta: 18 | model = Tag 19 | fields = '__all__' 20 | 21 | 22 | class CategorySerializer(serializers.ModelSerializer): 23 | class Meta: 24 | model = Category 25 | fields = '__all__' 26 | 27 | 28 | class ArticleSerializer(serializers.ModelSerializer): 29 | author = serializers.ReadOnlyField(source='author.username') 30 | category = CategorySerializer(read_only=True) 31 | tags = TagSerializer( 32 | many=True, 33 | read_only=True, 34 | ) 35 | keywords = serializers.SlugRelatedField( 36 | many=True, 37 | read_only=True, 38 | slug_field='name' 39 | ) 40 | 41 | class Meta: 42 | model = Article 43 | # fields = ('id', 'author', 'title', 'views', 'category', 'tags') 44 | # fields = '__all__' 45 | exclude = ('body',) 46 | 47 | 48 | class TimelineSerializer(serializers.ModelSerializer): 49 | class Meta: 50 | model = Timeline 51 | fields = '__all__' 52 | 53 | 54 | class ToolCategorySerializer(serializers.ModelSerializer): 55 | class Meta: 56 | model = ToolCategory 57 | fields = '__all__' 58 | 59 | 60 | class ToolLinkSerializer(serializers.ModelSerializer): 61 | category = ToolCategorySerializer() 62 | 63 | class Meta: 64 | model = ToolLink 65 | fields = '__all__' 66 | -------------------------------------------------------------------------------- /apps/api/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | # @Date : 2019/2/1 3 | 4 | from rest_framework.routers import DefaultRouter 5 | from .views import (UserListSet, ArticleListSet, TagListSet, 6 | CategoryListSet, TimelineListSet, ToolLinkListSet) 7 | 8 | router = DefaultRouter() 9 | router.register(r'users', UserListSet) 10 | router.register(r'articles', ArticleListSet) 11 | router.register(r'tags', TagListSet) 12 | router.register(r'categorys', CategoryListSet) 13 | router.register(r'timelines', TimelineListSet) 14 | router.register(r'toollinks', ToolLinkListSet) 15 | -------------------------------------------------------------------------------- /apps/api/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | from oauth.models import Ouser 5 | from blog.models import Article, Tag, Category, Timeline 6 | from tool.models import ToolLink 7 | from .serializers import (UserSerializer, ArticleSerializer, 8 | TimelineSerializer,TagSerializer,CategorySerializer,ToolLinkSerializer) 9 | from rest_framework import viewsets, permissions 10 | from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly 11 | # from .permissions import IsAdminUserOrReadOnly 12 | 13 | # RESEful API VIEWS 14 | class UserListSet(viewsets.ModelViewSet): 15 | queryset = Ouser.objects.all() 16 | serializer_class = UserSerializer 17 | permission_classes = (DjangoModelPermissionsOrAnonReadOnly,) 18 | 19 | class ArticleListSet(viewsets.ModelViewSet): 20 | queryset = Article.objects.all() 21 | serializer_class = ArticleSerializer 22 | permission_classes = (DjangoModelPermissionsOrAnonReadOnly,) 23 | 24 | def perform_create(self,serializer): 25 | serializer.save(author=self.request.user) 26 | 27 | class TagListSet(viewsets.ModelViewSet): 28 | queryset = Tag.objects.all() 29 | serializer_class = TagSerializer 30 | permission_classes = (DjangoModelPermissionsOrAnonReadOnly,) 31 | 32 | class CategoryListSet(viewsets.ModelViewSet): 33 | queryset = Category.objects.all() 34 | serializer_class = CategorySerializer 35 | permission_classes = (DjangoModelPermissionsOrAnonReadOnly,) 36 | 37 | class TimelineListSet(viewsets.ModelViewSet): 38 | queryset = Timeline.objects.all() 39 | serializer_class = TimelineSerializer 40 | permission_classes = (DjangoModelPermissionsOrAnonReadOnly,) 41 | 42 | class ToolLinkListSet(viewsets.ModelViewSet): 43 | queryset = ToolLink.objects.all() 44 | serializer_class = ToolLinkSerializer 45 | permission_classes = (DjangoModelPermissionsOrAnonReadOnly,) -------------------------------------------------------------------------------- /apps/blog/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'blog.apps.BlogConfig' -------------------------------------------------------------------------------- /apps/blog/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class BlogConfig(AppConfig): 5 | name = 'blog' 6 | verbose_name = '博客管理' 7 | 8 | def ready(self): 9 | from . import signals # 导入信号处理程序模块 10 | -------------------------------------------------------------------------------- /apps/blog/context_processors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import datetime 3 | import json 4 | from django.conf import settings 5 | from .utils import (site_full_url, get_site_create_day) 6 | 7 | # 静态文件版本(只收集常改的,不常改的直接在页面改),每次更新了静态文件就更新一下这个版本 8 | # todo 可以做成自动化,每次拉git代码的时候检查是否更新了某个静态文件,自动更新版本 9 | STATIC_VERSION = { 10 | 'css_blog_base': '20240305.02', 11 | 'css_blog_detail': '20240324.01', 12 | 'css_blog_night': '20240615.01', 13 | 14 | 'js_blog_base': '20240305.01', 15 | 'js_blog_article': '20240115.01', 16 | 'js_blog_code': '20240129.02', 17 | 18 | 'css_tool_tool': '20240115.01', 19 | 'js_tool_tool': '20240115.01', 20 | } 21 | 22 | 23 | # 自定义上下文管理器 24 | def settings_info(request): 25 | site_create_day = get_site_create_day(settings.SITE_CREATE_DATE) 26 | return { 27 | 'this_year': datetime.datetime.now().year, 28 | 'site_create_date': site_create_day[0], 29 | 'site_create_year': site_create_day[1], 30 | 'site_logo_name': settings.SITE_LOGO_NAME, 31 | 'site_end_title': settings.SITE_END_TITLE, 32 | 'site_description': settings.SITE_DESCRIPTION, 33 | 'site_keywords': settings.SITE_KEYWORDS, 34 | 'tool_flag': settings.TOOL_FLAG, 35 | 'api_flag': settings.API_FLAG, 36 | 'cnzz_protocol': settings.CNZZ_PROTOCOL, 37 | '51la': settings.LA51_PROTOCOL, 38 | 'beian': settings.BEIAN, 39 | 'my_github': settings.MY_GITHUB, 40 | 'site_verification': settings.MY_SITE_VERIFICATION, 41 | 'site_url': site_full_url(), 42 | 'static_version': STATIC_VERSION, 43 | } 44 | -------------------------------------------------------------------------------- /apps/blog/feeds.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from xml.sax.saxutils import escape 3 | from django.contrib.syndication.views import Feed 4 | from .models import Article 5 | from django.conf import settings 6 | 7 | 8 | class AllArticleRssFeed(Feed): 9 | # 显示在聚会阅读器上的标题 10 | title = settings.SITE_END_TITLE 11 | # 跳转网址,为主页 12 | link = "/" 13 | # 描述内容 14 | description = settings.SITE_DESCRIPTION 15 | 16 | # 需要显示的内容条目,这个可以自己挑选一些热门或者最新的博客 17 | def items(self): 18 | return Article.objects.filter(is_publish=True)[:10] 19 | 20 | # 显示的内容的标题,这个才是最主要的东西 21 | def item_title(self, item): 22 | return item.title 23 | 24 | # 显示的内容的描述 25 | def item_description(self, item): 26 | return item.body_to_markdown() 27 | -------------------------------------------------------------------------------- /apps/blog/management/commands/clear_cache.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from django.core.management.base import BaseCommand 3 | from django.core.cache import cache 4 | 5 | 6 | class Command(BaseCommand): 7 | help = 'Clears cache for specified keys or clears keys like views.*.statistics.* if none provided' 8 | 9 | def add_arguments(self, parser): 10 | parser.add_argument('keys', nargs='*', type=str, help='Keys to clear from cache') 11 | 12 | def handle(self, *args, **options): 13 | keys_to_clear = options['keys'] 14 | 15 | if not keys_to_clear: 16 | # If no keys provided, clear keys matching the pattern 17 | keys_matching_pattern = cache.keys('views.*.statistics.*') 18 | 19 | if keys_matching_pattern: 20 | for key in keys_matching_pattern: 21 | cache.delete(key) 22 | self.stdout.write( 23 | self.style.SUCCESS(f'Cache cleared successfully for key: {key}')) 24 | else: 25 | self.stdout.write(self.style.SUCCESS('No matching keys found to clear')) 26 | else: 27 | # Clear cache for each specified key 28 | for key in keys_to_clear: 29 | cache.delete(key) 30 | self.stdout.write(self.style.SUCCESS(f'Cache cleared successfully for key: {key}')) 31 | -------------------------------------------------------------------------------- /apps/blog/migrations/0002_article_is_publish.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-06-30 13:54 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='article', 15 | name='is_publish', 16 | field=models.BooleanField(default=True, verbose_name='是否发布'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /apps/blog/migrations/0003_auto_20230702_1043.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-02 10:43 2 | 3 | from django.db import migrations 4 | import imagekit.models.fields 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('blog', '0002_article_is_publish'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='friendlink', 16 | name='logo', 17 | field=imagekit.models.fields.ProcessedImageField(blank=True, default='friend/default.png', upload_to='friend/%Y/%m/%d', verbose_name='网站LOGO'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /apps/blog/migrations/0004_auto_20230702_1134.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-02 11:34 2 | 3 | from django.db import migrations 4 | import imagekit.models.fields 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('blog', '0003_auto_20230702_1043'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='friendlink', 16 | name='logo', 17 | field=imagekit.models.fields.ProcessedImageField(blank=True, default='friend/default.png', help_text='上传图片大小建议120x120以上,使用友联域名命名,如tendcode.com.png', upload_to='friend/%Y', verbose_name='网站LOGO'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /apps/blog/migrations/0005_auto_20230702_1623.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-02 16:23 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0004_auto_20230702_1134'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='friendlink', 15 | name='not_show_reason', 16 | field=models.CharField(blank=True, max_length=50, null=True, verbose_name='禁用原因'), 17 | ), 18 | migrations.AlterField( 19 | model_name='friendlink', 20 | name='is_show', 21 | field=models.BooleanField(default=False, verbose_name='是否展示'), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /apps/blog/migrations/0006_auto_20230708_0641.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-08 06:41 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0005_auto_20230702_1623'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterModelOptions( 14 | name='timeline', 15 | options={'ordering': ['-update_date'], 'verbose_name': '时间线', 'verbose_name_plural': '时间线'}, 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /apps/blog/migrations/0007_auto_20230709_1237.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-09 12:37 2 | 3 | from django.db import migrations 4 | import imagekit.models.fields 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('blog', '0006_auto_20230708_0641'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='friendlink', 16 | name='logo', 17 | field=imagekit.models.fields.ProcessedImageField(blank=True, default='friend/default/default.png', help_text='上传图片大小建议120x120以上,使用友联域名命名,如tendcode.com.png', upload_to='friend/upload/%Y', verbose_name='网站LOGO'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /apps/blog/migrations/0008_auto_20230710_1613.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-10 16:13 2 | 3 | from django.db import migrations 4 | import imagekit.models.fields 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('blog', '0007_auto_20230709_1237'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='article', 16 | name='img_link', 17 | field=imagekit.models.fields.ProcessedImageField(blank=True, default='article/default/default.png', help_text='上传图片大小建议使用5:3的宽高比,为了清晰度原始图片宽度应该超过250px', upload_to='article/upload/%Y/%m/%d/', verbose_name='封面图'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /apps/blog/migrations/0009_auto_20230713_1223.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-13 12:23 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0008_auto_20230710_1613'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='category', 15 | name='description', 16 | field=models.TextField(default='分类描述', help_text='用来作为SEO中description,长度参考SEO标准', max_length=240, verbose_name='描述'), 17 | ), 18 | migrations.AlterField( 19 | model_name='tag', 20 | name='description', 21 | field=models.TextField(default='标签描述', help_text='用来作为SEO中description,长度参考SEO标准', max_length=240, verbose_name='描述'), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /apps/blog/migrations/0011_auto_20230715_1443.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-15 14:43 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0010_auto_20230715_1407'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='article', 15 | name='topic_short_title', 16 | field=models.CharField(blank=True, help_text='专门给Topic使用的短标题', max_length=50, null=True, verbose_name='主题短标题'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /apps/blog/migrations/0012_auto_20230727_1929.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-07-27 19:29 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0011_auto_20230715_1443'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterModelOptions( 14 | name='subject', 15 | options={'ordering': ['sort_order'], 'verbose_name': '专题', 'verbose_name_plural': '专题'}, 16 | ), 17 | migrations.AlterModelOptions( 18 | name='topic', 19 | options={'ordering': ['sort_order'], 'verbose_name': '专题-主题', 'verbose_name_plural': '专题-主题'}, 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /apps/blog/migrations/0013_articleview.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-12-08 12:55 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0012_auto_20230727_1929'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='ArticleView', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('date', models.CharField(max_length=10, verbose_name='统计日期')), 18 | ('body', models.TextField(verbose_name='统计数据')), 19 | ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='录入时间')), 20 | ('update_date', models.DateTimeField(auto_now=True, verbose_name='更新时间')), 21 | ], 22 | options={ 23 | 'verbose_name': '文章浏览量统计', 24 | 'verbose_name_plural': '文章浏览量统计', 25 | 'ordering': ['create_date'], 26 | }, 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /apps/blog/migrations/0014_auto_20231208_1310.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-12-08 13:10 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0013_articleview'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='articleview', 15 | name='date', 16 | field=models.CharField(max_length=10, unique=True, verbose_name='统计日期'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /apps/blog/migrations/0015_pageview.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-12-13 11:20 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0014_auto_20231208_1310'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='PageView', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('url', models.CharField(max_length=255, unique=True, verbose_name='页面地址')), 18 | ('name', models.CharField(blank=True, max_length=255, null=True, verbose_name='页面名称')), 19 | ('views', models.IntegerField(default=0, verbose_name='浏览量')), 20 | ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='录入时间')), 21 | ('update_date', models.DateTimeField(auto_now=True, verbose_name='更新时间')), 22 | ], 23 | options={ 24 | 'verbose_name': '单页面浏览量', 25 | 'verbose_name_plural': '单页面浏览量', 26 | 'ordering': ['url'], 27 | }, 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /apps/blog/migrations/0016_pageview_is_compute.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2023-12-14 15:43 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0015_pageview'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='pageview', 15 | name='is_compute', 16 | field=models.BooleanField(default=True, verbose_name='是否计算到访问量'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /apps/blog/migrations/0017_feedhub.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2024-01-01 17:17 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0016_pageview_is_compute'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='FeedHub', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('name', models.CharField(max_length=50, unique=True, verbose_name='名称')), 18 | ('url', models.CharField(max_length=255, verbose_name='feed地址')), 19 | ('icon', models.TextField(help_text='可以填写base64图片格式或者图标地址', verbose_name='图标地址')), 20 | ('is_active', models.BooleanField(default=True, help_text='作为是否采集的标识', verbose_name='是否有效')), 21 | ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='录入时间')), 22 | ('data', models.TextField(blank=True, help_text='定义任务采集数据', null=True, verbose_name='数据')), 23 | ], 24 | options={ 25 | 'verbose_name': 'Feed Hub', 26 | 'verbose_name_plural': 'Feed Hub', 27 | 'ordering': ['name'], 28 | }, 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /apps/blog/migrations/0018_auto_20240101_1903.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2024-01-01 19:03 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0017_feedhub'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterModelOptions( 14 | name='feedhub', 15 | options={'ordering': ['sort_order'], 'verbose_name': 'Feed Hub', 'verbose_name_plural': 'Feed Hub'}, 16 | ), 17 | migrations.AddField( 18 | model_name='feedhub', 19 | name='sort_order', 20 | field=models.IntegerField(default=99, help_text='作为显示的时候的顺序', verbose_name='排序'), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /apps/blog/migrations/0019_menulink.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2024-03-26 09:25 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0018_auto_20240101_1903'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='MenuLink', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('name', models.CharField(help_text='如:Github 主页', max_length=20, unique=True, verbose_name='名称')), 18 | ('icon', models.CharField(help_text='如:fa-github', max_length=20, unique=True, verbose_name='图标')), 19 | ('link', models.CharField(max_length=200, unique=True, verbose_name='链接')), 20 | ('title', models.CharField(help_text='外链的描述', max_length=50, unique=True, verbose_name='标题')), 21 | ('active', models.BooleanField(default=True, help_text='是展示有效的链接', verbose_name='是否有效')), 22 | ('sort_order', models.IntegerField(default=99, help_text='作为显示的时候的顺序', verbose_name='排序')), 23 | ], 24 | options={ 25 | 'verbose_name': '菜单外链', 26 | 'verbose_name_plural': '菜单外链', 27 | 'ordering': ['sort_order'], 28 | }, 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /apps/blog/migrations/0020_auto_20240409_1309.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.28 on 2024-04-09 13:09 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('blog', '0019_menulink'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='carousel', 15 | name='content', 16 | field=models.CharField(blank=True, max_length=80, null=True, verbose_name='描述'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /apps/blog/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/migrations/__init__.py -------------------------------------------------------------------------------- /apps/blog/search_indexes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from haystack import indexes 4 | from .models import Article 5 | 6 | 7 | class ArticleIndex(indexes.SearchIndex, indexes.Indexable): 8 | text = indexes.CharField(document=True, use_template=True) 9 | views = indexes.IntegerField(model_attr='views') 10 | # 添加这个字段,可以在查询的时候作为过滤条件,如果不添加则不能用来过滤,新增字段要重新生成索引 11 | is_publish = indexes.BooleanField(model_attr='is_publish') 12 | 13 | def get_model(self): 14 | return Article 15 | 16 | def index_queryset(self, using=None): 17 | return self.get_model().objects.all() 18 | -------------------------------------------------------------------------------- /apps/blog/signals.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.dispatch import receiver 3 | from django.db.models.signals import post_save 4 | from django.urls import reverse 5 | 6 | from .models import FriendLink 7 | from comment.models import SystemNotification 8 | from oauth.models import Ouser 9 | 10 | 11 | @receiver(post_save, sender=FriendLink) 12 | def friend_link_create_signal(sender, instance, created, **kwargs): 13 | """ 14 | 创建新的友情链接则自带给管理员推送审核消息 15 | @param sender: 16 | @param instance: 17 | @param created: 18 | @param kwargs: 19 | @return: 20 | """ 21 | # 判断是否是第一次生成 22 | if created: 23 | superuser = Ouser.objects.filter(is_superuser=True) 24 | title = f'增加一个新的{instance._meta.verbose_name}:{instance.name}' 25 | admin_url = reverse('admin:blog_friendlink_change', args=[instance.id]) 26 | content = f'

友链地址:{instance.link},' \ 27 | f'描述:{instance.description},待管理员审核!!!

' 28 | new_notify = SystemNotification(title=title, content=content) 29 | new_notify.save() # 保存实例 30 | 31 | # 在保存实例后,将关联对象添加到多对多关系中 32 | new_notify.get_p.set(superuser) 33 | -------------------------------------------------------------------------------- /apps/blog/sitemaps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.contrib.sitemaps import Sitemap 3 | from .models import Article, Category, Tag 4 | from django.db.models.aggregates import Count 5 | from .utils import site_protocol 6 | 7 | 8 | class MySitemap(Sitemap): 9 | protocol = site_protocol() 10 | 11 | 12 | class ArticleSitemap(MySitemap): 13 | changefreq = 'weekly' 14 | priority = 1.0 15 | 16 | def items(self): 17 | return Article.objects.filter(is_publish=True) 18 | 19 | def lastmod(self, obj): 20 | return obj.update_date 21 | 22 | 23 | class CategorySitemap(MySitemap): 24 | changefreq = 'weekly' 25 | priority = 0.8 26 | 27 | def items(self): 28 | return Category.objects.filter(article__is_publish=True).annotate( 29 | total_num=Count('article')).filter(total_num__gt=0) 30 | 31 | def lastmod(self, obj): 32 | return obj.article_set.first().create_date 33 | 34 | 35 | class TagSitemap(MySitemap): 36 | changefreq = 'weekly' 37 | priority = 0.8 38 | 39 | def items(self): 40 | return Tag.objects.filter(article__is_publish=True).annotate( 41 | total_num=Count('article')).filter(total_num__gt=0) 42 | 43 | def lastmod(self, obj): 44 | return obj.article_set.first().create_date 45 | -------------------------------------------------------------------------------- /apps/blog/static/blog/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /apps/blog/static/blog/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /apps/blog/static/blog/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /apps/blog/static/blog/css/account.css: -------------------------------------------------------------------------------- 1 | .secondaryAction{color:#868e96;}.secondaryAction:hover{text-decoration:none;color:#007bff;}.asteriskField{margin-left:.25rem;color:#dc3545;}#social-login .login-title{position:relative;display:block;margin-bottom:10px;}#social-login span{color:#999;}#social-login span:before,#social-login span:after{position:absolute;top:50%;background:#eee;width:38%;height:1px;content:'';}#social-login span:before{left:0;}#social-login span:after{right:0;}.fa-weibo{color:#e12f11;opacity:.8;}.fa-github{color:#333;opacity:.8;}.fa-weibo:hover,.fa-github:hover{opacity:1;}.btn-sm{padding:.2rem .7rem;}.change_profile .form-control,.card-login .form-control{border-radius:0;}.change_profile .alert,.card-login .alert{border-radius:0;}.change_profile .alert li,.card-login .alert li{margin-bottom:.5rem;}.change_profile .alert ul,.card-login .alert ul{padding-left:.5rem;margin-bottom:0;}#profile-avatar .avatar{width:80px;padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;} -------------------------------------------------------------------------------- /apps/blog/static/blog/css/monokai.css: -------------------------------------------------------------------------------- 1 | .codehilite pre{font-size:85%;padding:.5rem;color:#A6ACCD;}.codehilite{background:#292b30;color:#A6ACCD;border-radius:8px;}.codehilite .hll{background-color:#49483e}.codehilite .c{color:#676E95}.codehilite .err{color:#960050;background-color:#1e0010}.codehilite .k{color:#89DDFF}.codehilite .l{color:#ae81ff}.codehilite .n{color:#A6ACCD}.codehilite .o{color:#f92672}.codehilite .p{color:#A6ACCD}.codehilite .ch{color:#676E95}.codehilite .cm{color:#676E95}.codehilite .cp{color:#676E95}.codehilite .cpf{color:#676E95}.codehilite .c1{color:#676E95}.codehilite .cs{color:#676E95}.codehilite .gd{color:#f92672}.codehilite .ge{font-style:italic}.codehilite .gi{color:#a6e22e}.codehilite .gs{font-weight:bold}.codehilite .gu{color:#676E95}.codehilite .kc{color:#89DDFF}.codehilite .kd{color:#89DDFF}.codehilite .kn{color:#f92672}.codehilite .kp{color:#89DDFF}.codehilite .kr{color:#89DDFF}.codehilite .kt{color:#89DDFF}.codehilite .ld{color:#C3E88D}.codehilite .m{color:#ae81ff}.codehilite .s{color:#C3E88D}.codehilite .na{color:#a6e22e}.codehilite .nb{color:#A6ACCD}.codehilite .nc{color:#a6e22e}.codehilite .no{color:#89DDFF}.codehilite .nd{color:#a6e22e}.codehilite .ni{color:#A6ACCD}.codehilite .ne{color:#a6e22e}.codehilite .nf{color:#a6e22e}.codehilite .nl{color:#A6ACCD}.codehilite .nn{color:#A6ACCD}.codehilite .nx{color:#a6e22e}.codehilite .py{color:#A6ACCD}.codehilite .nt{color:#f92672}.codehilite .nv{color:#A6ACCD}.codehilite .ow{color:#f92672}.codehilite .w{color:#A6ACCD}.codehilite .mb{color:#ae81ff}.codehilite .mf{color:#ae81ff}.codehilite .mh{color:#ae81ff}.codehilite .mi{color:#ae81ff}.codehilite .mo{color:#ae81ff}.codehilite .sa{color:#C3E88D}.codehilite .sb{color:#C3E88D}.codehilite .sc{color:#C3E88D}.codehilite .dl{color:#C3E88D}.codehilite .sd{color:#C3E88D}.codehilite .s2{color:#C3E88D}.codehilite .se{color:#ae81ff}.codehilite .sh{color:#C3E88D}.codehilite .si{color:#C3E88D}.codehilite .sx{color:#C3E88D}.codehilite .sr{color:#C3E88D}.codehilite .s1{color:#C3E88D}.codehilite .ss{color:#C3E88D}.codehilite .bp{color:#A6ACCD}.codehilite .fm{color:#a6e22e}.codehilite .vc{color:#A6ACCD}.codehilite .vg{color:#A6ACCD}.codehilite .vi{color:#A6ACCD}.codehilite .vm{color:#A6ACCD}.codehilite .il{color:#ae81ff} -------------------------------------------------------------------------------- /apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /apps/blog/static/blog/img/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/404.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/TOP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/TOP.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/baidu-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/baidu-2.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/blog.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/chrome.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/docker.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/favicon.ico -------------------------------------------------------------------------------- /apps/blog/static/blog/img/friend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/friend.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/github.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/html.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/map.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/nav-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/nav-logo.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/regex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/regex.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/reward_wx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/reward_wx.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/reward_zfb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/reward_zfb.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/rss.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/summary.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/toggle-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/toggle-dark.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/toggle-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/toggle-light.png -------------------------------------------------------------------------------- /apps/blog/static/blog/img/word-cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hopetree/izone/db9a9071e4fde9de8a8f85b1d785e63ea464c812/apps/blog/static/blog/img/word-cloud.png -------------------------------------------------------------------------------- /apps/blog/static/blog/js/js.cookie.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Minified by jsDelivr using Terser v3.14.1. 3 | * Original file: /npm/js-cookie@2.2.1/src/js.cookie.js 4 | * 5 | * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files 6 | */ 7 | !function(e){var n;if("function"==typeof define&&define.amd&&(define(e),n=!0),"object"==typeof exports&&(module.exports=e(),n=!0),!n){var t=window.Cookies,o=window.Cookies=e();o.noConflict=function(){return window.Cookies=t,o}}}(function(){function e(){for(var e=0,n={};e 8 | 9 | {% endblock %} 10 | {% block top-file %} 11 | 16 | {% endblock %} 17 | 18 | 19 | {% block base_content %} 20 |
21 |
22 |
23 |
{{ body|safe }}
24 |
25 |
26 | {% include 'blog/tags/base_right.html' %} 27 |
28 |
29 |
30 | {% endblock %} -------------------------------------------------------------------------------- /apps/blog/templates/blog/index.html: -------------------------------------------------------------------------------- 1 | {% extends "blog/base.html" %} 2 | {% load static %} 3 | {% load humanize %} 4 | {% load blog_tags %} 5 | {% load tctip_tags %} 6 | 7 | {% block head_title %}Tend to Code_一个使用django和bootstrap搭建的个人博客{% endblock %} 8 | {% block metas %} 9 | 10 | 11 | 12 | {% if site_verification %}{{ site_verification|safe }}{% endif %} 13 | {% endblock %} 14 | 15 | {% block top-file %}{% load_tctip %}{% endblock %} 16 | 17 | {% block base_content %} 18 |
19 |
20 |
21 | {% include 'blog/tags/carousel.html' %} 22 | 32 | {% load_article_summary articles user %} 33 | {% if is_paginated %} 34 |
{% load_pages 10 %}
35 |
{% load_pages 4 %}
36 | {% endif %} 37 |
38 |
39 | {% include 'blog/tags/base_right.html' %} 40 |
41 |
42 |
43 | {% endblock %} -------------------------------------------------------------------------------- /apps/blog/templates/blog/silian.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% for each in badurls %} 4 | 5 | {{ each.badurl }} 6 | 7 | {% endfor %} 8 | -------------------------------------------------------------------------------- /apps/blog/templates/blog/subjectIndex.html: -------------------------------------------------------------------------------- 1 | {% extends "blog/base.html" %} 2 | {% load static %} 3 | {% load blog_tags %} 4 | 5 | {% block head_title %}专题{% endblock %} 6 | {% block metas %} 7 | 8 | 9 | {% endblock %} 10 | 11 | {% block base_content %} 12 |
13 | 35 |
36 | {% endblock %} 37 | 38 | -------------------------------------------------------------------------------- /apps/blog/templates/blog/tags/carousel.html: -------------------------------------------------------------------------------- 1 | {% load static blog_tags %} 2 | {% get_carousel_list as carousels %} 3 |