Merge pull request #639 from liangliangyy/dev

Dev
sh_branch
且听风吟 3 years ago committed by GitHub
commit 2df3e1a974
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

2
.gitignore vendored

@ -67,8 +67,6 @@ target/
# virtualenv
venv/
migrations/
!migrations/__init__.py
collectedstatic/
djangoblog/whoosh_index/
google93fd32dbd906620a.html

@ -0,0 +1,49 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='BlogUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('nickname', models.CharField(blank=True, max_length=100, verbose_name='昵称')),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
('source', models.CharField(blank=True, max_length=100, verbose_name='创建来源')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': '用户',
'verbose_name_plural': '用户',
'ordering': ['-id'],
'get_latest_by': 'id',
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]

@ -1,26 +1,42 @@
import requests
from django.core.management.base import BaseCommand
from django.template.context_processors import static
from django.templatetags.static import static
from djangoblog.utils import save_user_avatar
from oauth.models import OAuthUser
from oauth.oauthmanager import get_manager_by_type
class Command(BaseCommand):
help = 'sync user avatar'
def test_picture(self, url):
try:
if requests.get(url, timeout=2).status_code == 200:
return True
except:
pass
def handle(self, *args, **options):
static_url = static("avatar/")
users = OAuthUser.objects.filter(picture__isnull=False).exclude(
picture__istartswith=static_url).all()
self.stdout.write('开始同步{count}个用户头像'.format(count=len(users)))
static_url = static("../")
users = OAuthUser.objects.filter(picture__isnull=False).all()
self.stdout.write(f'开始同步{len(users)}个用户头像')
for u in users:
self.stdout.write('开始同步:{id}'.format(id=u.nikename))
self.stdout.write(f'开始同步:{u.nickname}')
url = u.picture
if url.startswith(static_url):
if self.test_picture(url):
continue
else:
if u.metadata:
manage = get_manager_by_type(u.type)
url = manage.get_picture(u.metadata)
else:
continue
url = save_user_avatar(url)
if url:
self.stdout.write(
'结束同步:{id}.url:{url}'.format(
id=u.nikename, url=url))
f'结束同步:{u.nickname}.url:{url}')
u.picture = url
u.save()
self.stdout.write('结束同步')

@ -0,0 +1,137 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import mdeditor.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='BlogSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sitename', models.CharField(default='', max_length=200, verbose_name='网站名称')),
('site_description', models.TextField(default='', max_length=1000, verbose_name='网站描述')),
('site_seo_description', models.TextField(default='', max_length=1000, verbose_name='网站SEO描述')),
('site_keywords', models.TextField(default='', max_length=1000, verbose_name='网站关键字')),
('article_sub_length', models.IntegerField(default=300, verbose_name='文章摘要长度')),
('sidebar_article_count', models.IntegerField(default=10, verbose_name='侧边栏文章数目')),
('sidebar_comment_count', models.IntegerField(default=5, verbose_name='侧边栏评论数目')),
('article_comment_count', models.IntegerField(default=5, verbose_name='文章页面默认显示评论数目')),
('show_google_adsense', models.BooleanField(default=False, verbose_name='是否显示谷歌广告')),
('google_adsense_codes', models.TextField(blank=True, default='', max_length=2000, null=True, verbose_name='广告内容')),
('open_site_comment', models.BooleanField(default=True, verbose_name='是否打开网站评论功能')),
('beiancode', models.CharField(blank=True, default='', max_length=2000, null=True, verbose_name='备案号')),
('analyticscode', models.TextField(default='', max_length=1000, verbose_name='网站统计代码')),
('show_gongan_code', models.BooleanField(default=False, verbose_name='是否显示公安备案号')),
('gongan_beiancode', models.TextField(blank=True, default='', max_length=2000, null=True, verbose_name='公安备案号')),
],
options={
'verbose_name': '网站配置',
'verbose_name_plural': '网站配置',
},
),
migrations.CreateModel(
name='Links',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30, unique=True, verbose_name='链接名称')),
('link', models.URLField(verbose_name='链接地址')),
('sequence', models.IntegerField(unique=True, verbose_name='排序')),
('is_enable', models.BooleanField(default=True, verbose_name='是否显示')),
('show_type', models.CharField(choices=[('i', '首页'), ('l', '列表页'), ('p', '文章页面'), ('a', '全站'), ('s', '友情链接页面')], default='i', max_length=1, verbose_name='显示类型')),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
],
options={
'verbose_name': '友情链接',
'verbose_name_plural': '友情链接',
'ordering': ['sequence'],
},
),
migrations.CreateModel(
name='SideBar',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='标题')),
('content', models.TextField(verbose_name='内容')),
('sequence', models.IntegerField(unique=True, verbose_name='排序')),
('is_enable', models.BooleanField(default=True, verbose_name='是否启用')),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
],
options={
'verbose_name': '侧边栏',
'verbose_name_plural': '侧边栏',
'ordering': ['sequence'],
},
),
migrations.CreateModel(
name='Tag',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
('name', models.CharField(max_length=30, unique=True, verbose_name='标签名')),
('slug', models.SlugField(blank=True, default='no-slug', max_length=60)),
],
options={
'verbose_name': '标签',
'verbose_name_plural': '标签',
'ordering': ['name'],
},
),
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
('name', models.CharField(max_length=30, unique=True, verbose_name='分类名')),
('slug', models.SlugField(blank=True, default='no-slug', max_length=60)),
('index', models.IntegerField(default=0, verbose_name='权重排序-越大越靠前')),
('parent_category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='父级分类')),
],
options={
'verbose_name': '分类',
'verbose_name_plural': '分类',
'ordering': ['-index'],
},
),
migrations.CreateModel(
name='Article',
fields=[
('id', models.AutoField(primary_key=True, serialize=False)),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
('title', models.CharField(max_length=200, unique=True, verbose_name='标题')),
('body', mdeditor.fields.MDTextField(verbose_name='正文')),
('pub_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='发布时间')),
('status', models.CharField(choices=[('d', '草稿'), ('p', '发表')], default='p', max_length=1, verbose_name='文章状态')),
('comment_status', models.CharField(choices=[('o', '打开'), ('c', '关闭')], default='o', max_length=1, verbose_name='评论状态')),
('type', models.CharField(choices=[('a', '文章'), ('p', '页面')], default='a', max_length=1, verbose_name='类型')),
('views', models.PositiveIntegerField(default=0, verbose_name='浏览量')),
('article_order', models.IntegerField(default=0, verbose_name='排序,数字越大越靠前')),
('show_toc', models.BooleanField(default=False, verbose_name='是否显示toc目录')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='作者')),
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.category', verbose_name='分类')),
('tags', models.ManyToManyField(blank=True, to='blog.tag', verbose_name='标签集合')),
],
options={
'verbose_name': '文章',
'verbose_name_plural': '文章',
'ordering': ['-article_order', '-pub_time'],
'get_latest_by': 'id',
},
),
]

@ -143,7 +143,8 @@ class ArticleTest(TestCase):
self.client.get("/admin/blog/article/1/delete/")
self.client.get('/admin/servermanager/emailsendlog/')
self.client.get('admin/admin/logentry/')
self.client.get('/admin/admin/logentry/')
self.client.get('/admin/admin/logentry/1/change/')
def __check_pagination__(self, p, type, value):
s = load_pagination_info(p.page(1), type, value)
@ -188,6 +189,14 @@ class ArticleTest(TestCase):
self.assertEqual(rsp.status_code, 404)
def test_commands(self):
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()
from blog.documents import ELASTICSEARCH_ENABLED
if ELASTICSEARCH_ENABLED:
call_command("build_index")

@ -0,0 +1,38 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('blog', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Comment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('body', models.TextField(max_length=300, verbose_name='正文')),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
('is_enable', models.BooleanField(default=True, verbose_name='是否显示')),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.article', verbose_name='文章')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='作者')),
('parent_comment', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comments.comment', verbose_name='上级评论')),
],
options={
'verbose_name': '评论',
'verbose_name_plural': '评论',
'ordering': ['-id'],
'get_latest_by': 'id',
},
),
]

@ -177,17 +177,10 @@ def save_user_avatar(url):
:param url:头像url
:return: 本地路径
'''
setting = get_blog_setting()
logger.info(url)
try:
basedir = os.path.join(settings.STATICFILES, 'avatar')
imgname = url.split('/')[-1]
if imgname:
path = f'{basedir}/{imgname}'
if os.path.exists(path):
os.remove(path)
rsp = requests.get(url, timeout=2)
if rsp.status_code == 200:
if not os.path.exists(basedir):
@ -203,7 +196,7 @@ def save_user_avatar(url):
return static('avatar/' + save_filename)
except Exception as e:
logger.error(e)
return url
return static('blog/img/avatar.png')
def delete_sidebar_cache():

@ -9,17 +9,17 @@ logger = logging.getLogger(__name__)
class OAuthUserAdmin(admin.ModelAdmin):
search_fields = ('nikename', 'email')
search_fields = ('nickname', 'email')
list_per_page = 20
list_display = (
'id',
'nikename',
'nickname',
'link_to_usermodel',
'show_user_image',
'type',
'email',
)
list_display_links = ('id', 'nikename')
list_display_links = ('id', 'nickname')
list_filter = ('author', 'type',)
readonly_fields = []

@ -0,0 +1,57 @@
# Generated by Django 4.1.7 on 2023-03-07 09:53
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='OAuthConfig',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', models.CharField(choices=[('weibo', '微博'), ('google', '谷歌'), ('github', 'GitHub'), ('facebook', 'FaceBook'), ('qq', 'QQ')], default='a', max_length=10, verbose_name='类型')),
('appkey', models.CharField(max_length=200, verbose_name='AppKey')),
('appsecret', models.CharField(max_length=200, verbose_name='AppSecret')),
('callback_url', models.CharField(default='http://www.baidu.com', max_length=200, verbose_name='回调地址')),
('is_enable', models.BooleanField(default=True, verbose_name='是否显示')),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
],
options={
'verbose_name': 'oauth配置',
'verbose_name_plural': 'oauth配置',
'ordering': ['-created_time'],
},
),
migrations.CreateModel(
name='OAuthUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('openid', models.CharField(max_length=50)),
('nickname', models.CharField(max_length=50, verbose_name='昵称')),
('token', models.CharField(blank=True, max_length=150, null=True)),
('picture', models.CharField(blank=True, max_length=350, null=True)),
('type', models.CharField(max_length=50)),
('email', models.CharField(blank=True, max_length=50, null=True)),
('metadata', models.TextField(blank=True, null=True)),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='修改时间')),
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户')),
],
options={
'verbose_name': 'oauth用户',
'verbose_name_plural': 'oauth用户',
'ordering': ['-created_time'],
},
),
]

@ -14,17 +14,17 @@ class OAuthUser(models.Model):
null=True,
on_delete=models.CASCADE)
openid = models.CharField(max_length=50)
nikename = models.CharField(max_length=50, verbose_name='昵称')
nickname = models.CharField(max_length=50, verbose_name='昵称')
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)
matedata = models.TextField(null=True, blank=True)
metadata = models.TextField(null=True, blank=True)
created_time = models.DateTimeField('创建时间', default=now)
last_mod_time = models.DateTimeField('修改时间', default=now)
def __str__(self):
return self.nikename
return self.nickname
class Meta:
verbose_name = 'oauth用户'
@ -55,8 +55,7 @@ class OAuthConfig(models.Model):
def clean(self):
if OAuthConfig.objects.filter(
type=self.type).exclude(
id=self.id).count():
type=self.type).exclude(id=self.id).count():
raise ValidationError(_(self.type + '已经存在'))
def __str__(self):

@ -51,6 +51,10 @@ class BaseOauthManager(metaclass=ABCMeta):
def get_oauth_userinfo(self):
pass
@abstractmethod
def get_picture(self, metadata):
pass
def do_get(self, url, params, headers=None):
rsp = requests.get(url=url, params=params, headers=headers)
logger.info(rsp.text)
@ -122,9 +126,9 @@ class WBOauthManager(BaseOauthManager):
try:
datas = json.loads(rsp)
user = OAuthUser()
user.matedata = rsp
user.metadata = rsp
user.picture = datas['avatar_large']
user.nikename = datas['screen_name']
user.nickname = datas['screen_name']
user.openid = datas['id']
user.type = 'weibo'
user.token = self.access_token
@ -136,6 +140,10 @@ class WBOauthManager(BaseOauthManager):
logger.error('weibo oauth error.rsp:' + rsp)
return None
def get_picture(self, metadata):
datas = json.loads(metadata)
return datas['avatar_large']
class GoogleOauthManager(BaseOauthManager):
AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
@ -197,9 +205,9 @@ class GoogleOauthManager(BaseOauthManager):
datas = json.loads(rsp)
user = OAuthUser()
user.matedata = rsp
user.metadata = rsp
user.picture = datas['picture']
user.nikename = datas['name']
user.nickname = datas['name']
user.openid = datas['sub']
user.token = self.access_token
user.type = 'google'
@ -211,6 +219,10 @@ class GoogleOauthManager(BaseOauthManager):
logger.error('google oauth error.rsp:' + rsp)
return None
def get_picture(self, metadata):
datas = json.loads(metadata)
return datas['picture']
class GitHubOauthManager(BaseOauthManager):
AUTH_URL = 'https://github.com/login/oauth/authorize'
@ -268,11 +280,11 @@ class GitHubOauthManager(BaseOauthManager):
datas = json.loads(rsp)
user = OAuthUser()
user.picture = datas['avatar_url']
user.nikename = datas['name']
user.nickname = datas['name']
user.openid = datas['id']
user.type = 'github'
user.token = self.access_token
user.matedata = rsp
user.metadata = rsp
if 'email' in datas and datas['email']:
user.email = datas['email']
return user
@ -281,6 +293,10 @@ class GitHubOauthManager(BaseOauthManager):
logger.error('github oauth error.rsp:' + rsp)
return None
def get_picture(self, metadata):
datas = json.loads(metadata)
return datas['avatar_url']
class FaceBookOauthManager(BaseOauthManager):
AUTH_URL = 'https://www.facebook.com/v2.10/dialog/oauth'
@ -337,11 +353,11 @@ class FaceBookOauthManager(BaseOauthManager):
rsp = self.do_get(self.API_URL, params)
datas = json.loads(rsp)
user = OAuthUser()
user.nikename = datas['name']
user.nickname = datas['name']
user.openid = datas['id']
user.type = 'facebook'
user.token = self.access_token
user.matedata = rsp
user.metadata = rsp
if 'email' in datas and datas['email']:
user.email = datas['email']
if 'picture' in datas and datas['picture'] and datas['picture']['data'] and datas['picture']['data']['url']:
@ -351,6 +367,10 @@ class FaceBookOauthManager(BaseOauthManager):
logger.error(e)
return None
def get_picture(self, metadata):
datas = json.loads(metadata)
return str(datas['picture']['data']['url'])
class QQOauthManager(BaseOauthManager):
AUTH_URL = 'https://graph.qq.com/oauth2.0/authorize'
@ -425,17 +445,21 @@ class QQOauthManager(BaseOauthManager):
logger.info(rsp)
obj = json.loads(rsp)
user = OAuthUser()
user.nikename = obj['nickname']
user.nickname = obj['nickname']
user.openid = openid
user.type = 'qq'
user.token = self.access_token
user.matedata = rsp
user.metadata = rsp
if 'email' in obj:
user.email = obj['email']
if 'figureurl' in obj:
user.picture = str(obj['figureurl'])
return user
def get_picture(self, metadata):
datas = json.loads(metadata)
return str(datas['figureurl'])
@cache_decorator(expiration=100 * 60)
def get_oauth_apps():

@ -72,13 +72,13 @@ def authorize(request):
return HttpResponseRedirect(manager.get_authorization_url(nexturl))
user = manager.get_oauth_userinfo()
if user:
if not user.nikename or not user.nikename.strip():
user.nikename = "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S')
if not user.nickname or not user.nickname.strip():
user.nickname = "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S')
try:
temp = OAuthUser.objects.get(type=type, openid=user.openid)
temp.picture = user.picture
temp.matedata = user.matedata
temp.nikename = user.nikename
temp.metadata = user.metadata
temp.nickname = user.nickname
user = temp
except ObjectDoesNotExist:
pass
@ -97,9 +97,9 @@ def authorize(request):
author = result[0]
if result[1]:
try:
get_user_model().objects.get(username=user.nikename)
get_user_model().objects.get(username=user.nickname)
except ObjectDoesNotExist:
author.username = user.nikename
author.username = user.nickname
else:
author.username = "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S')
author.source = 'authorize'
@ -139,7 +139,7 @@ def emailconfirm(request, id, sign):
author = result[0]
if result[1]:
author.source = 'emailconfirm'
author.username = oauthuser.nikename.strip() if oauthuser.nikename.strip(
author.username = oauthuser.nickname.strip() if oauthuser.nickname.strip(
) else "djangoblog" + timezone.now().strftime('%y%m%d%I%M%S')
author.save()
oauthuser.author = author

@ -0,0 +1,31 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='OwnTrackLog',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tid', models.CharField(max_length=100, verbose_name='用户')),
('lat', models.FloatField(verbose_name='纬度')),
('lon', models.FloatField(verbose_name='经度')),
('created_time', models.DateTimeField(default=django.utils.timezone.now, verbose_name='创建时间')),
],
options={
'verbose_name': 'OwnTrackLogs',
'verbose_name_plural': 'OwnTrackLogs',
'ordering': ['created_time'],
'get_latest_by': 'created_time',
},
),
]

@ -58,7 +58,7 @@ class OwnTrackLogTest(TestCase):
self.assertEqual(rsp.status_code, 200)
rsp = self.client.get('/owntracks/show_maps')
self.assertEqual(rsp.status_code, 200)
# rsp = self.client.get('/owntracks/get_datas')
# self.assertEqual(rsp.status_code, 200)
# rsp = self.client.get('/owntracks/get_datas?date=2018-02-26')
# self.assertEqual(rsp.status_code, 200)
rsp = self.client.get('/owntracks/get_datas')
self.assertEqual(rsp.status_code, 200)
rsp = self.client.get('/owntracks/get_datas?date=2018-02-26')
self.assertEqual(rsp.status_code, 200)

@ -86,7 +86,8 @@ def convert_to_amap(locations):
}
rsp = requests.get(url=api, params=query)
result = json.loads(rsp.text)
convert_result.append(result['locations'])
if "locations" in result:
convert_result.append(result['locations'])
item = list(itertools.islice(it, 30))
return ";".join(convert_result)

@ -3,7 +3,7 @@ bleach==6.0.0
Django==4.1.7
django-compressor==4.3.1
django-haystack==3.2.1
django-ipware==4.0.2
django-ipware==5.0.0
django-mdeditor==0.1.20
django-uuslug==2.0.0
elasticsearch==7.16.1

@ -0,0 +1,45 @@
# Generated by Django 4.1.7 on 2023-03-02 07:14
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='commands',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=300, verbose_name='命令标题')),
('command', models.CharField(max_length=2000, verbose_name='命令')),
('describe', models.CharField(max_length=300, verbose_name='命令描述')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('last_mod_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
],
options={
'verbose_name': '命令',
'verbose_name_plural': '命令',
},
),
migrations.CreateModel(
name='EmailSendLog',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('emailto', models.CharField(max_length=300, verbose_name='收件人')),
('title', models.CharField(max_length=2000, verbose_name='邮件标题')),
('content', models.TextField(verbose_name='邮件内容')),
('send_result', models.BooleanField(default=False, verbose_name='结果')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
],
options={
'verbose_name': '邮件发送log',
'verbose_name_plural': '邮件发送log',
'ordering': ['-created_time'],
},
),
]
Loading…
Cancel
Save