51 Commits
Author SHA1 Message Date
车亮亮 a29290aadc Merge pull request #65 from liangliangyy/dev
修改侧边栏功能,增加分页测试。  close #59
2017-12-17 02:11:38 +08:00
liangliang 3b61b80598 修改侧边栏功能,增加分页测试。 close #59 2017-12-17 01:58:31 +08:00
车亮亮 d6346b37e6 Merge pull request #63 from liangliangyy/dev
closes #60, closes #61
2017-12-16 02:29:56 +08:00
liangliang 451f3983e0 closes #60, closes #61 2017-12-16 02:29:14 +08:00
车亮亮 75525b107a Merge pull request #56 from liangliangyy/dev
Fix #55
2017-12-10 00:04:23 +08:00
liangliang 10f2c66bb8 Fix #55 2017-12-09 23:55:10 +08:00
liangliangyy a58e5fb014 修改百度站长提交链接 2017-12-08 18:17:14 +08:00
车亮亮 fa049a5ea4 Update README.md 2017-12-07 16:40:14 +08:00
车亮亮 7e54996527 Merge pull request #51 from liangliangyy/dev
增加错误页面🙅‍♂️
2017-11-25 14:46:45 +08:00
liangliang 956ba2a167 增加错误页面🙅‍♂️ 2017-11-25 14:33:33 +08:00
车亮亮 6d30d40b86 Merge pull request #50 from liangliangyy/dev
升级依赖包
2017-11-25 13:40:28 +08:00
liangliang 6ccba22b91 升级依赖包 2017-11-25 13:26:25 +08:00
车亮亮 63c5ae8797 更新readme Fix #49 2017-11-15 18:30:24 +08:00
车亮亮 68ba79add6 Merge pull request #46 from liangliangyy/dev
修改用户默认头像👮‍♀️
2017-11-12 12:22:33 +08:00
liangliang bbbcb175c9 修改用户默认头像👮‍♀️ 2017-11-12 12:14:32 +08:00
车亮亮 062ad09ae0 Merge pull request #45 from liangliangyy/dev
删掉无用输出,增加文章标签长度判断,Fix #44
2017-11-11 20:58:53 +08:00
liangliang 521486d405 删掉无用输出,增加文章标签长度判断,Fix #44 2017-11-11 20:51:01 +08:00
车亮亮 2a7a96d566 Merge pull request #42 from liangliangyy/dev
修改oauth用户
2017-11-04 12:59:23 +08:00
liangliang b8e54d131b 修改oauth用户 2017-11-04 11:30:11 +08:00
liangliang 51f6b48b98 增加gitbook链接 2017-10-31 22:51:53 +08:00
车亮亮 b39ed27543 Merge pull request #40 from liangliangyy/dev
完善测试功能,覆盖更多功能✌️
2017-10-28 16:24:23 +08:00
liangliang 5ce213862d 完善测试功能,覆盖更多功能✌️ 2017-10-28 16:09:16 +08:00
车亮亮 ed4f96b1d4 Merge pull request #38 from liangliangyy/dev
修改cnzz统计为百度统计
2017-10-10 09:08:40 -05:00
liangliang e7ed787ab0 修改cnzz统计为百度统计 2017-10-10 21:45:19 +08:00
liangliang 90ac06a675 修改cnzz统计为百度统计 2017-10-10 21:43:39 +08:00
车亮亮 b7cd5e9a2d Merge pull request #37 from liangliangyy/dev
增加Facebook登录支持
2017-10-09 08:37:14 -05:00
liangliang d65284fb80 增加Facebook登录支持 2017-10-09 21:26:56 +08:00
车亮亮 1c7759738e Merge pull request #36 from liangliangyy/dev
自动清除session文件,修复创建oauth用户名过长bug Fix #34
2017-09-29 10:48:05 -05:00
liangliang 4076b99ff7 自动清除session文件,修复创建oauth用户名过长bug Fix #34 2017-09-29 23:35:04 +08:00
车亮亮 a360b6a1b8 Merge pull request #33 from liangliangyy/dev
界面修改
2017-09-24 01:06:53 +08:00
liangliang 711259beef 界面修改 2017-09-24 00:55:36 +08:00
车亮亮 b80eb18510 Update .coveragerc 2017-09-08 18:21:33 +08:00
车亮亮 58b32031be Merge pull request #31 from liangliangyy/dev
增加测试
2017-09-07 22:50:22 +08:00
liangliang 3067586803 增加测试 2017-09-07 22:40:30 +08:00
车亮亮 f36d5b4856 Update README.md 2017-09-03 17:20:30 +08:00
liangliang 1326c4ea15 update helpinfo 2017-09-03 16:22:09 +08:00
liangliang 1af0823d65 update encode 2017-09-03 16:20:41 +08:00
车亮亮 09f3e50be0 Merge pull request #30 from liangliangyy/weixin
增加微信功能
2017-09-03 15:36:13 +08:00
liangliang 9ba3393afb update travis 2017-09-03 15:25:59 +08:00
liangliang 0268b4beb5 update 2017-09-03 15:20:25 +08:00
liangliang b41b5c210d 完善微信管理功能 2017-09-03 14:51:16 +08:00
liangliang 2e4c61a5c8 增加微信功能 2017-08-27 02:58:32 +08:00
车亮亮 86d2318fed Update README.md 2017-08-24 16:44:17 +08:00
liangliang 1805f8e81e Merge branch 'master' of github.com:liangliangyy/DjangoBlog 2017-08-13 04:33:48 +08:00
liangliang 588d38d127 Update Readme, fixes #28 2017-08-13 04:33:34 +08:00
车亮亮 75243b4b84 Merge pull request #29 from liangliangyy/dev
精简代码,将文章,评论等保存后续动作修改为信号方式
2017-08-13 04:20:51 +08:00
liangliang f6ab2b7ccb 精简代码,将文章,评论等保存后续动作修改为信号方式 2017-08-13 04:12:17 +08:00
liangliang 7e5c3eac12 修改邮件服务器至zoho 2017-08-04 21:04:00 +08:00
车亮亮 2a9b9cb97c Merge pull request #26 from liangliangyy/dev
完善oauth登录功能
2017-07-22 12:31:26 +08:00
liangliang 249fdf10f3 完善oauth登录功能 2017-07-22 12:21:36 +08:00
车亮亮 8fb436649c Create README.md 2017-06-13 16:58:20 +08:00
51 changed files with 1227 additions and 275 deletions
+3
View File
@@ -8,3 +8,6 @@ omit =
*whoosh_cn_backend*
*apps*
*commands*
*oauth*
*travis_test*
*settings.py*
+3
View File
@@ -72,3 +72,6 @@ google93fd32dbd906620a.html
baidu_verify_FlHL7cUyC9.html
BingSiteAuth.xml
cb9339dbe2ff86a5aa169d28dba5f615.txt
werobot_session
django.jpg
uploads/
+1
View File
@@ -1,3 +1,4 @@
dist: precise
language: python
python:
- "3.4"
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.org/
@software: PyCharm
@file: blog_signals.py
@time: 2017/8/12 上午10:18
"""
import django.dispatch
from django.dispatch import receiver
from django.conf import settings
from DjangoBlog.utils import cache, send_email, expire_view_cache, logger
from DjangoBlog.spider_notify import SpiderNotify
from django.contrib.sites.models import Site
comment_save_signal = django.dispatch.Signal(providing_args=["comment_id", "username", "serverport"])
article_save_signal = django.dispatch.Signal(providing_args=['id', 'is_update_views'])
user_login_logout_signal = django.dispatch.Signal(providing_args=['id', 'type'])
@receiver(article_save_signal)
def article_save_callback(sender, **kwargs):
id = kwargs['id']
is_update_views = kwargs['is_update_views']
type = sender.__name__
obj = None
from blog.models import Article, Category, Tag
if type == 'Article':
obj = Article.objects.get(id=id)
elif type == 'Category':
obj = Category.objects.get(id=id)
elif type == 'Tag':
obj = Tag.objects.get(id=id)
if obj is not None:
if not settings.TESTING and not is_update_views:
try:
notify_url = obj.get_full_url()
SpiderNotify.baidu_notify([notify_url])
except Exception as ex:
logger.error("notify sipder", ex)
print(ex)
@receiver(comment_save_signal)
def comment_save_callback(sender, **kwargs):
from comments.models import Comment
serverport = kwargs['serverport']
username = kwargs['username']
comment = Comment.objects.get(id=kwargs['comment_id'])
site = Site.objects.get_current().domain
article = comment.article
# if not settings.DEBUG:
if True:
subject = '感谢您发表的评论'
article_url = "https://{site}{path}".format(site=site, path=comment.article.get_absolute_url())
html_content = """
<p>非常感谢您在本站发表评论</p>
您可以访问
<a href="%s" rel="bookmark">%s</a>
来查看您的评论,
再次感谢您!
<br />
如果上面链接无法打开,请将此链接复制至浏览器。
%s
""" % (article_url, comment.article.title, article_url)
tomail = comment.author.email
send_email([tomail], subject, html_content)
if comment.parent_comment:
html_content = """
您在 <a href="%s" rel="bookmark">%s</a> 的评论 <br/> %s <br/> 收到回复啦.快去看看吧
<br/>
如果上面链接无法打开,请将此链接复制至浏览器。
%s
""" % (article_url, article.title, comment.parent_comment.body, article_url)
tomail = comment.parent_comment.author.email
send_email([tomail], subject, html_content)
path = article.get_absolute_url()
site = Site.objects.get_current().domain
if site.find(':') > 0:
site = site[0:site.find(':')]
expire_view_cache(path, servername=site, serverport=serverport, key_prefix='blogdetail')
if cache.get('seo_processor'):
cache.delete('seo_processor')
comment_cache_key = 'article_comments_{id}'.format(id=article.id)
cache.delete(comment_cache_key)
from django.core.cache.utils import make_template_fragment_key
key = make_template_fragment_key('sidebar', [username])
cache.delete(key)
+13 -4
View File
@@ -45,6 +45,7 @@ INSTALLED_APPS = [
'accounts',
'comments',
'oauth',
'servermanager',
'compressor'
]
@@ -163,7 +164,7 @@ SITE_NAME = '且听风吟'
SITE_URL = 'http://www.lylinux.net'
SITE_DESCRIPTION = '大巧无工,重剑无锋.'
SITE_SEO_DESCRIPTION = '小站主要用来分享和记录学习经验,教程,记录个人生活的点滴以及一些随笔.欢迎大家访问小站'
SITE_SEO_KEYWORDS = 'linux,apache,mysql,服务器,ubuntu,shell,web,csharp,.net,asp,mac,swift'
SITE_SEO_KEYWORDS = 'linux,apache,mysql,服务器,ubuntu,shell,web,csharp,.net,asp,mac,swift,python,django'
ARTICLE_SUB_LENGTH = 300
SHOW_GOOGLE_ADSENSE = False
# bootstrap颜色样式
@@ -185,10 +186,12 @@ CACHE_CONTROL_MAX_AGE = 2592000
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'TIMEOUT': 10800,
'LOCATION': '127.0.0.1:11211',
},
'locmemcache': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'TIMEOUT': 10800,
'LOCATION': 'unique-snowflake',
}
}
@@ -214,11 +217,16 @@ OAHUTH = {
'appkey': os.environ.get('GITHUB_APP_KEY'),
'appsecret': os.environ.get('GITHUB_APP_SECRET'),
'callbackurl': 'http://www.lylinux.net/oauth/authorize?type=github'
},
'facebook': {
'appkey': os.environ.get('FACEBOOK_APP_KEY'),
'appsecret': os.environ.get('FACEBOOK_APP_SECRET'),
'callbackurl': 'http://www.lylinux.net/oauth/authorize?type=facebook'
}
}
SITE_ID = 1
BAIDU_NOTIFY_URL = "http://data.zz.baidu.com/urls?site=https://www.lylinux.net&token=1uAOGrMsUm5syDGn&type=original"
BAIDU_NOTIFY_URL = "http://data.zz.baidu.com/urls?site=https://www.lylinux.net&token=1uAOGrMsUm5syDGn"
# Emial:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
@@ -226,7 +234,7 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
# EMAIL_USE_SSL = True
EMAIL_HOST = 'smtp.exmail.qq.com'
EMAIL_HOST = 'smtp.zoho.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD')
@@ -234,7 +242,8 @@ DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = os.environ.get('DJANGO_EMAIL_USER')
# 设置debug=false 未处理异常邮件通知
ADMINS = [('liangliang', 'liangliangyy@gmail.com')]
# 微信管理员密码(两次md5获得)
WXADMIN = '995F03AC401D6CABABAEF756FC4D43C7'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.net/
@software: PyCharm
@file: tests.py
@time: 2017/10/25 下午10:16
"""
from django.test import Client, RequestFactory, TestCase
from blog.models import Article, Category, Tag
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
import datetime
from DjangoBlog.utils import *
class DjangoBlogTest(TestCase):
def setUp(self):
pass
def test_utils(self):
md5 = get_md5('test')
self.assertIsNotNone(md5)
c = CommonMarkdown.get_markdown('''
# Title1
```python
import os
```
[url](https://www.lylinux.org/)
[ddd](http://www.baidu.com)
''')
self.assertIsNotNone(c)
d = {
'd': 'key1',
'd2': 'key2'
}
data = parse_dict_to_url(d)
self.assertIsNotNone(data)
+4 -1
View File
@@ -31,6 +31,9 @@ sitemaps = {
'static': StaticViewSitemap
}
handler404 = 'blog.views.page_not_found_view'
handler500 = 'blog.views.server_error_view'
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('blog.urls', namespace='blog', app_name='blog')),
@@ -41,6 +44,6 @@ urlpatterns = [
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap'),
url(r'^feed/$', DjangoBlogFeed()),
url(r'^search', include('haystack.urls'), name='search'),
url(r'', include('servermanager.urls', namespace='servermanager', app_name='servermanagers'))
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+5 -12
View File
@@ -23,6 +23,7 @@ from pygments.formatters import html
import logging
import _thread
from django.core.mail import EmailMultiAlternatives
from django.conf import settings
logger = logging.getLogger('djangoblog')
@@ -106,7 +107,7 @@ def block_code(text, lang, inlinestyles=False, linenos=False):
class BlogMarkDownRenderer(mistune.Renderer):
def block_code(self, text, lang):
def block_code(self, text, lang=None):
# renderer has an options
inlinestyles = self.options.get('inlinestyles')
linenos = self.options.get('linenos')
@@ -144,18 +145,10 @@ class CommonMarkdown():
return mdp(value)
def send_email(subject, html_content, tomail):
msg = EmailMultiAlternatives(subject, html_content, from_email='no-reply@lylinux.net', to=tomail)
def send_email(emailto, title, content):
msg = EmailMultiAlternatives(title, content, from_email=settings.DEFAULT_FROM_EMAIL, to=emailto)
msg.content_subtype = "html"
def send_comment_email(msg):
try:
msg.send()
except:
print('send email error')
pass
_thread.start_new_thread(send_comment_email, (msg,))
_thread.start_new_thread(msg.send, (msg,))
def parse_dict_to_url(dict):
+42 -6
View File
@@ -4,9 +4,22 @@
[![Build Status](https://travis-ci.org/liangliangyy/DjangoBlog.svg?branch=master)](https://travis-ci.org/liangliangyy/DjangoBlog) [![Coverage Status](https://coveralls.io/repos/github/liangliangyy/DjangoBlog/badge.svg?branch=master)](https://coveralls.io/github/liangliangyy/DjangoBlog?branch=master) [![Requirements Status](https://requires.io/github/liangliangyy/DjangoBlog/requirements.svg?branch=master)](https://requires.io/github/liangliangyy/DjangoBlog/requirements/?branch=master) [![license](https://img.shields.io/github/license/liangliangyy/djangoblog.svg)]() [![GitHub release](https://img.shields.io/github/release/liangliangyy/djangoblog.svg)]() [![python3.5](https://img.shields.io/badge/python-3.5-brightgreen.svg)]() [![django1.10](https://img.shields.io/badge/django-1.10-brightgreen.svg)]()
## 主要功能:
- 文章,页面,分类目录,标签的添加,删除,编辑等。文章及页面支持`Markdown`,支持代码高亮。
- 支持文章全文搜索。
- 完整的评论功能,包括发表回复评论,以及评论的邮件提醒,支持`Markdown`
- 侧边栏功能,最新文章,最多阅读,标签云等。
- 支持Oauth登陆,现已有Google,GitHub,facebook,微博登录。
- 支持`Memcache`缓存,支持缓存自动刷新。
- 简单的SEO功能,新建文章等会自动通知Google和百度。
- 集成了简单的图床功能。
- 集成`django-compressor`,自动压缩`css``js`
- 基于`python3`,支持`Django`多版本。`Django`的1.8,1.9,1.10,1.11均测试通过。
- 网站异常邮件提醒,若有未捕捉到的异常会自动发送提醒邮件。
- 集成了微信公众号功能,现在可以使用微信公众号来管理你的vps了。
## 安装
使用pip安装:
`pip install -r requirements.txt`
`pip install -Ur requirements.txt`
如果你没有pip,使用如下方式安装:
OS X / Linux 电脑,终端下执行:
@@ -30,6 +43,10 @@ windows电脑:
有详细的部署介绍.
为了安全起见,没有把`SECRET_KEY`上传到Github中而是在环境变量中配置的,如果你想要正常运行的话,需要修改`settings.py`中的`SECRET_KEY`为你自己的就可以了。
如:`SECRET_KEY = 'n9ceqv38)#&mwuat@(mjb_p%em$e8$qyr#fw9ot!=ba6lijx-6'`
若本地部署后发现静态文件无法加载.请将`settings.py`中的`DEBUG=False`修改为`DEBUG=True`即可.
## 运行
修改`DjangoBlog/setting.py` 修改数据库配置,如下所示:
@@ -47,22 +64,26 @@ windows电脑:
### 创建数据库
终端下执行:
终端下执行:
./manage.py makemigrations
./manage.py migrate
./manage.py migrate
### 创建超级用户
终端下执行:
终端下执行:
./manage.py createsuperuser
### 创建测试数据
终端下执行:
终端下执行:
./manage.py create_testdata
### 收集静态文件
终端下执行:  
./manage.py collectstatic --noinput
./manage.py compress --force
### 开始运行:
执行:
执行:
`./manage.py runserver`
@@ -70,3 +91,18 @@ windows电脑:
浏览器打开: http://127.0.0.1:8000/ 就可以看到效果了。
## 问题相关
有任何问题欢迎提Issue,或者将问题描述发送至我邮箱 `liangliangyy#gmail.com`.我会尽快解答.推荐提交Issue方式.
## 捐赠
如果您觉得本项目对您有所帮助,欢迎您请我喝杯咖啡,您的支持是我最大的动力,您可以扫描下方二维码为我付款,谢谢。
### 支付宝:
<div align="center">
<img src="https://resource.lylinux.net/image/2017/12/16/IMG_0207.jpg" width="300" height="300" />
</div>
### 微信:
<div align="center">
<img src="https://resource.lylinux.net/image/2017/12/16/IMG_0206.jpg" width="300" height="300" />
</div>
+9 -1
View File
@@ -3,4 +3,12 @@ from django.contrib import admin
# Register your models here.
from .models import BlogUser
admin.site.register(BlogUser)
class BlogUserAdmin(admin.ModelAdmin):
list_display = ('id', 'nickname', 'username','email','last_login','date_joined')
list_display_links = ('id', 'username')
admin.site.register(BlogUser, BlogUserAdmin)
+3
View File
@@ -2,6 +2,7 @@ from django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site
from django.utils.timezone import now
# Create your models here.
@@ -9,6 +10,8 @@ from django.contrib.sites.models import Site
class BlogUser(AbstractUser):
nickname = models.CharField('昵称', max_length=50, blank=True)
mugshot = models.ImageField('头像', upload_to='upload/mugshots', blank=True)
created_time = models.DateTimeField('创建时间', default=now)
last_mod_time = models.DateTimeField('修改时间', default=now)
# objects = BlogUserManager()
+2 -2
View File
@@ -3,8 +3,8 @@
NAME="djangoblog" # Name of the application
DJANGODIR=//var/www/DjangoBlog # Django project directory
SOCKFILE=/var/www/DjangoBlog/run/gunicorn.sock # we will communicte using this unix socket
USER=www-data # the user to run as
GROUP=www-data # the group to run as
USER=root # the user to run as
GROUP=root # the group to run as
NUM_WORKERS=3 # how many worker processes should Gunicorn spawn
DJANGO_SETTINGS_MODULE=DjangoBlog.settings # which settings file should Django use
DJANGO_WSGI_MODULE=DjangoBlog.wsgi # WSGI module name
+15 -6
View File
@@ -1,7 +1,7 @@
from django.contrib import admin
# Register your models here.
from .models import Article, Category, Tag, Links
from .models import Article, Category, Tag, Links, SideBar
from pagedown.widgets import AdminPagedownWidget
from django import forms
from django.contrib.auth import get_user_model
@@ -39,7 +39,7 @@ class ArticlelAdmin(admin.ModelAdmin):
list_display_links = ('id', 'title')
list_filter = (ArticleListFilter, 'status', 'type', 'category', 'tags')
filter_horizontal = ('tags',)
exclude = ('slug', 'created_time')
exclude = ('slug', 'created_time', 'last_mod_time')
def get_form(self, request, obj=None, **kwargs):
form = super(ArticlelAdmin, self).get_form(request, obj, **kwargs)
@@ -53,15 +53,24 @@ class ArticlelAdmin(admin.ModelAdmin):
class TagAdmin(admin.ModelAdmin):
exclude = ('slug',)
exclude = ('slug', 'last_mod_time', 'created_time')
class CategoryAdmin(admin.ModelAdmin):
exclude = ('slug',)
exclude = ('slug', 'last_mod_time', 'created_time')
class LinksAdmin(admin.ModelAdmin):
exclude = ('last_mod_time', 'created_time')
class SideBarAdmin(admin.ModelAdmin):
list_display = ('name', 'content', 'is_enable', 'sequence')
exclude = ('last_mod_time', 'created_time')
admin.site.register(Article, ArticlelAdmin)
# admin.site.register(BlogPage, ArticlelAdmin)
admin.site.register(Category, CategoryAdmin)
admin.site.register(Tag, TagAdmin)
admin.site.register(Links)
admin.site.register(Links, LinksAdmin)
admin.site.register(SideBar, SideBarAdmin)
+9 -6
View File
@@ -25,25 +25,28 @@ class Command(BaseCommand):
def handle(self, *args, **options):
user = \
get_user_model().objects.get_or_create(email='test@test.com', username='testuser',
get_user_model().objects.get_or_create(email='test@test.com', username='测试用户',
password='test!q@w#eTYU')[0]
pcategory = Category.objects.get_or_create(name='pcategory', parent_category=None)[0]
pcategory = Category.objects.get_or_create(name='我是父类目', parent_category=None)[0]
category = Category.objects.get_or_create(name='category', parent_category=pcategory)[0]
category = Category.objects.get_or_create(name='子类目', parent_category=pcategory)[0]
category.save()
for i in range(1, 10):
basetag = Tag()
basetag.name = "标签"
basetag.save()
for i in range(1, 20):
article = Article.objects.get_or_create(category=category,
title='nice title ' + str(i),
body='nice content ' + str(i),
author=user
)[0]
tag = Tag()
tag.name = "nicetag" + str(i)
tag.name = "标签" + str(i)
tag.save()
article.tags.add(tag)
article.tags.add(basetag)
article.save()
from DjangoBlog.utils import cache
+30 -39
View File
@@ -2,31 +2,28 @@ from django.db import models
from django.core.urlresolvers import reverse
from django.conf import settings
from uuslug import slugify
from DjangoBlog.spider_notify import SpiderNotify
from django.contrib.sites.models import Site
from DjangoBlog.utils import cache_decorator, logger, cache
from django.utils.functional import cached_property
from django.utils.timezone import now
class BaseModel(models.Model):
slug = models.SlugField(default='no-slug', max_length=60, blank=True)
created_time = models.DateTimeField('创建时间', default=now)
last_mod_time = models.DateTimeField('修改时间', default=now)
def save(self, *args, **kwargs):
from DjangoBlog.blog_signals import article_save_signal
if not self.slug or self.slug == 'no-slug' or not self.id:
# Only set the slug when the object is created.
slug = self.title if 'title' in self.__dict__ else self.name
self.slug = slugify(slug)
super().save(*args, **kwargs)
if 'update_fields' in kwargs and len(kwargs['update_fields']) == 1 and kwargs['update_fields'][0] == 'views':
return
try:
if not settings.TESTING:
notify_url = self.get_full_url()
SpiderNotify.baidu_notify([notify_url])
except Exception as ex:
logger.error("notify sipder", ex)
print(ex)
# type = self.__class__.__name__
is_update_views = 'update_fields' in kwargs and len(kwargs['update_fields']) == 1 and kwargs['update_fields'][
0] == 'views'
article_save_signal.send(sender=self.__class__, is_update_views=is_update_views, id=self.id)
def get_full_url(self):
site = Site.objects.get_current().domain
@@ -53,8 +50,6 @@ class Article(BaseModel):
)
title = models.CharField('标题', max_length=200, unique=True)
body = models.TextField('正文')
created_time = models.DateTimeField('创建时间', auto_now_add=True)
last_mod_time = models.DateTimeField('修改时间', auto_now=True)
pub_time = models.DateTimeField('发布时间', blank=True, null=True)
status = models.CharField('文章状态', max_length=1, choices=STATUS_CHOICES, default='p')
comment_status = models.CharField('评论状态', max_length=1, choices=COMMENT_STATUS, default='o')
@@ -82,17 +77,6 @@ class Article(BaseModel):
'day': self.created_time.day
})
# todo remove
"""
return reverse('blog:detail', kwargs={
'article_id': self.id,
'year': self.created_time.year,
'month': self.created_time.month,
'day': self.created_time.day,
'slug': self.slug
})
"""
@cache_decorator(60 * 60 * 10)
def get_category_tree(self):
tree = self.category.get_category_tree()
@@ -101,17 +85,10 @@ class Article(BaseModel):
return names
def save(self, *args, **kwargs):
# self.summary = self.summary or self.body[:settings.ARTICLE_SUB_LENGTH]
if not self.slug or self.slug == 'no-slug' or not self.id:
# Only set the slug when the object is created.
self.slug = slugify(self.title)
"""
try:
notify = sipder_notify()
notify.notify(self.get_full_url())
except Exception as e:
print(e)
"""
super().save(*args, **kwargs)
def viewed(self):
@@ -148,8 +125,6 @@ class Article(BaseModel):
class Category(BaseModel):
"""文章分类"""
name = models.CharField('分类名', max_length=30, unique=True)
created_time = models.DateTimeField('创建时间', auto_now_add=True)
last_mod_time = models.DateTimeField('修改时间', auto_now=True)
parent_category = models.ForeignKey('self', verbose_name="父级分类", blank=True, null=True)
class Meta:
@@ -204,8 +179,6 @@ class Category(BaseModel):
class Tag(BaseModel):
"""文章标签"""
name = models.CharField('标签名', max_length=30, unique=True)
created_time = models.DateTimeField('创建时间', auto_now_add=True)
last_mod_time = models.DateTimeField('修改时间', auto_now=True)
def __str__(self):
return self.name
@@ -228,8 +201,8 @@ class Links(models.Model):
name = models.CharField('链接名称', max_length=30, unique=True)
link = models.URLField('链接地址')
sequence = models.IntegerField('排序', unique=True)
created_time = models.DateTimeField('创建时间', auto_now_add=True)
last_mod_time = models.DateTimeField('修改时间', auto_now=True)
created_time = models.DateTimeField('创建时间', default=now)
last_mod_time = models.DateTimeField('修改时间', default=now)
class Meta:
ordering = ['sequence']
@@ -238,3 +211,21 @@ class Links(models.Model):
def __str__(self):
return self.name
class SideBar(models.Model):
"""侧边栏,可以展示一些html内容"""
name = models.CharField('标题', max_length=100)
content = models.TextField("内容")
sequence = models.IntegerField('排序', unique=True)
is_enable = models.BooleanField('是否启用', default=True)
created_time = models.DateTimeField('创建时间', default=now)
last_mod_time = models.DateTimeField('修改时间', default=now)
class Meta:
ordering = ['sequence']
verbose_name = '侧边栏'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
+21 -9
View File
@@ -19,13 +19,15 @@ from django.template.defaultfilters import stringfilter
from django.utils.safestring import mark_safe
import random
from django.core.urlresolvers import reverse
from blog.models import Article, Category, Tag, Links
from blog.models import Article, Category, Tag, Links, SideBar
from django.utils.encoding import force_text
from django.shortcuts import get_object_or_404
import hashlib
import urllib
from comments.models import Comment
from DjangoBlog.utils import cache_decorator, logger
from DjangoBlog.utils import cache
from django.contrib.auth import get_user_model
from oauth.models import OAuthUser
register = template.Library()
@@ -123,6 +125,7 @@ def load_sidebar(user):
logger.info('load sidebar')
recent_articles = Article.objects.filter(status='p')[:settings.SIDEBAR_ARTICLE_COUNT]
sidebar_categorys = Category.objects.all()
extra_sidebars = SideBar.objects.filter(is_enable=True).order_by('sequence')
most_read_articles = Article.objects.filter(status='p').order_by('-views')[:settings.SIDEBAR_ARTICLE_COUNT]
dates = Article.objects.datetimes('created_time', 'month', order='DESC')
links = Links.objects.all()
@@ -133,10 +136,10 @@ def load_sidebar(user):
increment = 5
tags = Tag.objects.all()
sidebar_tags = None
if tags:
if tags and len(tags) > 0:
s = list(map(lambda t: (t, t.get_article_count()), tags))
count = sum(map(lambda t: t[1], s))
dd = count / len(tags)
dd = 1 if count == 0 else count / len(tags)
sidebar_tags = list(map(lambda x: (x[0], x[1], (x[1] / dd) * increment + 10), s))
return {
@@ -148,7 +151,8 @@ def load_sidebar(user):
'sidebar_comments': commment_list,
'user': user,
'show_adsense': show_adsense,
'sidebar_tags': sidebar_tags
'sidebar_tags': sidebar_tags,
'extra_sidebars': extra_sidebars
}
@@ -177,12 +181,13 @@ def load_pagination_info(page_obj, page_type, tag_name):
previous_number = page_obj.previous_page_number()
previous_url = reverse('blog:index_page', kwargs={'page': previous_number})
if page_type == '分类标签归档':
tag = get_object_or_404(Tag, name=tag_name)
if page_obj.has_next():
next_number = page_obj.next_page_number()
next_url = reverse('blog:tag_detail_page', kwargs={'page': next_number, 'tag_name': tag_name})
next_url = reverse('blog:tag_detail_page', kwargs={'page': next_number, 'tag_name': tag.slug})
if page_obj.has_previous():
previous_number = page_obj.previous_page_number()
previous_url = reverse('blog:tag_detail_page', kwargs={'page': previous_number, 'tag_name': tag_name})
previous_url = reverse('blog:tag_detail_page', kwargs={'page': previous_number, 'tag_name': tag.slug})
if page_type == '作者文章归档':
if page_obj.has_next():
next_number = page_obj.next_page_number()
@@ -192,13 +197,15 @@ def load_pagination_info(page_obj, page_type, tag_name):
previous_url = reverse('blog:author_detail_page', kwargs={'page': previous_number, 'author_name': tag_name})
if page_type == '分类目录归档':
category = get_object_or_404(Category, name=tag_name)
if page_obj.has_next():
next_number = page_obj.next_page_number()
next_url = reverse('blog:category_detail_page', kwargs={'page': next_number, 'category_name': tag_name})
next_url = reverse('blog:category_detail_page',
kwargs={'page': next_number, 'category_name': category.slug})
if page_obj.has_previous():
previous_number = page_obj.previous_page_number()
previous_url = reverse('blog:category_detail_page',
kwargs={'page': previous_number, 'category_name': tag_name})
kwargs={'page': previous_number, 'category_name': category.slug})
return {
'previous_url': previous_url,
@@ -237,6 +244,11 @@ def load_article_detail(article, isindex, user):
@register.filter
def gravatar_url(email, size=40):
"""获得gravatar头像"""
usermodels = OAuthUser.objects.filter(email=email)
if usermodels:
o = list(filter(lambda x: x.picture is not None, usermodels))
if o:
return o[0].picture
email = email.encode('utf-8')
default = "https://resource.lylinux.net/image/2017/03/26/120117.jpg".encode('utf-8')
+92 -2
View File
@@ -1,9 +1,15 @@
from django.test import Client, RequestFactory, TestCase
from blog.models import Article, Category, Tag
from blog.models import Article, Category, Tag, SideBar
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from blog.forms import BlogSearchForm
from django.core.paginator import Paginator
from blog.templatetags.blog_tags import load_pagination_info, load_articletags
import datetime
from accounts.models import BlogUser
from django.core.files.uploadedfile import SimpleUploadedFile
from django.conf import settings
import os
# Create your tests here.
@@ -17,10 +23,19 @@ class ArticleTest(TestCase):
site = Site.objects.get_current().domain
user = BlogUser.objects.get_or_create(email="liangliangyy@gmail.com", username="liangliangyy")[0]
user.set_password("liangliangyy")
user.is_staff = True
user.is_superuser = True
user.save()
response = self.client.get(user.get_absolute_url())
self.assertEqual(response.status_code, 200)
s = SideBar()
s.sequence = 1
s.name = 'test'
s.content = 'test content'
s.is_enable = True
s.save()
category = Category()
category.name = "category"
category.created_time = datetime.datetime.now()
@@ -45,17 +60,69 @@ class ArticleTest(TestCase):
article.save()
self.assertEqual(1, article.tags.count())
for i in range(20):
article = Article()
article.title = "nicetitle" + str(i)
article.body = "nicetitle" + str(i)
article.author = user
article.category = category
article.type = 'a'
article.status = 'p'
article.save()
article.tags.add(tag)
article.save()
response = self.client.get(article.get_absolute_url())
self.assertEqual(response.status_code, 200)
from DjangoBlog.spider_notify import SpiderNotify
SpiderNotify.notify(article.get_absolute_url())
response = self.client.get(tag.get_absolute_url())
self.assertEqual(response.status_code, 200)
response = self.client.get(category.get_absolute_url())
self.assertEqual(response.status_code, 200)
response = self.client.get('/search', {'q': 'django'})
self.assertEqual(response.status_code, 200)
s = load_articletags(article)
self.assertIsNotNone(s)
p = Paginator(Article.objects.all(), 2)
self.__check_pagination__(p, '', '')
p = Paginator(Article.objects.filter(tags=tag), 2)
self.__check_pagination__(p, '分类标签归档', tag.slug)
p = Paginator(Article.objects.filter(author__username='liangliangyy'), 2)
self.__check_pagination__(p, '作者文章归档', 'liangliangyy')
p = Paginator(Article.objects.filter(category=category), 2)
self.__check_pagination__(p, '分类目录归档', category.slug)
f = BlogSearchForm()
f.search()
self.client.login(username='liangliangyy', password='liangliangyy')
from DjangoBlog.spider_notify import SpiderNotify
SpiderNotify.baidu_notify([article.get_full_url()])
rsp = self.client.get('/refresh/')
self.assertEqual(rsp.status_code, 200)
from blog.templatetags.blog_tags import gravatar_url, gravatar
u = gravatar_url('liangliangyy@gmail.com')
u = gravatar('liangliangyy@gmail.com')
def __check_pagination__(self, p, type, value):
s = load_pagination_info(p.page(1), type, value)
self.assertIsNotNone(s)
response = self.client.get(s['previous_url'])
self.assertEqual(response.status_code, 200)
response = self.client.get(s['next_url'])
self.assertEqual(response.status_code, 200)
s = load_pagination_info(p.page(2), type, value)
self.assertIsNotNone(s)
response = self.client.get(s['previous_url'])
self.assertEqual(response.status_code, 200)
response = self.client.get(s['next_url'])
self.assertEqual(response.status_code, 200)
def test_validate_feed(self):
user = BlogUser.objects.get_or_create(email="liangliangyy12@gmail.com", username="liangliangyy")[0]
@@ -67,3 +134,26 @@ class ArticleTest(TestCase):
response = self.client.get('/sitemap.xml')
self.assertEqual(response.status_code, 200)
def test_image(self):
import requests
rsp = requests.get('https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2909203028,3998034658&fm=96')
imagepath = os.path.join(settings.BASE_DIR, 'django.jpg')
with open(imagepath, 'wb') as file:
file.write(rsp.content)
with open(imagepath, 'rb') as file:
imgfile = SimpleUploadedFile('django.jpg', file.read(), content_type='image/jpg')
form_data = {'django.jpg': imgfile}
rsp = self.client.post('/upload', form_data, follow=True)
self.assertEqual(rsp.status_code, 200)
"""
data = SimpleUploadedFile(imagepath, b'file_content', content_type='image/jpg')
rsp = self.client.post('/upload', {'django.jpg': data})
self.assertEqual(rsp.status_code, 200)
SimpleUploadedFile()
"""
def test_errorpage(self):
self.client.get('/eee')
self.client.get('/refresh_memcache')
+2 -2
View File
@@ -42,8 +42,8 @@ urlpatterns = [
url(r'^author/(?P<author_name>\w+)/(?P<page>\d+).html$', views.AuthorDetailView.as_view(),
name='author_detail_page'),
url(r'^tag/(?P<tag_name>.+).html$', views.TagDetailView.as_view(), name='tag_detail'),
url(r'^tag/(?P<tag_name>.+)/(?P<page>\d+).html$', views.TagDetailView.as_view(), name='tag_detail_page'),
url(r'^tag/(?P<tag_name>[\w-]+).html$', views.TagDetailView.as_view(), name='tag_detail'),
url(r'^tag/(?P<tag_name>[\w-]+)/(?P<page>\d+).html$', views.TagDetailView.as_view(), name='tag_detail_page'),
url(r'^upload', views.fileupload, name='upload'),
url(r'^refresh', views.refresh_memcache, name='refresh')
+19 -1
View File
@@ -84,7 +84,7 @@ class ArticleDetailView(DetailView):
pk_url_kwarg = 'article_id'
context_object_name = "article"
def get_object(self):
def get_object(self, queryset=None):
obj = super(ArticleDetailView, self).get_object()
obj.viewed()
self.object = obj
@@ -219,6 +219,8 @@ def fileupload(request):
basepath = r'/var/www/resource/{type}/{timestr}'.format(
type='files' if not isimage else'image', timestr=timestr)
if settings.TESTING:
basepath = settings.BASE_DIR + '/uploads'
url = 'https://resource.lylinux.net/{type}/{timestr}/{filename}'.format(
type='files' if not isimage else'image', timestr=timestr, filename=filename)
if not os.path.exists(basepath):
@@ -252,3 +254,19 @@ def refresh_memcache(request):
return HttpResponseForbidden()
except Exception as e:
return HttpResponse(e)
def page_not_found_view(request):
url = request.get_full_path()
return render(request, 'blog/error_page.html',
{'message': '哎呀,您访问的地址 ' + url + ' 是一个未知的地方。请点击首页看看别的?', 'statuscode': '404'})
def server_error_view(request):
return render(request, 'blog/error_page.html',
{'message': '哎呀,出错了,我已经收集到了错误信息,之后会抓紧抢修,请点击首页看看别的?', 'statuscode': '500'})
def permission_denied_view(request):
return render(request, 'blog/error_page.html',
{'message': '哎呀,您没有权限访问此页面,请点击首页看看别的?', 'statuscode': '403'})
-37
View File
@@ -18,28 +18,6 @@ from django.forms import ModelForm
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
"""
class CommentForm(forms.Form):
url = forms.URLField(label='网址', required=False)
email = forms.EmailField(label='电子邮箱', required=False)
name = forms.CharField(label='姓名')
body = forms.CharField(widget=forms.Textarea, label='评论')
parent_comment_id = forms.IntegerField(widget=forms.HiddenInput, required=False)
class LoginCommentForm(ModelForm):
url = forms.URLField(label='网址', required=False)
email = forms.EmailField(label='电子邮箱', required=False, widget=forms.HiddenInput)
name = forms.CharField(label='姓名', widget=forms.HiddenInput)
parent_comment_id = forms.IntegerField(widget=forms.HiddenInput, required=False)
def __init__(self):
pass
class Meta:
model = Comment
fields = ['body']
"""
class CommentForm(ModelForm):
url = forms.URLField(label='网址', required=False)
@@ -49,21 +27,6 @@ class CommentForm(ModelForm):
'aria-required': 'true'}
))
parent_comment_id = forms.IntegerField(widget=forms.HiddenInput, required=False)
"""
if get_user_model().is_authenticated:
email = forms.EmailField(label='电子邮箱', required=False, widget=forms.HiddenInput)
name = forms.CharField(label='姓名', widget=forms.HiddenInput)
"""
"""
def __init__(self, user, *args, **kwargs):
self.user = user
super(CommentForm, self).__init__(*args, **kwargs)
if self.user.is_authenticated:
self.fields.update({
'email': forms.CharField(widget=forms.HiddenInput()),
'name': forms.CharField(widget=forms.HiddenInput()),
})
"""
class Meta:
model = Comment
+4 -49
View File
@@ -1,19 +1,16 @@
from django.db import models
from django.conf import settings
from django.core.mail import send_mail
from django.core.mail import EmailMultiAlternatives
from django.contrib.sites.models import Site
import _thread
from blog.models import Article
from DjangoBlog.utils import cache
from DjangoBlog.utils import logger
from django.utils.timezone import now
# Create your models here.
class Comment(models.Model):
body = models.TextField('正文', max_length=300)
created_time = models.DateTimeField('创建时间', auto_now_add=True)
last_mod_time = models.DateTimeField('修改时间', auto_now=True)
created_time = models.DateTimeField('创建时间', default=now)
last_mod_time = models.DateTimeField('修改时间', default=now)
author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者', on_delete=models.CASCADE)
article = models.ForeignKey(Article, verbose_name='文章', on_delete=models.CASCADE)
parent_comment = models.ForeignKey('self', verbose_name="上级评论", blank=True, null=True)
@@ -24,50 +21,8 @@ class Comment(models.Model):
verbose_name_plural = verbose_name
get_latest_by = 'created_time'
def send_comment_email(self, msg):
try:
msg.send()
except:
pass
def __str__(self):
return self.body
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if not settings.DEBUG:
subject = '感谢您发表的评论'
site = Site.objects.get_current().domain
article_url = "https://{site}{path}".format(site=site, path=self.article.get_absolute_url())
html_content = """
<p>非常感谢您在本站发表评论</p>
您可以访问
<a href="%s" rel="bookmark">%s</a>
来查看您的评论
再次感谢您
<br />
如果上面链接无法打开请将此链接复制至浏览器
%s
""" % (article_url, self.article.title, article_url)
tomail = self.author.email
msg = EmailMultiAlternatives(subject, html_content, from_email='no-reply@lylinux.net', to=[tomail])
msg.content_subtype = "html"
_thread.start_new_thread(self.send_comment_email, (msg,))
if self.parent_comment:
html_content = """
您在 <a href="%s" rel="bookmark">%s</a> 的评论 <br/> %s <br/> 收到回复啦.快去看看吧
<br/>
如果上面链接无法打开请将此链接复制至浏览器
%s
""" % (article_url, self.article.title, self.parent_comment.body, article_url)
tomail = self.parent_comment.author.email
msg = EmailMultiAlternatives(subject, html_content, from_email='no-reply@lylinux.net', to=[tomail])
msg.content_subtype = "html"
_thread.start_new_thread(self.send_comment_email, (msg,))
def __str__(self):
return self.body
+35
View File
@@ -5,6 +5,8 @@ from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
import datetime
from accounts.models import BlogUser
from comments.templatetags.comments_tags import *
from DjangoBlog.utils import get_max_articleid_commentid
# Create your tests here.
@@ -59,3 +61,36 @@ class CommentsTest(TestCase):
article = Article.objects.get(pk=article.pk)
self.assertEqual(len(article.comment_list()), 1)
parent_comment_id = article.comment_list()[0].id
response = self.client.post(commenturl,
{
'body': '''
# Title1
```python
import os
```
[url](https://www.lylinux.org/)
[ddd](http://www.baidu.com)
''',
'email': user.email,
'name': user.username,
'parent_comment_id': parent_comment_id
})
self.assertEqual(response.status_code, 302)
article = Article.objects.get(pk=article.pk)
self.assertEqual(len(article.comment_list()), 2)
comment = Comment.objects.get(id=parent_comment_id)
tree = parse_commenttree(article.comment_list(), comment)
self.assertEqual(len(tree), 1)
data = show_comment_item(comment, True)
self.assertIsNotNone(data)
s = get_max_articleid_commentid()
self.assertIsNotNone(s)
+3 -14
View File
@@ -62,25 +62,14 @@ class CommentPostView(FormView):
comment.parent_comment = parent_comment
comment.save(True)
from DjangoBlog.utils import expire_view_cache, cache
from django.contrib.sites.models import Site
path = article.get_absolute_url()
site = Site.objects.get_current().domain
if site.find(':') > 0:
site = site[0:site.find(':')]
from DjangoBlog.blog_signals import comment_save_signal
port = 80
try:
# django1.8 没有这个方法...
port = self.request.get_port()
except:
pass
expire_view_cache(path, servername=site, serverport=port, key_prefix='blogdetail')
if cache.get('seo_processor'):
cache.delete('seo_processor')
comment_cache_key = 'article_comments_{id}'.format(id=article_id)
cache.delete(comment_cache_key)
from django.core.cache.utils import make_template_fragment_key
username = self.request.user.username if self.request.user else ''
key = make_template_fragment_key('sidebar', [username])
cache.delete(key)
comment_save_signal.send(sender=self.__class__, comment_id=comment.id, username=username, serverport=port)
return HttpResponseRedirect("%s#div-comment-%d" % (article.get_absolute_url(), comment.pk))
-9
View File
@@ -11,12 +11,3 @@ class OAuthUserAdmin(admin.ModelAdmin):
admin.site.register(OAuthUser, OAuthUserAdmin)
"""
author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='用户', blank=True, null=True)
openid = models.CharField(max_length=50)
nikename = models.CharField(max_length=50, verbose_name='昵称')
token = models.CharField(max_length=150)
picture = models.CharField(max_length=350, blank=True, null=True)
type = models.CharField(blank=False, null=False, max_length=50)
email = models.CharField(max_length=50, null=True, blank=True)
"""
+5 -2
View File
@@ -2,17 +2,20 @@ from django.db import models
# Create your models here.
from django.conf import settings
from django.utils.timezone import now
class OAuthUser(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='用户', blank=True, null=True)
openid = models.CharField(max_length=50)
nikename = models.CharField(max_length=50, verbose_name='昵称')
token = models.CharField(max_length=150)
token = models.CharField(max_length=150, null=True, blank=True)
picture = models.CharField(max_length=350, blank=True, null=True)
type = models.CharField(blank=False, null=False, max_length=50)
email = models.CharField(max_length=50, null=True, blank=True)
token = models.CharField(max_length=50, null=True, blank=True)
matedata = models.CharField(max_length=2000, null=True, blank=True)
created_time = models.DateTimeField('创建时间', default=now)
last_mod_time = models.DateTimeField('修改时间', default=now)
def __str__(self):
return self.nikename
+74 -7
View File
@@ -45,7 +45,7 @@ class BaseOauthManager(metaclass=ABCMeta):
return self.is_access_token_set and self.access_token is not None and self.openid is not None
@abstractmethod
def get_authorization_url(self):
def get_authorization_url(self, nexturl='/'):
pass
@abstractmethod
@@ -77,11 +77,11 @@ class WBOauthManager(BaseOauthManager):
self.callback_url = settings.OAHUTH['sina']['callbackurl']
super(WBOauthManager, self).__init__(access_token=access_token, openid=openid)
def get_authorization_url(self):
def get_authorization_url(self, nexturl='/'):
params = {
'client_id': self.client_id,
'response_type': 'code',
'redirect_uri': self.callback_url
'redirect_uri': self.callback_url + '&next_url=' + nexturl
}
url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
return url
@@ -96,7 +96,6 @@ class WBOauthManager(BaseOauthManager):
'redirect_uri': self.callback_url
}
rsp = self.do_post(self.TOKEN_URL, params)
print(rsp)
try:
obj = json.loads(rsp)
self.access_token = str(obj['access_token'])
@@ -117,6 +116,7 @@ class WBOauthManager(BaseOauthManager):
datas = json.loads(rsp)
user = OAuthUser()
user.matedata = rsp
user.picture = datas['avatar_large']
user.nikename = datas['screen_name']
user.openid = datas['id']
@@ -142,7 +142,7 @@ class GoogleOauthManager(BaseOauthManager):
self.callback_url = settings.OAHUTH['google']['callbackurl']
super(GoogleOauthManager, self).__init__(access_token=access_token, openid=openid)
def get_authorization_url(self):
def get_authorization_url(self, nexturl='/'):
params = {
'client_id': self.client_id,
'response_type': 'code',
@@ -185,6 +185,7 @@ class GoogleOauthManager(BaseOauthManager):
datas = json.loads(rsp)
user = OAuthUser()
user.matedata = rsp
user.picture = datas['picture']
user.nikename = datas['name']
user.openid = datas['sub']
@@ -210,11 +211,11 @@ class GitHubOauthManager(BaseOauthManager):
self.callback_url = settings.OAHUTH['github']['callbackurl']
super(GitHubOauthManager, self).__init__(access_token=access_token, openid=openid)
def get_authorization_url(self):
def get_authorization_url(self, nexturl='/'):
params = {
'client_id': self.client_id,
'response_type': 'code',
'redirect_uri': self.callback_url,
'redirect_uri': self.callback_url + '&next_url=' + nexturl,
'scope': 'user'
}
# url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote)
@@ -255,6 +256,7 @@ class GitHubOauthManager(BaseOauthManager):
user.openid = datas['id']
user.type = 'github'
user.token = self.access_token
user.matedata = rsp
if datas['email']:
user.email = datas['email']
@@ -264,6 +266,71 @@ class GitHubOauthManager(BaseOauthManager):
return None
class FaceBookOauthManager(BaseOauthManager):
AUTH_URL = 'https://www.facebook.com/v2.10/dialog/oauth'
TOKEN_URL = 'https://graph.facebook.com/v2.10/oauth/access_token'
API_URL = 'https://graph.facebook.com/me'
ICON_NAME = 'facebook'
def __init__(self, access_token=None, openid=None):
self.client_id = settings.OAHUTH['facebook']['appkey']
self.client_secret = settings.OAHUTH['facebook']['appsecret']
self.callback_url = settings.OAHUTH['facebook']['callbackurl']
super(FaceBookOauthManager, self).__init__(access_token=access_token, openid=openid)
def get_authorization_url(self, nexturl='/'):
params = {
'client_id': self.client_id,
'response_type': 'code',
'redirect_uri': self.callback_url, # + '&next_url=' + nexturl,
'scope': 'email,public_profile'
}
url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
return url
def get_access_token_by_code(self, code):
params = {
'client_id': self.client_id,
'client_secret': self.client_secret,
# 'grant_type': 'authorization_code',
'code': code,
'redirect_uri': self.callback_url
}
rsp = self.do_post(self.TOKEN_URL, params)
try:
obj = json.loads(rsp)
token = str(obj['access_token'])
self.access_token = token
return self.access_token
except:
return None
def get_oauth_userinfo(self):
params = {
'access_token': self.access_token,
'fields': 'id,name,picture,email'
}
try:
rsp = self.do_get(self.API_URL, params)
datas = json.loads(rsp)
user = OAuthUser()
user.nikename = datas['name']
user.openid = datas['id']
user.type = 'facebook'
user.token = self.access_token
user.matedata = rsp
if datas['email']:
user.email = datas['email']
if datas['picture'] and datas['picture']['data'] and datas['picture']['data']['url']:
user.picture = str(datas['picture']['data']['url'])
return user
except Exception as e:
logger.warn(e)
return None
def get_oauth_apps():
applications = BaseOauthManager.__subclasses__()
return list(map(lambda x: x(), applications))
+8 -3
View File
@@ -13,7 +13,7 @@
@time: 2017/3/4 下午3:22
"""
from oauth.oauthmanager import get_oauth_apps
from django.core.urlresolvers import reverse
from django import template
from django.conf import settings
@@ -21,9 +21,14 @@ register = template.Library()
@register.inclusion_tag('oauth/oauth_applications.html')
def load_oauth_applications():
def load_oauth_applications(request):
applications = get_oauth_apps()
apps = list(map(lambda x: (x.ICON_NAME, x.get_authorization_url()), applications))
baseurl = reverse('oauth:oauthlogin')
path = request.get_full_path()
apps = list(map(lambda x: (x.ICON_NAME,
'{baseurl}?type={type}&next_url={next}'
.format(baseurl=baseurl, type=x.ICON_NAME, next=path)), applications))
return {
'apps': apps
}
+1 -10
View File
@@ -22,14 +22,5 @@ urlpatterns = [
url(r'^oauth/requireemail/(?P<oauthid>\d+).html', views.RequireEmailView.as_view(), name='require_email'),
url(r'^oauth/emailconfirm/(?P<id>\d+)/(?P<sign>\S+).html', views.emailconfirm, name='email_confirm'),
url(r'^oauth/bindsuccess/(?P<oauthid>\d+).html', views.bindsuccess, name='bindsuccess'),
url(r'^oauth/oauthlogin$', views.oauthlogin,name='oauthlogin')
]
"""
urlpatterns = [
url(r'^oauth/wbauthorize/(?P<sitename>\w+)$', views.wbauthorize),
url(r'^oauth/wboauthurl$', views.wboauthurl),
# url(r'^oauth/wbauthorize/(?P<sitename>\w+)$', views.wbauthorize),
url(r'^oauth/googleoauthurl', views.googleoauthurl),
url(r'^oauth/googleauthorize', views.googleauthorize),
]
"""
+28 -14
View File
@@ -18,6 +18,20 @@ from django.http import HttpResponseForbidden
from .oauthmanager import get_manager_by_type
def oauthlogin(request):
type = request.GET.get('type', None)
if not type:
return HttpResponseRedirect('/')
manager = get_manager_by_type(type)
if not manager:
return HttpResponseRedirect('/')
nexturl = request.GET.get('next_url', None)
if not nexturl or nexturl == '/login/':
nexturl = '/'
authorizeurl = manager.get_authorization_url(nexturl)
return HttpResponseRedirect(authorizeurl)
def authorize(request):
manager = None
type = request.GET.get('type', None)
@@ -28,14 +42,17 @@ def authorize(request):
return HttpResponseRedirect('/')
code = request.GET.get('code', None)
rsp = manager.get_access_token_by_code(code)
nexturl = request.GET.get('next_url', None)
if not nexturl:
nexturl = '/'
if not rsp:
return HttpResponseRedirect(manager.get_authorization_url())
return HttpResponseRedirect(manager.get_authorization_url(nexturl))
user = manager.get_oauth_userinfo()
if user:
if not user.nikename:
import datetime
user.nikename = "djangoblog" + datetime.datetime.now().strftime('%Y%m%f%H%m%s')
user.nikename = "djangoblog" + datetime.datetime.now().strftime('%y%m%d%I%M%S')
try:
token = user.token
user = OAuthUser.objects.get(type=type, openid=user.openid)
@@ -54,27 +71,22 @@ def authorize(request):
result = get_user_model().objects.get_or_create(email=user.email)
author = result[0]
if result[1]:
author.username = user.nikename + '_' + str(user.openid)
author.username = user.nikename
author.save()
user.author = author
user.save()
login(request, author)
return HttpResponseRedirect('/')
return HttpResponseRedirect(nexturl)
if not email:
# todo
# 未避免用户名重复,暂时使用oauth用户名+openid这种方式来创建用户
# author = get_user_model().objects.get_or_create(username=user.nikename + '_' + str(user.openid))[0]
# user.author = author
user.save()
url = reverse('oauth:require_email', kwargs={
'oauthid': user.id
})
return HttpResponseRedirect(url)
else:
return HttpResponseRedirect('/')
return HttpResponseRedirect(nexturl)
def emailconfirm(request, id, sign):
@@ -90,7 +102,7 @@ def emailconfirm(request, id, sign):
result = get_user_model().objects.get_or_create(email=oauthuser.email)
author = result[0]
if result[1]:
author.username = oauthuser.nikename + '_' + str(oauthuser.openid)
author.username = oauthuser.nikename
author.save()
"""
if oauthuser.email and author.email:
@@ -102,7 +114,7 @@ def emailconfirm(request, id, sign):
login(request, author)
site = Site.objects.get_current().domain
send_email('恭喜您绑定成功!', '''
content = '''
<p>恭喜您您已经成功绑定您的邮箱您可以使用{type}来直接免密码登录本网站.欢迎您继续关注本站地址是</p>
<a href="{url}" rel="bookmark">{url}</a>
@@ -111,7 +123,9 @@ def emailconfirm(request, id, sign):
<br />
如果上面链接无法打开请将此链接复制至浏览器
{url}
'''.format(type=oauthuser.type, url='http://' + site), [oauthuser.email, ])
'''.format(type=oauthuser.type, url='http://' + site)
send_email(emailto=[oauthuser.email, ], title='恭喜您绑定成功!', content=content)
url = reverse('oauth:bindsuccess', kwargs={
'oauthid': id
})
@@ -172,7 +186,7 @@ class RequireEmailView(FormView):
如果上面链接无法打开请将此链接复制至浏览器
{url}
""".format(url=url)
send_email('绑定您的电子邮箱', content, [email, ])
send_email(emailto=[email, ], title='绑定您的电子邮箱', content=content)
url = reverse('oauth:bindsuccess', kwargs={
'oauthid': oauthid
})
+16 -12
View File
@@ -1,30 +1,34 @@
appdirs==1.4.3
Django==1.11.2
coverage==4.4.1
Django==1.11.7
django-appconf==1.0.2
django-autoslug==1.9.3
django-compressor==2.1.1
django-debug-toolbar==1.8
django-compressor==2.2
django-debug-toolbar==1.9.1
django-haystack==2.6.1
django-ipware==1.1.6
django-pagedown==0.1.3
django-uuslug==1.1.8
jieba==0.38
markdown2==2.3.4
mistune==0.7.4
jieba==0.39
jsonpickle==0.9.5
markdown2==2.3.5
mistune==0.8.1
olefile==0.44
packaging==16.8
Pillow==4.1.1
Pillow==4.3.0
Pygments==2.2.0
PyMySQL==0.7.11
pyparsing==2.2.0
python-memcached==1.58
python-slugify==1.2.4
pytz==2017.2
pytz==2017.3
rcssmin==1.0.6
requests==2.17.3
requests==2.18.4
rjsmin==1.0.12
six==1.10.0
sqlparse==0.2.3
Unidecode==0.4.20
six==1.11.0
sqlparse==0.2.4
Unidecode==0.4.21
urllib3==1.22
webencodings==0.5.1
WeRoBot==1.1.1
Whoosh==2.7.4
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.org/
@software: PyCharm
@file: __init__.py.py
@time: 2017/8/27 上午11:40
"""
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.org/
@software: PyCharm
@file: blogapi.py
@time: 2017/8/27 上午11:40
"""
from blog.models import Article, Category, Tag
from haystack.query import EmptySearchQuerySet, SearchQuerySet
class BlogApi():
def __init__(self):
self.searchqueryset = SearchQuerySet()
self.searchqueryset.auto_query('')
self.__max_takecount__ = 8
def search_articles(self, query):
sqs = self.searchqueryset.auto_query(query)
sqs = sqs.load_all()
return sqs[:self.__max_takecount__]
def get_category_lists(self):
return Category.objects.all()
def get_category_articles(self, categoryname):
articles = Article.objects.filter(category__name=categoryname)
if articles:
return articles[:self.__max_takecount__]
return None
def get_recent_articles(self):
return Article.objects.all()[:self.__max_takecount__]
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.org/
@software: PyCharm
@file: commonapi.py
@time: 2017/9/2 上午1:43
"""
import requests
import json
from DjangoBlog.utils import logger
class TuLing():
def __init__(self):
self.__key__ = '2f1446eb0321804291b0a1e217c25bb5'
self.__appid__ = 137762
def __build_req_url(self, content):
return 'http://www.tuling123.com/openapi/api?key=%s&info=%s&userid=%s' % (
self.__key__, content, self.__appid__)
def UserAgent(self, url):
rsp = requests.get(url)
return rsp.content
def getdata(self, content):
try:
requrl = self.__build_req_url(content)
res = self.UserAgent(requrl).decode('utf-8')
jsons = json.loads(res, encoding='utf-8')
if str(jsons["code"]) == '100000':
return jsons["text"]
except Exception as e:
logger.warn(e)
return "哎呀,出错啦。"
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.org/
@software: PyCharm
@file: MemcacheStorage.py
@time: 2017/8/27 上午2:42
"""
from werobot.session import SessionStorage
from werobot.utils import json_loads, json_dumps
from DjangoBlog.utils import cache
class MemcacheStorage(SessionStorage):
def __init__(self, prefix='ws_'):
self.prefix = prefix
self.cache = cache
@property
def is_available(self):
value = "1"
self.set('checkavaliable', value=value)
return value == self.get('checkavaliable')
def key_name(self, s):
return '{prefix}{s}'.format(prefix=self.prefix, s=s)
def get(self, id):
id = self.key_name(id)
session_json = self.cache.get(id) or '{}'
return json_loads(session_json)
def set(self, id, value):
id = self.key_name(id)
self.cache.set(id, json_dumps(value))
def delete(self, id):
id = self.key_name(id)
self.cache.delete(id)
View File
+11
View File
@@ -0,0 +1,11 @@
from django.contrib import admin
# Register your models here.
from .models import commands
class CommandsAdmin(admin.ModelAdmin):
list_display = ('title', 'command', 'describe')
admin.site.register(commands, CommandsAdmin)
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class ServermanagerConfig(AppConfig):
name = 'servermanager'
+17
View File
@@ -0,0 +1,17 @@
from django.db import models
# Create your models here.
class commands(models.Model):
title = models.CharField('命令标题', max_length=300)
command = models.CharField('命令', max_length=2000)
describe = models.CharField('命令描述', max_length=300)
created_time = models.DateTimeField('创建时间', auto_now_add=True)
last_mod_time = models.DateTimeField('修改时间', auto_now=True)
def __str__(self):
return self.title
class Meta:
verbose_name = '命令'
verbose_name_plural = verbose_name
+245
View File
@@ -0,0 +1,245 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.org/
@software: PyCharm
@file: robot.py
@time: 2017/8/27 上午1:55
"""
from werobot import WeRoBot
import re
from werobot.replies import ArticlesReply, MusicReply, ImageReply, Article
from .MemcacheStorage import MemcacheStorage
from servermanager.Api.blogapi import BlogApi
from servermanager.Api.commonapi import TuLing
import os
import json
from DjangoBlog.utils import get_md5
from django.conf import settings
import jsonpickle
from servermanager.models import commands
robot = WeRoBot(token='lylinux', enable_session=True)
memstorage = MemcacheStorage()
if memstorage.is_available:
robot.config['SESSION_STORAGE'] = memstorage
else:
from werobot.session.filestorage import FileStorage
import os
from django.conf import settings
if os.path.exists(os.path.join(settings.BASE_DIR, 'werobot_session')):
os.remove(os.path.join(settings.BASE_DIR, 'werobot_session'))
robot.config['SESSION_STORAGE'] = FileStorage(filename='werobot_session')
blogapi = BlogApi()
tuling = TuLing()
def convert_to_articlereply(articles, message):
reply = ArticlesReply(message=message)
from blog.templatetags.blog_tags import custom_markdown, truncatechars_content
from DjangoBlog.utils import CommonMarkdown
from django.utils.safestring import mark_safe
for post in articles:
imgs = re.findall(r'(?:http\:|https\:)?\/\/.*\.(?:png|jpg)', post.body)
imgurl = ''
if imgs:
imgurl = imgs[0]
article = Article(
title=post.title,
description=truncatechars_content(post.body),
img=imgurl,
url=post.get_full_url()
)
reply.add_article(article)
return reply
@robot.filter(re.compile(r"^\?.*"))
def search(message, session):
s = message.content
searchstr = str(s).replace('?', '')
result = blogapi.search_articles(searchstr)
if result:
articles = list(map(lambda x: x.object, result))
reply = convert_to_articlereply(articles, message)
return reply
else:
return '没有找到相关文章。'
@robot.filter(re.compile(r'^category\s*$', re.I))
def category(message, session):
categorys = blogapi.get_category_lists()
content = ','.join(map(lambda x: x.name, categorys))
return '所有文章分类目录:' + content
@robot.filter(re.compile(r'^recent\s*$', re.I))
def recents(message, session):
articles = blogapi.get_recent_articles()
if articles:
reply = convert_to_articlereply(articles, message)
return reply
else:
return "暂时还没有文章"
@robot.filter(re.compile('^help$', re.I))
def help(message, session):
return '''欢迎关注!
默认会与图灵机器人聊天~~
你可以通过下面这些命令来获得信息
?关键字搜索文章.
?python.
category获得文章分类目录及文章数.
category-***获得该分类目录文章
如category-python
recent获得最新文章
help获得帮助.
weather:获得天气
如weather:西安
idcard:获得身份证信息
如idcard:61048119xxxxxxxxxx
music:音乐搜索
如music:阴天快乐
PS:以上标点符号都不支持中文标点~~
'''
@robot.filter(re.compile('^weather\:.*$', re.I))
def weather(message, session):
return "建设中..."
@robot.filter(re.compile('^idcard\:.*$', re.I))
def idcard(message, session):
return "建设中..."
@robot.handler
def echo(message, session):
handler = MessageHandler(message, session)
return handler.handler()
class CommandHandler():
def __init__(self):
self.commands = commands.objects.all()
def run(self, title):
cmd = list(filter(lambda x: x.title.upper() == title.upper(), self.commands))
if cmd:
return self.__run_command__(cmd[0].command)
else:
return "未找到相关命令,请输入hepme获得帮助。"
def __run_command__(self, cmd):
try:
str = os.popen(cmd).read()
return str
except:
return '命令执行出错!'
def get_help(self):
rsp = ''
for cmd in self.commands:
rsp += '{c}:{d}\n'.format(c=cmd.title, d=cmd.describe)
return rsp
cmdhandler = CommandHandler()
class MessageHandler():
def __init__(self, message, session):
userid = message.source
self.message = message
self.session = session
self.userid = userid
try:
info = session[userid]
self.userinfo = jsonpickle.decode(info)
except:
userinfo = WxUserInfo()
self.userinfo = userinfo
@property
def is_admin(self):
return self.userinfo.isAdmin
@property
def is_password_set(self):
return self.userinfo.isPasswordSet
def savesession(self):
info = jsonpickle.encode(self.userinfo)
self.session[self.userid] = info
def handler(self):
info = self.message.content
if self.userinfo.isAdmin and info.upper() == 'EXIT':
self.userinfo = WxUserInfo()
self.savesession()
return "退出成功"
if info.upper() == 'ADMIN':
self.userinfo.isAdmin = True
self.savesession()
return "输入管理员密码"
if self.userinfo.isAdmin and not self.userinfo.isPasswordSet:
passwd = settings.WXADMIN
if settings.TESTING:
passwd='123'
if passwd.upper() == get_md5(get_md5(info)).upper():
self.userinfo.isPasswordSet = True
self.savesession()
return "验证通过,请输入命令或者要执行的命令代码:输入helpme获得帮助"
else:
if self.userinfo.Count >= 3:
self.userinfo = WxUserInfo()
self.savesession()
return "超过验证次数"
self.userinfo.Count += 1
self.savesession()
return "验证失败,请重新输入管理员密码:"
if self.userinfo.isAdmin and self.userinfo.isPasswordSet:
if self.userinfo.Command != '' and info.upper() == 'Y':
return cmdhandler.run(self.userinfo.Command)
else:
if info.upper() == 'HELPME':
return cmdhandler.get_help()
self.userinfo.Command = info
self.savesession()
return "确认执行: " + info + " 命令?"
rsp = tuling.getdata(info)
return rsp
class WxUserInfo():
def __init__(self):
self.isAdmin = False
self.isPasswordSet = False
self.Count = 0
self.Command = ''
"""
@robot.handler
def hello(message, session):
blogapi = BlogApi()
result = blogapi.search_articles(message.content)
if result:
articles = list(map(lambda x: x.object, result))
reply = convert_to_articlereply(articles, message)
return reply
else:
return '没有找到相关文章。'
"""
+82
View File
@@ -0,0 +1,82 @@
from django.test import Client, RequestFactory, TestCase
from django.contrib.sites.models import Site
from .models import commands
import datetime
from accounts.models import BlogUser
from blog.models import Category, Article
from .robot import search, category, recents
from werobot.messages.messages import TextMessage
from .robot import MessageHandler, CommandHandler
from servermanager.Api.commonapi import TuLing
# Create your tests here.
class ServerManagerTest(TestCase):
def setUp(self):
self.client = Client()
self.factory = RequestFactory()
def test_tuling(self):
t = TuLing()
content = t.getdata('test')
self.assertIsNotNone(content)
def test_validate_comment(self):
site = Site.objects.get_current().domain
user = BlogUser.objects.create_superuser(email="liangliangyy1@gmail.com",
username="liangliangyy1", password="liangliangyy1")
self.client.login(username='liangliangyy1', password='liangliangyy1')
c = Category()
c.name = "categoryccc"
c.created_time = datetime.datetime.now()
c.last_mod_time = datetime.datetime.now()
c.save()
article = Article()
article.title = "nicetitleccc"
article.body = "nicecontentccc"
article.author = user
article.category = c
article.type = 'a'
article.status = 'p'
article.save()
s = TextMessage([])
s.content = "nicetitleccc"
rsp = search(s, None)
self.assertTrue(rsp != '没有找到相关文章。')
rsp = category(None, None)
self.assertIsNotNone(rsp)
rsp = recents(None, None)
self.assertTrue(rsp != '暂时还没有文章')
cmd = commands()
cmd.title = "test"
cmd.command = "ls"
cmd.describe = "test"
cmd.save()
cmdhandler = CommandHandler()
rsp = cmdhandler.run('test')
self.assertIsNotNone(rsp)
s.source = 'u'
s.content = 'test'
msghandler = MessageHandler(s, {})
#msghandler.userinfo.isPasswordSet = True
#msghandler.userinfo.isAdmin = True
msghandler.handler()
s.content = 'y'
msghandler.handler()
s.content='idcard:12321233'
msghandler.handler()
s.content='weather:上海'
msghandler.handler()
s.content='admin'
msghandler.handler()
s.content='123'
msghandler.handler()
s.content = 'exit'
msghandler.handler()
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@version: ??
@author: liangliangyy
@license: MIT Licence
@contact: liangliangyy@gmail.com
@site: https://www.lylinux.org/
@software: PyCharm
@file: urls.py
@time: 2017/8/27 上午2:27
"""
from django.conf.urls import url
from werobot.contrib.django import make_view
from .robot import robot
urlpatterns = [
url(r'^robot/', make_view(robot)),
]
+3
View File
@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.
+1 -1
View File
@@ -29,7 +29,7 @@
</label>
</div>
{% load oauth_tags %}
{% load_oauth_applications %}
{% load_oauth_applications request%}
</form>
</div>
+1 -1
View File
@@ -53,7 +53,7 @@
href="{% url "account:login" %}?next={{ request.get_full_path }}">登录</a>后发表评论</h3>
{% load oauth_tags %}
{% load_oauth_applications %}
{% load_oauth_applications request%}
</div>
{% endif %}
+45
View File
@@ -0,0 +1,45 @@
{% extends 'share_layout/base.html' %}
{% load blog_tags %}
{% load cache %}
{% block header %}
{% if tag_name %}
{% if statuscode == '404' %}
<title>404 NotFound</title>
{% elif statuscode == '500' %}
<title>Permission Denied</title>
{% elif statuscode == '403' %}
<title>500 Error</title>
{% else %}
<title></title>
{% endif %}
{% comment %}<meta name="description" content="{{ page_type }}:{{ tag_name }}"/>{% endcomment %}
{% else %}
<title>{{ SITE_NAME }} | {{ SITE_DESCRIPTION }}</title>
{% endif %}
<meta name="description" content="{{ SITE_SEO_DESCRIPTION }}"/>
<meta name="keywords" content="{{ SITE_KEYWORDS }}"/>
<meta property="og:type" content="blog"/>
<meta property="og:title" content="{{ SITE_NAME }}"/>
<meta property="og:description" content="{{ SITE_DESCRIPTION }}"/>
<meta property="og:url" content="{{ SITE_BASE_URL }}"/>
<meta property="og:site_name" content="{{ SITE_NAME }}"/>
{% endblock %}
{% block content %}
<div id="primary" class="site-content">
<div id="content" role="main">
<header class="archive-header">
<h1 class="archive-title">{{ message }}</h1>
</header><!-- .archive-header -->
</div><!-- #content -->
</div><!-- #primary -->
{% endblock %}
{% block sidebar %}
{% load_sidebar user %}
{% endblock %}
+14 -4
View File
@@ -8,6 +8,17 @@
</div>
</form>
</aside>
{% if extra_sidebars %}
{% for sidebar in extra_sidebars %}
<aside class="widget_text widget widget_custom_html"><h3 class="widget-title">
{{ sidebar.name }}</h3>
<div class="textwidget custom-html-widget">
{{ sidebar.content }}
</div>
</aside>
{% endfor %}
{% endif %}
{% if most_read_articles %}
<aside id="views-4" class="widget widget_views"><h3 class="widget-title">Views</h3>
@@ -41,8 +52,7 @@
{% for c in sidebar_comments %}
<li class="recentcomments">
<span class="comment-author-link">
<a href="{{ c.author.get_absolute_url }}" rel="external"
class="url">{{ c.author.username }}</a></span>
{{ c.author.username }}</span>
发表在
<a href="{{ c.article.get_absolute_url }}">{{ c.article.title }}</a>
</li>
@@ -109,8 +119,8 @@
{% else %}
<li><a href="{% url "account:login" %}">登录</a>
{% endif %}
<li><a href="http://gitbook.lylinux.net" target="_blank" rel="nofollow">GitBook</a></li>
</ul>
</aside>
<div id="rocket" class="show" title="点我返回顶部"></div>
<div id="rocket" class="show" title="点我返回顶部"></div>
</div><!-- #secondary -->
+11 -7
View File
@@ -1,12 +1,9 @@
<script type="text/javascript">
var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");
document.write(unescape("%3Cspan id='cnzz_stat_icon_1261145394'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s4.cnzz.com/stat.php%3Fid%3D1261145394%26show%3Dpic' type='text/javascript'%3E%3C/script%3E"));
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
@@ -16,5 +13,12 @@
ga('create', 'UA-27354903-4', 'auto');
ga('send', 'pageview');
</script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?30dd00aec5f76607ba37c6770ae48e45";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<a href="https://tongji.baidu.com/sc-web/3478620/home/ico?siteId=11261596" target="_blank" rel="nofollow">百度统计</a>
+3 -1
View File
@@ -21,7 +21,9 @@
Powered by
<a href="https://www.djangoproject.com/" rel="nofollow" target="blank">Django</a>
&nbsp;|&nbsp;
<a href="https://github.com/liangliangyy/DjangoBlog" rel="nofollow" target="blank"> LiangLiangyy</a>
<a href="https://github.com/liangliangyy/DjangoBlog" rel="nofollow" target="blank">LiangLiangyy</a>
|
<a href="https://www.lylinux.net" target="blank">Lylinux</a>
|
本页面加载耗时:<!!LOAD_TIMES!!>s
</div>
+16 -12
View File
@@ -1,29 +1,33 @@
appdirs==1.4.3
Django==1.11.2
coverage==4.4.1
Django==1.11.7
django-appconf==1.0.2
django-autoslug==1.9.3
django-compressor==2.1.1
django-debug-toolbar==1.8
django-compressor==2.2
django-debug-toolbar==1.9.1
django-haystack==2.6.1
django-ipware==1.1.6
django-pagedown==0.1.3
django-uuslug==1.1.8
jieba==0.38
markdown2==2.3.4
mistune==0.7.4
jieba==0.39
jsonpickle==0.9.5
markdown2==2.3.5
mistune==0.8.1
olefile==0.44
packaging==16.8
Pillow==4.1.1
Pillow==4.3.0
Pygments==2.2.0
PyMySQL==0.7.11
pyparsing==2.2.0
python-slugify==1.2.4
pytz==2017.2
pytz==2017.3
rcssmin==1.0.6
requests==2.17.3
requests==2.18.4
rjsmin==1.0.12
six==1.10.0
sqlparse==0.2.3
Unidecode==0.4.20
six==1.11.0
sqlparse==0.2.4
Unidecode==0.4.21
urllib3==1.22
webencodings==0.5.1
WeRoBot==1.1.1
Whoosh==2.7.4
+8 -1
View File
@@ -47,6 +47,7 @@ INSTALLED_APPS = [
'accounts',
'comments',
'oauth',
'servermanager',
'compressor'
]
@@ -215,6 +216,11 @@ OAHUTH = {
'appkey': 'githubappkey',
'appsecret': 'githubappsecret',
'callbackurl': 'http://www.lylinux.net/oauth/authorize?type=github'
},
'facebook': {
'appkey': 'facebookappkey',
'appsecret': 'facebookappsecret',
'callbackurl': 'http://www.lylinux.net/oauth/authorize?type=facebook'
}
}
@@ -235,7 +241,8 @@ DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = os.environ.get('DJANGO_EMAIL_USER')
# 设置debug=false 未处理异常邮件通知
ADMINS = [('liangliang', 'liangliangyy@gmail.com')]
# 微信管理员密码(两次md5获得)
WXADMIN = '995F03AC401D6CABABAEF756FC4D43C7'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,