merge origin/main: adopt env-var secrets fix, keep no-SQLite structure
This commit is contained in:
+6
-4
@@ -417,8 +417,9 @@ class ArticleLikeToggleView(APIView):
|
|||||||
like, created = ArticleLike.objects.get_or_create(user=request.user, article=article)
|
like, created = ArticleLike.objects.get_or_create(user=request.user, article=article)
|
||||||
if not created:
|
if not created:
|
||||||
like.delete()
|
like.delete()
|
||||||
article.likes = max(0, article.likes - 1)
|
Article.objects.filter(pk=pk).update(likes=F("likes") - 1)
|
||||||
article.save(update_fields=['likes'])
|
article.refresh_from_db()
|
||||||
|
article.likes = max(0, article.likes)
|
||||||
return create_standardized_response(
|
return create_standardized_response(
|
||||||
data={'liked': False, 'likes_count': article.likes},
|
data={'liked': False, 'likes_count': article.likes},
|
||||||
code=ResponseCode.SUCCESS
|
code=ResponseCode.SUCCESS
|
||||||
@@ -498,8 +499,9 @@ class ArticleCommentLikeToggleView(APIView):
|
|||||||
like, created = ArticleCommentLike.objects.get_or_create(user=request.user, comment=comment)
|
like, created = ArticleCommentLike.objects.get_or_create(user=request.user, comment=comment)
|
||||||
if not created:
|
if not created:
|
||||||
like.delete()
|
like.delete()
|
||||||
comment.likes = max(0, comment.likes - 1)
|
ArticleComment.objects.filter(pk=pk).update(likes=F("likes") - 1)
|
||||||
comment.save(update_fields=['likes'])
|
comment.refresh_from_db()
|
||||||
|
comment.likes = max(0, comment.likes)
|
||||||
return create_standardized_response(
|
return create_standardized_response(
|
||||||
data={'liked': False, 'likes_count': comment.likes},
|
data={'liked': False, 'likes_count': comment.likes},
|
||||||
code=ResponseCode.SUCCESS
|
code=ResponseCode.SUCCESS
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'django-insecure-j+-psq=m++l7hup73k1eg+wm-b&2_)!+_^o=6(=xc$1px*kqt@'
|
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'django-insecure-dev-only-key-change-in-production')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = os.environ.get('DJANGO_DEBUG', 'True') == 'True'
|
DEBUG = os.environ.get('DJANGO_DEBUG', 'True') == 'True'
|
||||||
@@ -66,7 +66,7 @@ CORS_ALLOWED_ORIGINS = [
|
|||||||
]
|
]
|
||||||
CORS_ALLOW_ALL_ORIGINS = False
|
CORS_ALLOW_ALL_ORIGINS = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
|
||||||
|
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
CORS_ALLOW_HEADERS = [
|
CORS_ALLOW_HEADERS = [
|
||||||
@@ -127,7 +127,7 @@ EMAIL_HOST = 'smtp.qq.com'
|
|||||||
EMAIL_PORT = 465
|
EMAIL_PORT = 465
|
||||||
EMAIL_USE_SSL = True
|
EMAIL_USE_SSL = True
|
||||||
EMAIL_HOST_USER = 'cs10086086@qq.com'
|
EMAIL_HOST_USER = 'cs10086086@qq.com'
|
||||||
EMAIL_HOST_PASSWORD = 'ldzpymytsinkfjhb'
|
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', '')
|
||||||
EMAIL_USE_TLS = False
|
EMAIL_USE_TLS = False
|
||||||
|
|
||||||
AUTH_USER_MODEL = 'user.FUser'
|
AUTH_USER_MODEL = 'user.FUser'
|
||||||
@@ -173,7 +173,7 @@ DATABASES = {
|
|||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'chunyu_project',
|
'NAME': 'chunyu_project',
|
||||||
'USER': 'root',
|
'USER': 'root',
|
||||||
'PASSWORD': 'mysql_NpyMCS',
|
'PASSWORD': os.environ.get('MYSQL_PASSWORD', ''),
|
||||||
'HOST': '192.168.5.7',
|
'HOST': '192.168.5.7',
|
||||||
'PORT': '3306',
|
'PORT': '3306',
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
@@ -189,7 +189,7 @@ DATABASES = {
|
|||||||
REDIS_HOST = '192.168.5.7'
|
REDIS_HOST = '192.168.5.7'
|
||||||
REDIS_PORT = 6379
|
REDIS_PORT = 6379
|
||||||
REDIS_DB = 0
|
REDIS_DB = 0
|
||||||
REDIS_PASSWORD = 'jhkdjhkjdhsIUTYURTU_sx86Jf'
|
REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD', '')
|
||||||
SESSION_DB = 1
|
SESSION_DB = 1
|
||||||
CELERY_BROKER_DB = 2
|
CELERY_BROKER_DB = 2
|
||||||
CELERY_RESULT_BACKEND_DB = 2
|
CELERY_RESULT_BACKEND_DB = 2
|
||||||
|
|||||||
+12
-5
@@ -500,10 +500,14 @@ class CDNStaticFileView(APIView):
|
|||||||
)
|
)
|
||||||
if not os.path.exists(file_path):
|
if not os.path.exists(file_path):
|
||||||
raise Http404
|
raise Http404
|
||||||
response = FileResponse(open(file_path, 'rb'), content_type='text/markdown; charset=utf-8')
|
fh = open(file_path, "rb")
|
||||||
response['Cache-Control'] = 'max-age=86400'
|
try:
|
||||||
return response
|
response = FileResponse(fh, content_type="text/markdown; charset=utf-8")
|
||||||
|
response["Cache-Control"] = "max-age=86400"
|
||||||
|
return response
|
||||||
|
except Exception:
|
||||||
|
fh.close()
|
||||||
|
raise
|
||||||
|
|
||||||
class CourseFavoriteToggleView(APIView):
|
class CourseFavoriteToggleView(APIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
@@ -745,7 +749,10 @@ class MyProgressView(APIView):
|
|||||||
'last_studied_at': read.completed_at,
|
'last_studied_at': read.completed_at,
|
||||||
}
|
}
|
||||||
course_map[course_id]['completed_chapters'] += 1
|
course_map[course_id]['completed_chapters'] += 1
|
||||||
if read.completed_at > course_map[course_id]['last_studied_at']:
|
if read.completed_at and (
|
||||||
|
not course_map[course_id]['last_studied_at'] or
|
||||||
|
read.completed_at > course_map[course_id]['last_studied_at']
|
||||||
|
):
|
||||||
course_map[course_id]['last_studied_at'] = read.completed_at
|
course_map[course_id]['last_studied_at'] = read.completed_at
|
||||||
|
|
||||||
courses = []
|
courses = []
|
||||||
|
|||||||
+9
-15
@@ -67,8 +67,8 @@ class GlobalSearchView(APIView):
|
|||||||
|
|
||||||
for article in articles:
|
for article in articles:
|
||||||
cover_url = ''
|
cover_url = ''
|
||||||
if article.cover and hasattr(article.cover, 'url'):
|
if article.cover_image and hasattr(article.cover_image, 'url'):
|
||||||
cover_url = request.build_absolute_uri(article.cover.url)
|
cover_url = request.build_absolute_uri(article.cover_image.url)
|
||||||
|
|
||||||
excerpt = article.excerpt or ''
|
excerpt = article.excerpt or ''
|
||||||
if not excerpt and article.content:
|
if not excerpt and article.content:
|
||||||
@@ -91,21 +91,16 @@ class GlobalSearchView(APIView):
|
|||||||
).order_by('-created_at')[:100]
|
).order_by('-created_at')[:100]
|
||||||
|
|
||||||
for tool in tools:
|
for tool in tools:
|
||||||
cover_url = ''
|
|
||||||
if tool.icon and hasattr(tool.icon, 'url'):
|
|
||||||
cover_url = request.build_absolute_uri(tool.icon.url)
|
|
||||||
|
|
||||||
results.append({
|
results.append({
|
||||||
'id': tool.id,
|
'id': tool.id,
|
||||||
'type': '工具',
|
'type': '工具',
|
||||||
'title': tool.name,
|
'title': tool.name,
|
||||||
'desc': tool.description or '',
|
'desc': tool.description or '',
|
||||||
'cover': cover_url,
|
'cover': '',
|
||||||
'views': tool.views or 0,
|
'views': tool.usage_count or 0,
|
||||||
'likes': tool.likes or 0,
|
'likes': 0,
|
||||||
'url': f'/use?tool={tool.id}',
|
'url': f'/use?tool={tool.id}',
|
||||||
})
|
})
|
||||||
|
|
||||||
if content_type == 'all' or content_type == 'course':
|
if content_type == 'all' or content_type == 'course':
|
||||||
courses = Course.objects.filter(
|
courses = Course.objects.filter(
|
||||||
Q(title__icontains=q) | Q(description__icontains=q)
|
Q(title__icontains=q) | Q(description__icontains=q)
|
||||||
@@ -113,8 +108,8 @@ class GlobalSearchView(APIView):
|
|||||||
|
|
||||||
for course in courses:
|
for course in courses:
|
||||||
cover_url = ''
|
cover_url = ''
|
||||||
if course.cover and hasattr(course.cover, 'url'):
|
if course.cover_image and hasattr(course.cover_image, 'url'):
|
||||||
cover_url = request.build_absolute_uri(course.cover.url)
|
cover_url = request.build_absolute_uri(course.cover_image.url)
|
||||||
|
|
||||||
results.append({
|
results.append({
|
||||||
'id': course.id,
|
'id': course.id,
|
||||||
@@ -122,9 +117,8 @@ class GlobalSearchView(APIView):
|
|||||||
'title': course.title,
|
'title': course.title,
|
||||||
'desc': course.description or '',
|
'desc': course.description or '',
|
||||||
'cover': cover_url,
|
'cover': cover_url,
|
||||||
'views': course.views or 0,
|
'views': 0,
|
||||||
'likes': course.likes or 0,
|
'likes': 0,
|
||||||
'url': f'/courses/{course.id}',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if content_type == 'all' or content_type == 'api':
|
if content_type == 'all' or content_type == 'api':
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ from django.core.cache import caches
|
|||||||
default_cache = caches['default']
|
default_cache = caches['default']
|
||||||
session_cache = caches['session']
|
session_cache = caches['session']
|
||||||
celery_cache = caches['celery']
|
celery_cache = caches['celery']
|
||||||
from ..models import FUser, LoginRecord
|
from ..models import FUser, LoginRecord, Follow
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
from rest_framework_simplejwt.tokens import RefreshToken
|
||||||
from ..serializers.user_serializers import UserSerializer, ChangePasswordSerializer, UserUpdateSerializer
|
from ..serializers.user_serializers import UserSerializer, ChangePasswordSerializer, UserUpdateSerializer
|
||||||
from ..tasks import send_verification_email_task, send_reset_password_email_task
|
from ..tasks import send_verification_email_task, send_reset_password_email_task
|
||||||
|
|||||||
Reference in New Issue
Block a user