Merge branch 'dev'

master
liangliangyy 9 years ago
commit 99be726e95

@ -19,14 +19,14 @@ 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
# DEBUG = True
DEBUG = False
# ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['www.lylinux.net', '127.0.0.1']
ALLOWED_HOSTS = ['www.lylinux.net', '127.0.0.1', 'example.com']
# Application definition
INSTALLED_APPS = [
@ -51,9 +51,9 @@ MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.gzip.GZipMiddleware',
#'django.middleware.cache.UpdateCacheMiddleware',
# 'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.cache.FetchFromCacheMiddleware',
# 'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
@ -195,19 +195,24 @@ CACHE_MIDDLEWARE_SECONDS = 60 * 60 * 10
CACHE_MIDDLEWARE_KEY_PREFIX = "djangoblog"
CACHE_MIDDLEWARE_ALIAS = 'default'
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = 'default'
# SESSION_ENGINE = "django.contrib.sessions.backends.cache"
# SESSION_CACHE_ALIAS = 'default'
OAHUTH = {
'sina': {
'appkey': '3161614143',
'appsecret': 'ee17c099317f872eeddb25204ea46721',
'callbackurl': 'http://www.lylinux.net/oauth/weibo'
'callbackurl': 'http://www.lylinux.net/oauth/authorize?type=weibo'
},
'google': {
'appkey': os.environ.get('GOOGLE_APP_KEY'),
'appsecret': os.environ.get('GOOGLE_APP_SECRET'),
'callbackurl': 'http://www.lylinux.net/oauth/googleauthorize'
'callbackurl': 'http://www.lylinux.net/oauth/authorize?type=google'
},
'github': {
'appkey': os.environ.get('GITHUB_APP_KEY'),
'appsecret': os.environ.get('GITHUB_APP_SECRET'),
'callbackurl': 'http://www.lylinux.net/oauth/authorize?type=github'
}
}

@ -19,12 +19,10 @@ from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import html
import logging
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():
@ -120,3 +118,24 @@ class common_markdown():
mdp = mistune.Markdown(escape=True, renderer=renderer)
return mdp(value)
def send_email(subject, html_content, tomail):
msg = EmailMultiAlternatives(subject, html_content, from_email='no-reply@lylinux.net', to=tomail)
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,))
def parse_dict_to_url(dict):
from urllib.parse import quote
url = '&'.join(['{}={}'.format(quote(k, safe='/'), quote(v, safe='/'))
for k, v in dict.items()])
return url

@ -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)

@ -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'))

@ -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)

@ -0,0 +1,74 @@
/* Make clicks pass-through */
#nprogress {
pointer-events: none;
}
#nprogress .bar {
background: red;
position: fixed;
z-index: 1031;
top: 0;
left: 0;
width: 100%;
height: 2px;
}
/* Fancy blur effect */
#nprogress .peg {
display: block;
position: absolute;
right: 0px;
width: 100px;
height: 100%;
box-shadow: 0 0 10px #29d, 0 0 5px #29d;
opacity: 1.0;
-webkit-transform: rotate(3deg) translate(0px, -4px);
-ms-transform: rotate(3deg) translate(0px, -4px);
transform: rotate(3deg) translate(0px, -4px);
}
/* Remove these to get rid of the spinner */
#nprogress .spinner {
display: block;
position: fixed;
z-index: 1031;
top: 15px;
right: 15px;
}
#nprogress .spinner-icon {
width: 18px;
height: 18px;
box-sizing: border-box;
border: solid 2px transparent;
border-top-color: red;
border-left-color: red;
border-radius: 50%;
-webkit-animation: nprogress-spinner 400ms linear infinite;
animation: nprogress-spinner 400ms linear infinite;
}
.nprogress-custom-parent {
overflow: hidden;
position: relative;
}
.nprogress-custom-parent #nprogress .spinner,
.nprogress-custom-parent #nprogress .bar {
position: absolute;
}
@-webkit-keyframes nprogress-spinner {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes nprogress-spinner {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

@ -0,0 +1,305 @@
.icon-sn-google {
background-position: 0 -28px;
}
.icon-sn-bg-google {
background-color: #4285f4;
background-position: 0 0;
}
.fa-sn-google {
color: #4285f4;
}
.icon-sn-github {
background-position: -28px -28px;
}
.icon-sn-bg-github {
background-color: #333;
background-position: -28px 0;
}
.fa-sn-github {
color: #333;
}
.icon-sn-weibo {
background-position: -56px -28px;
}
.icon-sn-bg-weibo {
background-color: #e90d24;
background-position: -56px 0;
}
.fa-sn-weibo {
color: #e90d24;
}
.icon-sn-qq {
background-position: -84px -28px;
}
.icon-sn-bg-qq {
background-color: #0098e6;
background-position: -84px 0;
}
.fa-sn-qq {
color: #0098e6;
}
.icon-sn-twitter {
background-position: -112px -28px;
}
.icon-sn-bg-twitter {
background-color: #50abf1;
background-position: -112px 0;
}
.fa-sn-twitter {
color: #50abf1;
}
.icon-sn-facebook {
background-position: -140px -28px;
}
.icon-sn-bg-facebook {
background-color: #4862a3;
background-position: -140px 0;
}
.fa-sn-facebook {
color: #4862a3;
}
.icon-sn-renren {
background-position: -168px -28px;
}
.icon-sn-bg-renren {
background-color: #197bc8;
background-position: -168px 0;
}
.fa-sn-renren {
color: #197bc8;
}
.icon-sn-tqq {
background-position: -196px -28px;
}
.icon-sn-bg-tqq {
background-color: #1f9ed2;
background-position: -196px 0;
}
.fa-sn-tqq {
color: #1f9ed2;
}
.icon-sn-douban {
background-position: -224px -28px;
}
.icon-sn-bg-douban {
background-color: #279738;
background-position: -224px 0;
}
.fa-sn-douban {
color: #279738;
}
.icon-sn-weixin {
background-position: -252px -28px;
}
.icon-sn-bg-weixin {
background-color: #00b500;
background-position: -252px 0;
}
.fa-sn-weixin {
color: #00b500;
}
.icon-sn-dotted {
background-position: -280px -28px;
}
.icon-sn-bg-dotted {
background-color: #eee;
background-position: -280px 0;
}
.fa-sn-dotted {
color: #eee;
}
.icon-sn-site {
background-position: -308px -28px;
}
.icon-sn-bg-site {
background-color: #00b500;
background-position: -308px 0;
}
.fa-sn-site {
color: #00b500;
}
.icon-sn-linkedin {
background-position: -336px -28px;
}
.icon-sn-bg-linkedin {
background-color: #0077b9;
background-position: -336px 0;
}
.fa-sn-linkedin {
color: #0077b9;
}
[class*=icon-sn-] {
display: inline-block;
background-image: url('../img/icon-sn.svg');
background-repeat: no-repeat;
width: 28px;
height: 28px;
vertical-align: middle;
background-size: auto 56px;
}
[class*=icon-sn-]:hover {
opacity: .8;
filter: alpha(opacity=80);
}
.btn-sn-google {
background: #4285f4;
}
.btn-sn-google:active, .btn-sn-google:focus, .btn-sn-google:hover {
background: #2a75f3;
}
.btn-sn-github {
background: #333;
}
.btn-sn-github:active, .btn-sn-github:focus, .btn-sn-github:hover {
background: #262626;
}
.btn-sn-weibo {
background: #e90d24;
}
.btn-sn-weibo:active, .btn-sn-weibo:focus, .btn-sn-weibo:hover {
background: #d10c20;
}
.btn-sn-qq {
background: #0098e6;
}
.btn-sn-qq:active, .btn-sn-qq:focus, .btn-sn-qq:hover {
background: #0087cd;
}
.btn-sn-twitter {
background: #50abf1;
}
.btn-sn-twitter:active, .btn-sn-twitter:focus, .btn-sn-twitter:hover {
background: #38a0ef;
}
.btn-sn-facebook {
background: #4862a3;
}
.btn-sn-facebook:active, .btn-sn-facebook:focus, .btn-sn-facebook:hover {
background: #405791;
}
.btn-sn-renren {
background: #197bc8;
}
.btn-sn-renren:active, .btn-sn-renren:focus, .btn-sn-renren:hover {
background: #166db1;
}
.btn-sn-tqq {
background: #1f9ed2;
}
.btn-sn-tqq:active, .btn-sn-tqq:focus, .btn-sn-tqq:hover {
background: #1c8dbc;
}
.btn-sn-douban {
background: #279738;
}
.btn-sn-douban:active, .btn-sn-douban:focus, .btn-sn-douban:hover {
background: #228330;
}
.btn-sn-weixin {
background: #00b500;
}
.btn-sn-weixin:active, .btn-sn-weixin:focus, .btn-sn-weixin:hover {
background: #009c00;
}
.btn-sn-dotted {
background: #eee;
}
.btn-sn-dotted:active, .btn-sn-dotted:focus, .btn-sn-dotted:hover {
background: #e1e1e1;
}
.btn-sn-site {
background: #00b500;
}
.btn-sn-site:active, .btn-sn-site:focus, .btn-sn-site:hover {
background: #009c00;
}
.btn-sn-linkedin {
background: #0077b9;
}
.btn-sn-linkedin:active, .btn-sn-linkedin:focus, .btn-sn-linkedin:hover {
background: #0067a0;
}
[class*=btn-sn-], [class*=btn-sn-]:active, [class*=btn-sn-]:focus, [class*=btn-sn-]:hover {
border: none;
color: #fff;
}
.btn-sn-more {
padding: 0;
}
.btn-sn-more, .btn-sn-more:active, .btn-sn-more:hover {
box-shadow: none;
}
[class*=btn-sn-] [class*=icon-sn-] {
background-color: transparent;
}

@ -1998,6 +1998,9 @@ div {
#wp-auto-top-bottom:hover {
background-position: right -68px;
}
.widget-login{
margin-top: 15px!important;
}
/* ------------------------------------------------------------------------- *
* Comments
@ -2358,308 +2361,3 @@ li #reply-title {
font: inherit;
vertical-align: baseline;
}
.icon-sn-google {
background-position: 0 -28px;
}
.icon-sn-bg-google {
background-color: #4285f4;
background-position: 0 0;
}
.fa-sn-google {
color: #4285f4;
}
.icon-sn-github {
background-position: -28px -28px;
}
.icon-sn-bg-github {
background-color: #333;
background-position: -28px 0;
}
.fa-sn-github {
color: #333;
}
.icon-sn-weibo {
background-position: -56px -28px;
}
.icon-sn-bg-weibo {
background-color: #e90d24;
background-position: -56px 0;
}
.fa-sn-weibo {
color: #e90d24;
}
.icon-sn-qq {
background-position: -84px -28px;
}
.icon-sn-bg-qq {
background-color: #0098e6;
background-position: -84px 0;
}
.fa-sn-qq {
color: #0098e6;
}
.icon-sn-twitter {
background-position: -112px -28px;
}
.icon-sn-bg-twitter {
background-color: #50abf1;
background-position: -112px 0;
}
.fa-sn-twitter {
color: #50abf1;
}
.icon-sn-facebook {
background-position: -140px -28px;
}
.icon-sn-bg-facebook {
background-color: #4862a3;
background-position: -140px 0;
}
.fa-sn-facebook {
color: #4862a3;
}
.icon-sn-renren {
background-position: -168px -28px;
}
.icon-sn-bg-renren {
background-color: #197bc8;
background-position: -168px 0;
}
.fa-sn-renren {
color: #197bc8;
}
.icon-sn-tqq {
background-position: -196px -28px;
}
.icon-sn-bg-tqq {
background-color: #1f9ed2;
background-position: -196px 0;
}
.fa-sn-tqq {
color: #1f9ed2;
}
.icon-sn-douban {
background-position: -224px -28px;
}
.icon-sn-bg-douban {
background-color: #279738;
background-position: -224px 0;
}
.fa-sn-douban {
color: #279738;
}
.icon-sn-weixin {
background-position: -252px -28px;
}
.icon-sn-bg-weixin {
background-color: #00b500;
background-position: -252px 0;
}
.fa-sn-weixin {
color: #00b500;
}
.icon-sn-dotted {
background-position: -280px -28px;
}
.icon-sn-bg-dotted {
background-color: #eee;
background-position: -280px 0;
}
.fa-sn-dotted {
color: #eee;
}
.icon-sn-site {
background-position: -308px -28px;
}
.icon-sn-bg-site {
background-color: #00b500;
background-position: -308px 0;
}
.fa-sn-site {
color: #00b500;
}
.icon-sn-linkedin {
background-position: -336px -28px;
}
.icon-sn-bg-linkedin {
background-color: #0077b9;
background-position: -336px 0;
}
.fa-sn-linkedin {
color: #0077b9;
}
[class*=icon-sn-] {
display: inline-block;
background-image: url('../img/icon-sn.svg');
background-repeat: no-repeat;
width: 28px;
height: 28px;
vertical-align: middle;
background-size: auto 56px;
}
[class*=icon-sn-]:hover {
opacity: .8;
filter: alpha(opacity=80);
}
.btn-sn-google {
background: #4285f4;
}
.btn-sn-google:active, .btn-sn-google:focus, .btn-sn-google:hover {
background: #2a75f3;
}
.btn-sn-github {
background: #333;
}
.btn-sn-github:active, .btn-sn-github:focus, .btn-sn-github:hover {
background: #262626;
}
.btn-sn-weibo {
background: #e90d24;
}
.btn-sn-weibo:active, .btn-sn-weibo:focus, .btn-sn-weibo:hover {
background: #d10c20;
}
.btn-sn-qq {
background: #0098e6;
}
.btn-sn-qq:active, .btn-sn-qq:focus, .btn-sn-qq:hover {
background: #0087cd;
}
.btn-sn-twitter {
background: #50abf1;
}
.btn-sn-twitter:active, .btn-sn-twitter:focus, .btn-sn-twitter:hover {
background: #38a0ef;
}
.btn-sn-facebook {
background: #4862a3;
}
.btn-sn-facebook:active, .btn-sn-facebook:focus, .btn-sn-facebook:hover {
background: #405791;
}
.btn-sn-renren {
background: #197bc8;
}
.btn-sn-renren:active, .btn-sn-renren:focus, .btn-sn-renren:hover {
background: #166db1;
}
.btn-sn-tqq {
background: #1f9ed2;
}
.btn-sn-tqq:active, .btn-sn-tqq:focus, .btn-sn-tqq:hover {
background: #1c8dbc;
}
.btn-sn-douban {
background: #279738;
}
.btn-sn-douban:active, .btn-sn-douban:focus, .btn-sn-douban:hover {
background: #228330;
}
.btn-sn-weixin {
background: #00b500;
}
.btn-sn-weixin:active, .btn-sn-weixin:focus, .btn-sn-weixin:hover {
background: #009c00;
}
.btn-sn-dotted {
background: #eee;
}
.btn-sn-dotted:active, .btn-sn-dotted:focus, .btn-sn-dotted:hover {
background: #e1e1e1;
}
.btn-sn-site {
background: #00b500;
}
.btn-sn-site:active, .btn-sn-site:focus, .btn-sn-site:hover {
background: #009c00;
}
.btn-sn-linkedin {
background: #0077b9;
}
.btn-sn-linkedin:active, .btn-sn-linkedin:focus, .btn-sn-linkedin:hover {
background: #0067a0;
}
[class*=btn-sn-], [class*=btn-sn-]:active, [class*=btn-sn-]:focus, [class*=btn-sn-]:hover {
border: none;
color: #fff;
}
.btn-sn-more {
padding: 0;
}
.btn-sn-more, .btn-sn-more:active, .btn-sn-more:hover {
box-shadow: none;
}
[class*=btn-sn-] [class*=icon-sn-] {
background-color: transparent;
}

@ -17,3 +17,14 @@ function cancel_reply() {
$("#id_parent_comment_id").val('')
$("#commentform").appendTo($("#respond"));
}
NProgress.start();
NProgress.set(0.4);
//Increment
var interval = setInterval(function () {
NProgress.inc();
}, 1000);
$(document).ready(function () {
NProgress.done();
clearInterval(interval);
});

@ -0,0 +1,480 @@
/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
* @license MIT */
;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.NProgress = factory();
}
})(this, function() {
var NProgress = {};
NProgress.version = '0.2.0';
var Settings = NProgress.settings = {
minimum: 0.08,
easing: 'linear',
positionUsing: '',
speed: 200,
trickle: true,
trickleSpeed: 200,
showSpinner: true,
barSelector: '[role="bar"]',
spinnerSelector: '[role="spinner"]',
parent: 'body',
template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
};
/**
* Updates configuration.
*
* NProgress.configure({
* minimum: 0.1
* });
*/
NProgress.configure = function(options) {
var key, value;
for (key in options) {
value = options[key];
if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;
}
return this;
};
/**
* Last number.
*/
NProgress.status = null;
/**
* Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.
*
* NProgress.set(0.4);
* NProgress.set(1.0);
*/
NProgress.set = function(n) {
var started = NProgress.isStarted();
n = clamp(n, Settings.minimum, 1);
NProgress.status = (n === 1 ? null : n);
var progress = NProgress.render(!started),
bar = progress.querySelector(Settings.barSelector),
speed = Settings.speed,
ease = Settings.easing;
progress.offsetWidth; /* Repaint */
queue(function(next) {
// Set positionUsing if it hasn't already been set
if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();
// Add transition
css(bar, barPositionCSS(n, speed, ease));
if (n === 1) {
// Fade out
css(progress, {
transition: 'none',
opacity: 1
});
progress.offsetWidth; /* Repaint */
setTimeout(function() {
css(progress, {
transition: 'all ' + speed + 'ms linear',
opacity: 0
});
setTimeout(function() {
NProgress.remove();
next();
}, speed);
}, speed);
} else {
setTimeout(next, speed);
}
});
return this;
};
NProgress.isStarted = function() {
return typeof NProgress.status === 'number';
};
/**
* Shows the progress bar.
* This is the same as setting the status to 0%, except that it doesn't go backwards.
*
* NProgress.start();
*
*/
NProgress.start = function() {
if (!NProgress.status) NProgress.set(0);
var work = function() {
setTimeout(function() {
if (!NProgress.status) return;
NProgress.trickle();
work();
}, Settings.trickleSpeed);
};
if (Settings.trickle) work();
return this;
};
/**
* Hides the progress bar.
* This is the *sort of* the same as setting the status to 100%, with the
* difference being `done()` makes some placebo effect of some realistic motion.
*
* NProgress.done();
*
* If `true` is passed, it will show the progress bar even if its hidden.
*
* NProgress.done(true);
*/
NProgress.done = function(force) {
if (!force && !NProgress.status) return this;
return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);
};
/**
* Increments by a random amount.
*/
NProgress.inc = function(amount) {
var n = NProgress.status;
if (!n) {
return NProgress.start();
} else if(n > 1) {
return;
} else {
if (typeof amount !== 'number') {
if (n >= 0 && n < 0.2) { amount = 0.1; }
else if (n >= 0.2 && n < 0.5) { amount = 0.04; }
else if (n >= 0.5 && n < 0.8) { amount = 0.02; }
else if (n >= 0.8 && n < 0.99) { amount = 0.005; }
else { amount = 0; }
}
n = clamp(n + amount, 0, 0.994);
return NProgress.set(n);
}
};
NProgress.trickle = function() {
return NProgress.inc();
};
/**
* Waits for all supplied jQuery promises and
* increases the progress as the promises resolve.
*
* @param $promise jQUery Promise
*/
(function() {
var initial = 0, current = 0;
NProgress.promise = function($promise) {
if (!$promise || $promise.state() === "resolved") {
return this;
}
if (current === 0) {
NProgress.start();
}
initial++;
current++;
$promise.always(function() {
current--;
if (current === 0) {
initial = 0;
NProgress.done();
} else {
NProgress.set((initial - current) / initial);
}
});
return this;
};
})();
/**
* (Internal) renders the progress bar markup based on the `template`
* setting.
*/
NProgress.render = function(fromStart) {
if (NProgress.isRendered()) return document.getElementById('nprogress');
addClass(document.documentElement, 'nprogress-busy');
var progress = document.createElement('div');
progress.id = 'nprogress';
progress.innerHTML = Settings.template;
var bar = progress.querySelector(Settings.barSelector),
perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0),
parent = document.querySelector(Settings.parent),
spinner;
css(bar, {
transition: 'all 0 linear',
transform: 'translate3d(' + perc + '%,0,0)'
});
if (!Settings.showSpinner) {
spinner = progress.querySelector(Settings.spinnerSelector);
spinner && removeElement(spinner);
}
if (parent != document.body) {
addClass(parent, 'nprogress-custom-parent');
}
parent.appendChild(progress);
return progress;
};
/**
* Removes the element. Opposite of render().
*/
NProgress.remove = function() {
removeClass(document.documentElement, 'nprogress-busy');
removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');
var progress = document.getElementById('nprogress');
progress && removeElement(progress);
};
/**
* Checks if the progress bar is rendered.
*/
NProgress.isRendered = function() {
return !!document.getElementById('nprogress');
};
/**
* Determine which positioning CSS rule to use.
*/
NProgress.getPositioningCSS = function() {
// Sniff on document.body.style
var bodyStyle = document.body.style;
// Sniff prefixes
var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :
('MozTransform' in bodyStyle) ? 'Moz' :
('msTransform' in bodyStyle) ? 'ms' :
('OTransform' in bodyStyle) ? 'O' : '';
if (vendorPrefix + 'Perspective' in bodyStyle) {
// Modern browsers with 3D support, e.g. Webkit, IE10
return 'translate3d';
} else if (vendorPrefix + 'Transform' in bodyStyle) {
// Browsers without 3D support, e.g. IE9
return 'translate';
} else {
// Browsers without translate() support, e.g. IE7-8
return 'margin';
}
};
/**
* Helpers
*/
function clamp(n, min, max) {
if (n < min) return min;
if (n > max) return max;
return n;
}
/**
* (Internal) converts a percentage (`0..1`) to a bar translateX
* percentage (`-100%..0%`).
*/
function toBarPerc(n) {
return (-1 + n) * 100;
}
/**
* (Internal) returns the correct CSS for changing the bar's
* position given an n percentage, and speed and ease from Settings
*/
function barPositionCSS(n, speed, ease) {
var barCSS;
if (Settings.positionUsing === 'translate3d') {
barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };
} else if (Settings.positionUsing === 'translate') {
barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };
} else {
barCSS = { 'margin-left': toBarPerc(n)+'%' };
}
barCSS.transition = 'all '+speed+'ms '+ease;
return barCSS;
}
/**
* (Internal) Queues a function to be executed.
*/
var queue = (function() {
var pending = [];
function next() {
var fn = pending.shift();
if (fn) {
fn(next);
}
}
return function(fn) {
pending.push(fn);
if (pending.length == 1) next();
};
})();
/**
* (Internal) Applies css properties to an element, similar to the jQuery
* css method.
*
* While this helper does assist with vendor prefixed property names, it
* does not perform any manipulation of values prior to setting styles.
*/
var css = (function() {
var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],
cssProps = {};
function camelCase(string) {
return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) {
return letter.toUpperCase();
});
}
function getVendorProp(name) {
var style = document.body.style;
if (name in style) return name;
var i = cssPrefixes.length,
capName = name.charAt(0).toUpperCase() + name.slice(1),
vendorName;
while (i--) {
vendorName = cssPrefixes[i] + capName;
if (vendorName in style) return vendorName;
}
return name;
}
function getStyleProp(name) {
name = camelCase(name);
return cssProps[name] || (cssProps[name] = getVendorProp(name));
}
function applyCss(element, prop, value) {
prop = getStyleProp(prop);
element.style[prop] = value;
}
return function(element, properties) {
var args = arguments,
prop,
value;
if (args.length == 2) {
for (prop in properties) {
value = properties[prop];
if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);
}
} else {
applyCss(element, args[1], args[2]);
}
}
})();
/**
* (Internal) Determines if an element or space separated list of class names contains a class name.
*/
function hasClass(element, name) {
var list = typeof element == 'string' ? element : classList(element);
return list.indexOf(' ' + name + ' ') >= 0;
}
/**
* (Internal) Adds a class to an element.
*/
function addClass(element, name) {
var oldList = classList(element),
newList = oldList + name;
if (hasClass(oldList, name)) return;
// Trim the opening space.
element.className = newList.substring(1);
}
/**
* (Internal) Removes a class from an element.
*/
function removeClass(element, name) {
var oldList = classList(element),
newList;
if (!hasClass(element, name)) return;
// Replace the class name.
newList = oldList.replace(' ' + name + ' ', ' ');
// Trim the opening and closing spaces.
element.className = newList.substring(1, newList.length - 1);
}
/**
* (Internal) Gets a space separated list of the class names on the element.
* The list is wrapped with a single space on each end to facilitate finding
* matches within the list.
*/
function classList(element) {
return (' ' + (element && element.className || '') + ' ').replace(/\s+/gi, ' ');
}
/**
* (Internal) Removes an element from the DOM.
*/
function removeElement(element) {
element && element.parentNode && element.parentNode.removeChild(element);
}
return NProgress;
});

@ -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
"""

@ -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)

@ -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'

@ -0,0 +1,26 @@
#!/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: forms.py
@time: 2017/3/7 下午8:58
"""
from django.contrib.auth.forms import forms
from django.forms import widgets
class RequireEmailForm(forms.Form):
email = forms.EmailField(label='电子邮箱', required=True)
oauthid = forms.IntegerField(widget=forms.HiddenInput, required=False)
def __init__(self, *args, **kwargs):
super(RequireEmailForm, self).__init__(*args, **kwargs)
self.fields['email'].widget = widgets.EmailInput(attrs={'placeholder': "email", "class": "form-control"})

@ -4,33 +4,14 @@ from django.db import models
from django.conf import settings
class BaseModel(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='用户')
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 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

@ -14,12 +14,15 @@
"""
from abc import ABCMeta, abstractmethod, abstractproperty
from oauth.models import OAuthUser
from django.conf import settings
import requests
import json
import urllib.parse
from DjangoBlog.utils import logger, parse_dict_to_url
class BaseManager(metaclass=ABCMeta):
class BaseOauthManager(metaclass=ABCMeta):
"""获取用户授权"""
AUTH_URL = None
"""获取token"""
@ -29,10 +32,7 @@ class BaseManager(metaclass=ABCMeta):
'''icon图标名'''
ICON_NAME = None
def __init__(self, client_id, client_secret, callback_url, access_token=None, openid=None):
self.client_id = client_id
self.client_secret = client_secret
self.callback_url = callback_url
def __init__(self, access_token=None, openid=None):
self.access_token = access_token
self.openid = openid
@ -65,14 +65,17 @@ class BaseManager(metaclass=ABCMeta):
return rsp.text
class WBOauthManager(BaseManager):
class WBOauthManager(BaseOauthManager):
AUTH_URL = 'https://api.weibo.com/oauth2/authorize'
TOKEN_URL = 'https://api.weibo.com/oauth2/access_token'
API_URL = 'https://api.weibo.com/2/users/show.json'
ICON_NAME = 'weibo'
def __init__(self, client_id, client_secret, callback_url, access_token=None, openid=None):
super(WBOauthManager, self).__init__(client_id=client_id, client_secret=client_secret,
callback_url=callback_url, access_token=access_token, openid=openid)
def __init__(self, access_token=None, openid=None):
self.client_id = settings.OAHUTH['sina']['appkey']
self.client_secret = settings.OAHUTH['sina']['appsecret']
self.callback_url = settings.OAHUTH['sina']['callbackurl']
super(WBOauthManager, self).__init__(access_token=access_token, openid=openid)
def get_authorization_url(self):
params = {
@ -84,7 +87,7 @@ class WBOauthManager(BaseManager):
return url
def get_access_token_by_code(self, code):
print(code)
params = {
'client_id': self.client_id,
'client_secret': self.client_secret,
@ -93,7 +96,7 @@ class WBOauthManager(BaseManager):
'redirect_uri': self.callback_url
}
rsp = self.do_post(self.TOKEN_URL, params)
print(rsp)
# return rsp
obj = json.loads(rsp)
@ -116,18 +119,20 @@ class WBOauthManager(BaseManager):
'access_token': self.access_token
}
rsp = self.do_get(self.API_URL, params)
print(rsp)
class GoogleOauthManager(BaseManager):
class GoogleOauthManager(BaseOauthManager):
AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token'
API_URL = 'https://www.googleapis.com/oauth2/v3/userinfo'
ICON_NAME = 'google'
def __init__(self, client_id, client_secret, callback_url, access_token=None, openid=None):
super(GoogleOauthManager, self).__init__(client_id=client_id, client_secret=client_secret,
callback_url=callback_url, access_token=access_token, openid=openid)
def __init__(self, access_token=None, openid=None):
self.client_id = settings.OAHUTH['google']['appkey']
self.client_secret = settings.OAHUTH['google']['appsecret']
self.callback_url = settings.OAHUTH['google']['callbackurl']
super(GoogleOauthManager, self).__init__(access_token=access_token, openid=openid)
def get_authorization_url(self):
params = {
@ -136,7 +141,8 @@ class GoogleOauthManager(BaseManager):
'redirect_uri': self.callback_url,
'scope': 'openid email',
}
url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote)
# url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote)
url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
return url
def get_access_token_by_code(self, code):
@ -149,10 +155,16 @@ class GoogleOauthManager(BaseManager):
'redirect_uri': self.callback_url
}
rsp = self.do_post(self.TOKEN_URL, params)
print(rsp)
obj = json.loads(rsp)
self.access_token = str(obj['access_token'])
self.openid = str(obj['id_token'])
try:
self.access_token = str(obj['access_token'])
self.openid = str(obj['id_token'])
logger.info(self.ICON_NAME + ' oauth ' + rsp)
return self.access_token
except:
logger.info(self.ICON_NAME + ' oauth error ' + rsp)
return None
def get_oauth_userinfo(self):
if not self.is_authorized:
@ -161,5 +173,95 @@ class GoogleOauthManager(BaseManager):
'access_token': self.access_token
}
rsp = self.do_get(self.API_URL, params)
print(rsp)
return json.loads(rsp)
try:
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):
AUTH_URL = 'https://github.com/login/oauth/authorize'
TOKEN_URL = 'https://github.com/login/oauth/access_token'
API_URL = 'https://api.github.com/user'
ICON_NAME = 'github'
def __init__(self, access_token=None, openid=None):
self.client_id = settings.OAHUTH['github']['appkey']
self.client_secret = settings.OAHUTH['github']['appsecret']
self.callback_url = settings.OAHUTH['github']['callbackurl']
super(GitHubOauthManager, self).__init__(access_token=access_token, openid=openid)
def get_authorization_url(self):
params = {
'client_id': self.client_id,
'response_type': 'code',
'redirect_uri': self.callback_url,
'scope': 'user'
}
# url = self.AUTH_URL + "?" + urllib.parse.urlencode(params, quote_via=urllib.parse.quote)
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:
from urllib import parse
r = parse.parse_qs(rsp)
self.access_token = (r['access_token'][0])
return self.access_token
except:
return None
def get_oauth_userinfo(self):
params = {
'access_token': self.access_token
}
rsp = self.do_get(self.API_URL, params)
try:
datas = json.loads(rsp)
user = OAuthUser()
user.picture = datas['avatar_url']
user.nikename = datas['name']
user.openid = datas['id']
user.type = 'github'
if datas['email']:
user.email = datas['email']
return user
except:
logger.info('github oauth error.rsp:' + rsp)
return None
def get_oauth_apps():
applications = BaseOauthManager.__subclasses__()
return list(map(lambda x: x(), applications))
def get_manager_by_type(type):
applications = get_oauth_apps()
finds = list(filter(lambda x: x.ICON_NAME.lower() == type.lower(), applications))
if finds:
return finds[0]
return None

@ -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
@time: 2017/3/4 下午3:22
"""

@ -0,0 +1,29 @@
#!/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: oauth_tags.py
@time: 2017/3/4 下午3:22
"""
from oauth.oauthmanager import get_oauth_apps
from django import template
from django.conf import settings
register = template.Library()
@register.inclusion_tag('oauth/oauth_applications.html')
def load_oauth_applications():
applications = get_oauth_apps()
apps = list(map(lambda x: (x.ICON_NAME, x.get_authorization_url()), applications))
return {
'apps': apps
}

@ -1,13 +1,3 @@
from django.test import TestCase
# Create your tests here.
class OAuthTet(TestCase):
def setUp(self):
pass
from oauth.oauthmanager import WBOauthManager
from django.conf import settings
settings.OAHUTH['sina']
manager=WBOauthManager(client_id=settings.OAHUTH['sina']['appkey'],client_secret=settings.OAHUTH['sina']['appsecret'],callback_url=settings.OAHUTH['sina']['callbackurl'])

@ -17,6 +17,13 @@ from django.conf.urls import url
from django.views.decorators.cache import cache_page
from . import views
urlpatterns = [
url(r'^oauth/authorize$', views.authorize),
url(r'^oauth/requireemail/(?P<oauthid>\d+)', views.RequireEmailView.as_view(), name='require_email'),
url(r'^oauth/emailconfirm/(?P<id>\d+)/(?P<sign>\S+)', views.emailconfirm, name='email_confirm'),
]
"""
urlpatterns = [
url(r'^oauth/wbauthorize/(?P<sitename>\w+)$', views.wbauthorize),
url(r'^oauth/wboauthurl$', views.wboauthurl),
@ -24,3 +31,4 @@ urlpatterns = [
url(r'^oauth/googleoauthurl', views.googleoauthurl),
url(r'^oauth/googleauthorize', views.googleauthorize),
]
"""

@ -1,13 +1,159 @@
from django.shortcuts import render
# Create your views here.
from .oauthmanager import WBOauthManager, GoogleOauthManager
from django.conf import settings
from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import get_user_model
from .models import GoogleUserInfo
from .models import OAuthUser
from django.contrib.auth import login
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):
manager = None
type = request.GET.get('type', None)
if not type:
return HttpResponseRedirect('/')
manager = get_manager_by_type(type)
if not manager:
return HttpResponseRedirect('/')
code = request.GET.get('code', None)
rsp = manager.get_access_token_by_code(code)
if not rsp:
return HttpResponseRedirect(manager.get_authorization_url())
user = manager.get_oauth_userinfo()
if user:
try:
user = OAuthUser.objects.get(type=type, openid=user.openid)
except ObjectDoesNotExist:
pass
email = user.email
if 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 + '_' + str(user.openid), email=email)
user.author = author
user.save()
login(request, author)
return HttpResponseRedirect('/')
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
})
print(url)
return HttpResponseRedirect(url)
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('恭喜您绑定成功!', '''
<p>恭喜您您已经成功绑定您的邮箱您可以使用{type}来直接免密码登录本网站.欢迎您继续关注本站地址是</p>
<a href="{url}" rel="bookmark">{url}</a>
再次感谢您
<br />
如果上面链接无法打开请将此链接复制至浏览器
{url}
'''.format(type=oauthuser.type, url='http://' + site), [oauthuser.email, ])
return HttpResponseRedirect('/')
class RequireEmailView(FormView):
form_class = RequireEmailForm
template_name = 'oauth/require_email.html'
def get(self, request, *args, **kwargs):
oauthid = self.kwargs['oauthid']
oauthuser = get_object_or_404(OAuthUser, pk=oauthid)
if oauthuser.email:
pass
# return HttpResponseRedirect('/')
return super(RequireEmailView, self).get(request, *args, **kwargs)
def get_initial(self):
oauthid = self.kwargs['oauthid']
return {
'email': '',
'oauthid': oauthid
}
def get_context_data(self, **kwargs):
oauthid = self.kwargs['oauthid']
oauthuser = get_object_or_404(OAuthUser, pk=oauthid)
if oauthuser.picture:
kwargs['picture'] = oauthuser.picture
return super(RequireEmailView, self).get_context_data(**kwargs)
def form_valid(self, form):
email = form.cleaned_data['email']
oauthid = form.cleaned_data['oauthid']
oauthuser = get_object_or_404(OAuthUser, pk=oauthid)
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 = """
<p>请点击下面链接绑定您的邮箱</p>
<a href="{url}" rel="bookmark">{url}</a>
再次感谢您
<br />
如果上面链接无法打开请将此链接复制至浏览器
{url}
""".format(url=url)
send_email('绑定您的电子邮箱', content, [email, ])
return HttpResponseRedirect('/')
"""
def wbauthorize(request, sitename):
manager = WBOauthManager(client_id=settings.OAHUTH['sina']['appkey'],
client_secret=settings.OAHUTH['sina']['appsecret'],
@ -27,33 +173,34 @@ def wboauthurl(request):
def googleoauthurl(request):
manager = GoogleOauthManager(client_id=settings.OAHUTH['google']['appkey'],
client_secret=settings.OAHUTH['google']['appsecret'],
callback_url=settings.OAHUTH['google']['callbackurl'])
manager = GoogleOauthManager()
url = manager.get_authorization_url()
return HttpResponse(url)
def googleauthorize(request):
manager = GoogleOauthManager(client_id=settings.OAHUTH['google']['appkey'],
client_secret=settings.OAHUTH['google']['appsecret'],
callback_url=settings.OAHUTH['google']['callbackurl'])
manager = GoogleOauthManager()
code = request.GET.get('code', None)
rsp = manager.get_access_token_by_code(code)
print(rsp)
if not rsp:
return HttpResponseRedirect(manager.get_authorization_url())
user = manager.get_oauth_userinfo()
if user:
email = user['email']
author = get_user_model().objects.get(email=email)
if not author:
author = get_user_model().objects.create_user(username=user["name"], email=email, password=None,
nikename=user["name"])
if not GoogleUserInfo.objects.filter(author_id=author.pk):
userinfo = GoogleUserInfo()
userinfo.author = author
userinfo.picture = user["picture"]
userinfo.token = manager.access_token
userinfo.openid = manager.openid
userinfo.nikename = user["name"]
userinfo.save()
return HttpResponse(rsp)
if email:
author = get_user_model().objects.get(email=email)
if not author:
author = get_user_model().objects.create_user(username=user["name"], email=email)
if not GoogleUserInfo.objects.filter(author_id=author.pk):
userinfo = GoogleUserInfo()
userinfo.author = author
userinfo.picture = user["picture"]
userinfo.token = manager.access_token
userinfo.openid = manager.openid
userinfo.nikename = user["name"]
userinfo.save()
login(request, author)
else:
pass
return HttpResponseRedirect('/')
"""

@ -28,7 +28,8 @@
<input type="checkbox" value="remember-me"> Stay signed in
</label>
</div>
{% load oauth_tags %}
{% load_oauth_applications %}
</form>
</div>

@ -45,7 +45,17 @@
{% comment %}{% load comments_tags %}
{% load_post_comment article from %}{% endcomment %}
{% include 'comments/tags/comment_list.html' %}
{% include 'comments/tags/post_comment.html' %}
{% if user.is_authenticated %}
{% include 'comments/tags/post_comment.html' %}
{% else %}
<div class="comments-area">
<h3 class="comment-meta">您还没有登录请您<a href="{% url "account:login" %}">登录</a>后发表评论</h3>
{% load oauth_tags %}
{% load_oauth_applications %}
</div>
{% endif %}
{% endif %}
</div><!-- #primary -->

@ -0,0 +1,10 @@
<div class="widget-login">
<small>
快捷登录:
</small>
{% for icon,url in apps %}
<a href="{{ url }}" rel="nofollow">
<span class="icon-sn-{{ icon }}"></span>
</a>
{% endfor %}
</div>

@ -0,0 +1,46 @@
{% extends 'share_layout/base_account.html' %}
{% load static %}
{% block content %}
<div class="container">
<h2 class="form-signin-heading text-center">Binding E-mail account</h2>
<div class="card card-signin">
{% if picture %}
<img class="img-circle profile-img" src="{{ picture }}" alt="">
{% else %}
<img class="img-circle profile-img" src="{% static 'blog/img/avatar.png' %}" alt="">
{% endif %}
<form class="form-signin" action="" method="post">
{% csrf_token %}
{% comment %}<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" placeholder="Email" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>{% endcomment %}
{{ form.non_field_errors }}
{% for field in form %}
{{ field }}
{{ field.errors }}
{% endfor %}
<button class="btn btn-lg btn-primary btn-block" type="submit">Submit</button>
{% comment %}
<div class="checkbox">
<a class="pull-right">Need help?</a>
<label>
<input type="checkbox" value="remember-me"> Stay signed in
</label>
</div>
{% endcomment %}
</form>
</div>
<p class="text-center">
<a href="{% url "account:login" %}">Sign In</a>
</p>
</div> <!-- /container -->
{% endblock %}

@ -17,7 +17,7 @@
{% block header %}
{% endblock %}
<link rel="profile" href="http://gmpg.org/xfn/11"/>
{% comment %}<link rel="pingback" href="https://www.lylinux.org/xmlrpc.php"/>{% endcomment %}
<!--[if lt IE 9]>
<script src="{% static 'blog/js/html5.js' %}" type="text/javascript"></script>
<![endif]-->
@ -32,11 +32,13 @@
{% compress css %}
<link rel='stylesheet' id='twentytwelve-style-css' href='{% static 'blog/css/style.css' %}' type='text/css'
media='all'/>
<link href="{% static 'blog/css/oauth_style.css' %}" rel="stylesheet">
{% comment %}<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>{% endcomment %}
<!--[if lt IE 9]>
<link rel='stylesheet' id='twentytwelve-ie-css' href='{% static 'blog/css/ie.css' %}' type='text/css' media='all' />
<![endif]-->
<link rel="stylesheet" href="{% static 'pygments/default.css' %}"/>
<link rel="stylesheet" href="{% static 'blog/css/nprogress.css' %}">
{% block compress_css %}
{% endblock %}
{% endcompress %}
@ -44,6 +46,7 @@
<script type='text/javascript' src='{% static 'blog/js/jquery-migrate.min.js' %}' defer='defer'></script>{% endcomment %}
{% compress js %}
<script type="text/javascript" src="{% static 'blog/js/jquery-3.1.1.js' %}"></script>
<script type="text/javascript" src="{% static 'blog/js/nprogress.js' %}"></script>
{% endcompress %}
</head>

@ -15,7 +15,7 @@
{% compress css %}
<!-- Bootstrap core CSS -->
<link href="{% static 'assets/css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'blog/css/oauth_style.css' %}" rel="stylesheet">
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<link href="{% static 'assets/css/ie10-viewport-bug-workaround.css' %}" rel="stylesheet">
<!-- TODC Bootstrap core CSS -->

Loading…
Cancel
Save