diff --git a/DjangoBlog/settings.py b/DjangoBlog/settings.py index 6897111..73f0500 100644 --- a/DjangoBlog/settings.py +++ b/DjangoBlog/settings.py @@ -19,7 +19,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '&3g0bdza#c%dm1lf%5gi&0-*53p3t0m*hmcvo29cn^$ji7je(c' +SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True diff --git a/DjangoBlog/utils.py b/DjangoBlog/utils.py index 7be4976..cae7626 100644 --- a/DjangoBlog/utils.py +++ b/DjangoBlog/utils.py @@ -23,10 +23,6 @@ import _thread from django.core.mail import EmailMultiAlternatives logger = logging.getLogger('djangoblog') -from importlib import import_module -from django.conf import settings - -SessionStore = import_module(settings.SESSION_ENGINE).SessionStore def get_max_articleid_commentid(): diff --git a/blog/admin.py b/blog/admin.py index 5c646ed..b4173d7 100644 --- a/blog/admin.py +++ b/blog/admin.py @@ -16,6 +16,11 @@ class ArticleForm(forms.ModelForm): class ArticlelAdmin(admin.ModelAdmin): form = ArticleForm + list_display = ('id', 'title', 'author', 'created_time', 'views', 'status', 'type') + list_display_links = ('id', 'title') + list_filter = ('author', 'status', 'type', 'category', 'tags') + filter_horizontal = ('tags',) + exclude = ('slug', 'created_time') def save_model(self, request, obj, form, change): super(ArticlelAdmin, self).save_model(request, obj, form, change) @@ -23,8 +28,16 @@ class ArticlelAdmin(admin.ModelAdmin): cache.clear() +class TagAdmin(admin.ModelAdmin): + exclude = ('slug',) + + +class CategoryAdmin(admin.ModelAdmin): + exclude = ('slug',) + + admin.site.register(Article, ArticlelAdmin) # admin.site.register(BlogPage, ArticlelAdmin) -admin.site.register(Category) -admin.site.register(Tag) +admin.site.register(Category, CategoryAdmin) +admin.site.register(Tag, TagAdmin) admin.site.register(Links) diff --git a/blog/management/commands/create_testdata.py b/blog/management/commands/create_testdata.py new file mode 100644 index 0000000..aa41421 --- /dev/null +++ b/blog/management/commands/create_testdata.py @@ -0,0 +1,44 @@ +#!/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: create_testdata.py +@time: 2017/3/11 上午1:58 +""" + +from django.core.management.base import BaseCommand +from blog.models import Article, Tag, Category +from django.contrib.auth import get_user_model +from django.core.exceptions import ObjectDoesNotExist +import datetime + + +class Command(BaseCommand): + help = 'create test datas' + + def handle(self, *args, **options): + user = \ + get_user_model().objects.get_or_create(email='test@test.com', username='testuser', + password='test!q@w#eTYU')[0] + + pcategory = Category.objects.get_or_create(name='pcategory', parent_category=None)[0] + + category = Category.objects.get_or_create(name='category', parent_category=pcategory)[0] + + category.save() + for i in range(1, 10): + article = Article.objects.get_or_create(category=category, + title='nice title ' + str(i), + body='nice content ' + str(i), + author=user + ) + from DjangoBlog.utils import cache + cache.clear() + self.stdout.write(self.style.SUCCESS('created test datas \n')) diff --git a/blog/models.py b/blog/models.py index 8331a9a..169df92 100644 --- a/blog/models.py +++ b/blog/models.py @@ -141,70 +141,6 @@ class Article(BaseModel): return Article.objects.filter(id__lt=self.id, status='p').first() -''' -class BlogPage(models.Model): - """文章""" - STATUS_CHOICES = ( - ('d', '草稿'), - ('p', '发表'), - ) - COMMENT_STATUS = ( - ('o', '打开'), - ('c', '关闭'), - ) - title = models.CharField('标题', max_length=200) - 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, - help_text="不指定发布时间则视为草稿,可以指定未来时间,到时将自动发布。") - status = models.CharField('文章状态', max_length=1, choices=STATUS_CHOICES, default='o') - comment_status = models.CharField('评论状态', max_length=1, choices=COMMENT_STATUS) - # summary = models.CharField('摘要', max_length=200, blank=True, help_text="可选,若为空将摘取正文的前300个字符。") - views = models.PositiveIntegerField('浏览量', default=0) - - author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='作者', on_delete=models.CASCADE) - slug = models.SlugField(default='no-slug', max_length=60, blank=True) - - class Meta: - ordering = ['-pub_time'] - verbose_name = "页面" - verbose_name_plural = verbose_name - - def __str__(self): - return self.title - - def get_absolute_url(self): - return reverse('blog:pagedetail', kwargs= - { - 'page_id': self.id, - 'year': self.created_time.year, - 'month': self.created_time.month, - 'day': self.created_time.day, - 'slug': self.slug - }) - - 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) - - super().save(*args, **kwargs) - - def viewed(self): - self.views += 1 - self.save(update_fields=['views']) - - def comment_list(self): - comments = self.comment_set.all() - parent_comments = comments.filter(parent_comment=None) - - def get_category_tree(self): - return [] -''' - - class Category(BaseModel): """文章分类""" name = models.CharField('分类名', max_length=30, unique=True) diff --git a/blog/views.py b/blog/views.py index b53a9c2..067b0cb 100644 --- a/blog/views.py +++ b/blog/views.py @@ -29,33 +29,6 @@ from django.utils.decorators import classonlymethod from django.utils.decorators import method_decorator from django.shortcuts import get_object_or_404 -""" -class SeoProcessor(): - __metaclass__ = ABCMeta - - @abstractmethod - def get_title(self): - pass - - @abstractmethod - def get_keywords(self): - pass - - @abstractmethod - def get_description(self): - pass -""" - -""" -class CachedTemplateView(ListView): - @classonlymethod - def as_view(cls, **initkwargs): - # print(request) - - view = super(CachedTemplateView, cls).as_view(**initkwargs) - return cache_page(60 * 60 * 10)(view) -""" - class ArticleListView(ListView): # template_name属性用于指定使用哪个模板进行渲染 @@ -117,24 +90,6 @@ class IndexView(ArticleListView): cache_key = 'index_{page}'.format(page=self.page_number) return cache_key - ''' - def get_queryset(self): - # return self.get_queryset_data() - cache_key = 'index_{page}'.format(page=self.page_number) - return self.get_queryset_from_cache(cache_key=cache_key) - """ - value = cache.get(cache_key) - if value: - logger.info('get view cache.key:{key}'.format(key=cache_key)) - return value - else: - article_list = Article.objects.filter(type='a', status='p') - cache.set(cache_key, article_list) - logger.info('set view cache.key:{key}'.format(key=cache_key)) - return article_list - """ - ''' - class ArticleDetailView(DetailView): template_name = 'blog/article_detail.html' @@ -175,37 +130,6 @@ class ArticleDetailView(DetailView): return super(ArticleDetailView, self).get_context_data(**kwargs) - """ - @classonlymethod - def as_view(cls, **initkwargs): - self = cls(**initkwargs) - keyperfix = "blogdetail" - return cache_page(60 * 60 * 10, key_prefix=keyperfix)(super(ArticleDetailView, cls).as_view(**initkwargs)) - """ - - -""" - def post(self, request, *args, **kwargs): - form = CommentForm(request.POST) - - if form.is_valid(): - data = form.cleaned_data - pass - """ - -''' -class PageDetailView(ArticleDetailView): - model = BlogPage - pk_url_kwarg = 'page_id' - - def get_object(self): - obj = super(PageDetailView, self).get_object() - print(obj.title) - obj.viewed() - # obj.body = markdown2.markdown(obj.body) - return obj -''' - class CategoryDetailView(ArticleListView): page_type = "分类目录归档" @@ -226,35 +150,8 @@ class CategoryDetailView(ArticleListView): cache_key = 'category_list_{categoryname}_{page}'.format(categoryname=categoryname, page=self.page_number) return cache_key - ''' - def get_queryset(self): - slug = self.kwargs['category_name'] - # category = Category.objects.get(slug=slug) - category = get_object_or_404(Category, slug=slug) - categoryname = category.name - self.categoryname = categoryname - try: - categoryname = categoryname.split('/')[-1] - except: - pass - - cache_key = 'category_list_{categoryname}_{page}'.format(categoryname=categoryname, page=self.page_number) - - value = cache.get(cache_key) - if value: - logger.info('get view cache.key:{key}'.format(key=cache_key)) - return value - else: - article_list = Article.objects.filter(category__name=categoryname, status='p') - cache.set(cache_key, article_list) - logger.info('set view cache.key:{key}'.format(key=cache_key)) - return article_list - ''' - def get_context_data(self, **kwargs): - # slug = self.kwargs['category_name'] - # category = Category.objects.get(slug=slug) - # categoryname = category.name + categoryname = self.categoryname try: categoryname = categoryname.split('/')[-1] @@ -360,25 +257,18 @@ def refresh_memcache(request): """ -class BlogSearchView(SearchView): - form_class = BlogSearchForm - template_name = 'blog/article_detail.html' - model = Article - # template_name属性用于指定使用哪个模板进行渲染 - template_name = 'blog/article_index.html' +class SeoProcessor(): + __metaclass__ = ABCMeta - # context_object_name属性用于给上下文变量取名(在模板中使用该名字) - context_object_name = 'article_list' + @abstractmethod + def get_title(self): + pass - def get_queryset(self): - queryset = super(BlogSearchView, self).get_queryset() - # further filter queryset based on some set of criteria - # return queryset.filter(pub_date__gte=date(2015, 1, 1)) - return queryset + @abstractmethod + def get_keywords(self): + pass - def get_context_data(self, **kwargs): - tag_name = 'search' - kwargs['page_type'] = 'search' - kwargs['tag_name'] = tag_name - return super(BlogSearchView, self).get_context_data(**kwargs) + @abstractmethod + def get_description(self): + pass """ diff --git a/comments/models.py b/comments/models.py index 61650f3..106e5cf 100644 --- a/comments/models.py +++ b/comments/models.py @@ -11,9 +11,6 @@ from DjangoBlog.utils import cache # Create your models here. class Comment(models.Model): - # url = models.URLField('地址', blank=True, null=True) - # email = models.EmailField('电子邮件', blank=True, null=True) - body = models.TextField('正文', max_length=300) created_time = models.DateTimeField('创建时间', auto_now_add=True) last_mod_time = models.DateTimeField('修改时间', auto_now=True) diff --git a/comments/views.py b/comments/views.py index c5bcf10..787f397 100644 --- a/comments/views.py +++ b/comments/views.py @@ -9,17 +9,7 @@ from django.http import HttpResponseRedirect from django.contrib.auth import get_user_model from django import forms -""" -from django.core.urlresolvers import reverse -from django.contrib import auth -from django.utils.decorators import method_decorator -from django.views.decorators.cache import never_cache -from django.views.decorators.csrf import csrf_protect -from django.contrib.auth.decorators import login_required -""" - -# @method_decorator(login_required,name='dispatch') class CommentPostView(FormView): form_class = CommentForm template_name = 'blog/article_detail.html' diff --git a/oauth/models.py b/oauth/models.py index 4613a8c..33ec0da 100644 --- a/oauth/models.py +++ b/oauth/models.py @@ -8,44 +8,10 @@ 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=50) - picture = models.CharField(max_length=50, blank=True, null=True) + 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) def __str__(self): return self.nikename - - -""" -class BaseModel(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=50) - picture = models.CharField(max_length=50, blank=True, null=True) - - def __str__(self): - return self.nikename - - class Meta: - abstract = True - - -class SinaWBUserInfo(BaseModel): - class Meta: - verbose_name = "新浪微博" - verbose_name_plural = verbose_name - - -class QQUserInfo(BaseModel): - class Meta: - verbose_name = "QQ" - verbose_name_plural = verbose_name - - -class GoogleUserInfo(BaseModel): - class Meta: - verbose_name = "Google" - verbose_name_plural = verbose_name -""" diff --git a/oauth/oauthmanager.py b/oauth/oauthmanager.py index 66c0bbd..3a49f66 100644 --- a/oauth/oauthmanager.py +++ b/oauth/oauthmanager.py @@ -172,8 +172,20 @@ class GoogleOauthManager(BaseOauthManager): 'access_token': self.access_token } rsp = self.do_get(self.API_URL, params) - print(rsp) - return json.loads(rsp) + try: + print(rsp) + datas = json.loads(rsp) + user = OAuthUser() + user.picture = datas['picture'] + user.nikename = datas['name'] + user.openid = datas['sub'] + user.type = 'google' + if datas['email']: + user.email = datas['email'] + return user + except: + logger.info('google oauth error.rsp:' + rsp) + return None class GitHubOauthManager(BaseOauthManager): diff --git a/oauth/urls.py b/oauth/urls.py index b14dbfd..37d3542 100644 --- a/oauth/urls.py +++ b/oauth/urls.py @@ -20,6 +20,7 @@ from . import views urlpatterns = [ url(r'^oauth/authorize$', views.authorize), url(r'^oauth/requireemail/(?P\d+)', views.RequireEmailView.as_view(), name='require_email'), + url(r'^oauth/emailconfirm/(?P\d+)/(?P\S+)', views.emailconfirm, name='email_confirm'), ] """ diff --git a/oauth/views.py b/oauth/views.py index c44fab3..cc82d97 100644 --- a/oauth/views.py +++ b/oauth/views.py @@ -1,7 +1,7 @@ from django.shortcuts import render # Create your views here. -from .oauthmanager import WBOauthManager, GoogleOauthManager, get_manager_by_type + from django.conf import settings from django.http import HttpResponse, HttpResponseRedirect from django.contrib.auth import get_user_model @@ -11,6 +11,11 @@ from django.shortcuts import get_object_or_404 from django.views.generic import FormView, RedirectView from oauth.forms import RequireEmailForm from django.core.urlresolvers import reverse +from DjangoBlog.utils import send_email, get_md5 +from django.contrib.sites.models import Site +from django.core.exceptions import ObjectDoesNotExist +from django.http import HttpResponseForbidden +from .oauthmanager import WBOauthManager, GoogleOauthManager, get_manager_by_type def authorize(request): @@ -26,22 +31,33 @@ def authorize(request): if not rsp: return HttpResponseRedirect(manager.get_authorization_url()) user = manager.get_oauth_userinfo() - author = None + if user: + try: + user = OAuthUser.objects.get(type=type, openid=user.openid) + except ObjectDoesNotExist: + pass email = user.email - email = None if email: - author = get_user_model().objects.get(email=email) + author = None + try: + author = get_user_model().objects.get(email=email) + except ObjectDoesNotExist: + pass if not author: - author = get_user_model().objects.create_user(username=user.nikename, email=email) + author = get_user_model(). \ + objects.create_user(username=user.nikename + '_' + str(user.openid), email=email) user.author = author user.save() login(request, author) return HttpResponseRedirect('/') if not email: - author = get_user_model().objects.create_user(username=user.nikename) + # 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 @@ -50,13 +66,34 @@ def authorize(request): return HttpResponseRedirect(url) -""" -def require_email(request, oauthid): - oauthuser = get_object_or_404(OAuthUser, pk=oauthid) - if oauthuser.email: +def emailconfirm(request, id, sign): + if not sign: + return HttpResponseForbidden() + if not get_md5(settings.SECRET_KEY + str(id) + settings.SECRET_KEY).upper() == sign.upper(): + return HttpResponseForbidden() + oauthuser = get_object_or_404(OAuthUser, pk=id) + author = get_user_model().objects.get(pk=oauthuser.author_id) + if oauthuser.email and author.email: + login(request, author) return HttpResponseRedirect('/') + author.set_password('$%^Q1W2E3R4T5Y6,./') + author.email = oauthuser.email + author.save() + login(request, author) -""" + site = Site.objects.get_current().domain + send_email('恭喜您绑定成功!', ''' +

恭喜您,您已经成功绑定您的邮箱,您可以使用{type}来直接免密码登录本网站.欢迎您继续关注本站,地址是

+ + {url} + + 再次感谢您! +
+ 如果上面链接无法打开,请将此链接复制至浏览器。 + {url} + '''.format(type=oauthuser.type, url='http://' + site), [oauthuser.email, ]) + + return HttpResponseRedirect('/') class RequireEmailView(FormView): @@ -90,8 +127,18 @@ class RequireEmailView(FormView): email = form.cleaned_data['email'] oauthid = form.cleaned_data['oauthid'] oauthuser = get_object_or_404(OAuthUser, pk=oauthid) - from DjangoBlog.utils import send_email - url = '123' + oauthuser.email = email + oauthuser.save() + sign = get_md5(settings.SECRET_KEY + str(oauthuser.id) + settings.SECRET_KEY) + site = Site.objects.get_current().domain + if settings.DEBUG: + site = '127.0.0.1:8000' + path = reverse('oauth:email_confirm', kwargs={ + 'id': oauthid, + 'sign': sign + }) + url = "http://{site}{path}".format(site=site, path=path) + print(url) content = """

请点击下面链接绑定您的邮箱