From 9ba6f815e1500ee0f30600e53b5aedb643fe7f84 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sat, 26 Mar 2022 23:34:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0vod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0033_workscope_courses.py | 19 +++++ test_server/examtest/models_paper.py | 2 + test_server/rbac/views/role.py | 2 + test_server/server/settings.py | 3 +- test_server/server/urls.py | 1 + test_server/utils/response.py | 1 + test_server/vod/__init__.py | 0 test_server/vod/admin.py | 3 + test_server/vod/apps.py | 5 ++ test_server/vod/migrations/0001_initial.py | 72 ++++++++++++++++++ .../vod/migrations/0002_auto_20220326_2305.py | 26 +++++++ test_server/vod/migrations/__init__.py | 0 test_server/vod/models.py | 37 ++++++++++ test_server/vod/serializers.py | 14 ++++ test_server/vod/tests.py | 3 + test_server/vod/urls.py | 13 ++++ test_server/vod/views.py | 72 ++++++++++++++++++ test_server/vod/vodclient.py | 73 +++++++++++++++++++ 18 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 test_server/examtest/migrations/0033_workscope_courses.py create mode 100644 test_server/vod/__init__.py create mode 100644 test_server/vod/admin.py create mode 100644 test_server/vod/apps.py create mode 100644 test_server/vod/migrations/0001_initial.py create mode 100644 test_server/vod/migrations/0002_auto_20220326_2305.py create mode 100644 test_server/vod/migrations/__init__.py create mode 100644 test_server/vod/models.py create mode 100644 test_server/vod/serializers.py create mode 100644 test_server/vod/tests.py create mode 100644 test_server/vod/urls.py create mode 100644 test_server/vod/views.py create mode 100644 test_server/vod/vodclient.py diff --git a/test_server/examtest/migrations/0033_workscope_courses.py b/test_server/examtest/migrations/0033_workscope_courses.py new file mode 100644 index 0000000..9d392d7 --- /dev/null +++ b/test_server/examtest/migrations/0033_workscope_courses.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.4 on 2022-03-26 15:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('vod', '0001_initial'), + ('examtest', '0032_auto_20210613_2234'), + ] + + operations = [ + migrations.AddField( + model_name='workscope', + name='courses', + field=models.ManyToManyField(to='vod.Course', verbose_name='所选课程'), + ), + ] diff --git a/test_server/examtest/models_paper.py b/test_server/examtest/models_paper.py index 7f896a6..beef981 100644 --- a/test_server/examtest/models_paper.py +++ b/test_server/examtest/models_paper.py @@ -3,6 +3,7 @@ from django.template.defaultfilters import default from rbac.models import SoftCommonModel, CommonModel from django.contrib.postgres.fields import JSONField, ArrayField from question.models import Questioncat, Question +from vod.models import Course @@ -36,6 +37,7 @@ class WorkScope(CommonModel): sortnum = models.IntegerField('排序码', default=1) is_public = models.BooleanField('是否公开', default=True) # can_choose = models.BooleanField('客户是否可选择', default=False) + courses = models.ManyToManyField(Course, verbose_name='所选课程') class Meta: verbose_name = '工作类别' diff --git a/test_server/rbac/views/role.py b/test_server/rbac/views/role.py index a7895b1..29b989d 100644 --- a/test_server/rbac/views/role.py +++ b/test_server/rbac/views/role.py @@ -6,6 +6,8 @@ from utils.custom import CommonPagination from ..permission import RbacPermission from ..models import Role from ..serializers.role_serializer import RoleListSerializer, RoleModifySerializer +from rest_framework.response import Response +from rest_framework import status class RoleViewSet(ModelViewSet): diff --git a/test_server/server/settings.py b/test_server/server/settings.py index 85d948e..2747486 100644 --- a/test_server/server/settings.py +++ b/test_server/server/settings.py @@ -49,7 +49,8 @@ INSTALLED_APPS = [ 'analyse', 'cms', 'qtest', - 'develop' + 'develop', + 'vod' ] MIDDLEWARE = [ diff --git a/test_server/server/urls.py b/test_server/server/urls.py index c6cc82f..8a99d12 100644 --- a/test_server/server/urls.py +++ b/test_server/server/urls.py @@ -25,6 +25,7 @@ from utils.view import redirect urlpatterns = [ path('rbac/', include('rbac.urls')), + path('vod/', include('vod.urls')), path('develop/', include('develop.urls')), path('crm/', include('crm.urls')), path('question/', include('question.urls')), diff --git a/test_server/utils/response.py b/test_server/utils/response.py index e97d94a..8bcf799 100644 --- a/test_server/utils/response.py +++ b/test_server/utils/response.py @@ -45,6 +45,7 @@ class FitJSONRenderer(JSONRenderer): response = renderer_context.get("response") response_body.code = response.status_code if response_body.code >= 400: # drf异常 + response_body.data = data if isinstance(data, dict): data = data[list(data.keys())[0]] if isinstance(data, list): diff --git a/test_server/vod/__init__.py b/test_server/vod/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test_server/vod/admin.py b/test_server/vod/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/test_server/vod/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/test_server/vod/apps.py b/test_server/vod/apps.py new file mode 100644 index 0000000..d5b0761 --- /dev/null +++ b/test_server/vod/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class VodConfig(AppConfig): + name = 'vod' diff --git a/test_server/vod/migrations/0001_initial.py b/test_server/vod/migrations/0001_initial.py new file mode 100644 index 0000000..fee6a75 --- /dev/null +++ b/test_server/vod/migrations/0001_initial.py @@ -0,0 +1,72 @@ +# Generated by Django 3.0.4 on 2022-03-13 14:41 + +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='Course', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_delete', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=200, verbose_name='名称')), + ('description', models.TextField(blank=True, null=True, verbose_name='课程介绍')), + ('sort', models.IntegerField(default=1, verbose_name='排序数字')), + ('create_admin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='course_create_admin', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Video', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_delete', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=100, verbose_name='视频名称')), + ('description', models.TextField(blank=True, null=True, verbose_name='视频描述')), + ('fileid', models.CharField(max_length=200, unique=True, verbose_name='云点播视频id')), + ('mediaurl', models.CharField(max_length=200, verbose_name='视频地址')), + ('coverurl', models.CharField(max_length=200, verbose_name='封面地址')), + ('duration', models.IntegerField(default=0, verbose_name='时长(秒)')), + ('views', models.IntegerField(default=0, verbose_name='观看次数')), + ('viewsp', models.IntegerField(default=0, verbose_name='观看人数')), + ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='vod.Course', verbose_name='所属课程')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='VRecord', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_delete', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('views', models.PositiveIntegerField(default=0, verbose_name='观看次数')), + ('completed', models.BooleanField(default=False, verbose_name='是否观看完成')), + ('current', models.PositiveIntegerField(default=0, verbose_name='当前观看进度(秒)')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='viewrecord_user', to=settings.AUTH_USER_MODEL, verbose_name='观看人')), + ('video', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='record_video', to='vod.Video', verbose_name='点播视频')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/test_server/vod/migrations/0002_auto_20220326_2305.py b/test_server/vod/migrations/0002_auto_20220326_2305.py new file mode 100644 index 0000000..0513d4f --- /dev/null +++ b/test_server/vod/migrations/0002_auto_20220326_2305.py @@ -0,0 +1,26 @@ +# Generated by Django 3.0.4 on 2022-03-26 15:05 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('crm', '0040_auto_20220215_2120'), + ('vod', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='vrecord', + name='user', + ), + migrations.AddField( + model_name='vrecord', + name='consumer', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='viewrecord_consumer', to='crm.Consumer', verbose_name='观看人'), + preserve_default=False, + ), + ] diff --git a/test_server/vod/migrations/__init__.py b/test_server/vod/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test_server/vod/models.py b/test_server/vod/models.py new file mode 100644 index 0000000..b3f60f0 --- /dev/null +++ b/test_server/vod/models.py @@ -0,0 +1,37 @@ +from django.db import models +from rbac.models import CommonModel, UserProfile + +# Create your models here. +class Course(CommonModel): + """ + 视频课程分类 + """ + name = models.CharField(max_length=200, verbose_name='名称') + description = models.TextField(verbose_name='课程介绍', null=True, blank=True) + sort = models.IntegerField(default=1, verbose_name='排序数字') + create_admin = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True, blank=True, related_name='course_create_admin') + +class Video(CommonModel): + """ + 视频 + """ + name = models.CharField(verbose_name='视频名称', max_length=100) + course = models.ForeignKey(Course, verbose_name='所属课程', on_delete=models.CASCADE) + description = models.TextField(verbose_name='视频描述', null=True, blank=True) + fileid = models.CharField(verbose_name='云点播视频id', unique=True, max_length=200) + mediaurl = models.CharField(verbose_name='视频地址', max_length=200) + coverurl = models.CharField(verbose_name='封面地址', max_length=200) + duration = models.IntegerField(verbose_name='时长(秒)', default=0) + views = models.IntegerField(verbose_name='观看次数', default=0) + viewsp = models.IntegerField(verbose_name='观看人数', default=0) + +class VRecord(CommonModel): + + """ + 观看记录 + """ + consumer = models.ForeignKey('crm.consumer', on_delete=models.CASCADE, verbose_name='观看人', related_name='viewrecord_consumer') + views = models.PositiveIntegerField(verbose_name='观看次数', default=0) + completed = models.BooleanField(verbose_name='是否观看完成', default=False) + current = models.PositiveIntegerField(verbose_name='当前观看进度(秒)', default=0) + video = models.ForeignKey(Video, verbose_name='点播视频', on_delete=models.CASCADE, related_name='record_video') \ No newline at end of file diff --git a/test_server/vod/serializers.py b/test_server/vod/serializers.py new file mode 100644 index 0000000..e2dbbb2 --- /dev/null +++ b/test_server/vod/serializers.py @@ -0,0 +1,14 @@ +from rest_framework import serializers + +from vod.models import Course, Video + +class CourseSerializer(serializers.ModelSerializer): + class Meta: + model = Course + fields = '__all__' + +class VideoSerializer(serializers.ModelSerializer): + course_name = serializers.CharField(source='course.name', read_only=True) + class Meta: + model = Video + fields = '__all__' \ No newline at end of file diff --git a/test_server/vod/tests.py b/test_server/vod/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/test_server/vod/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/test_server/vod/urls.py b/test_server/vod/urls.py new file mode 100644 index 0000000..bc05c54 --- /dev/null +++ b/test_server/vod/urls.py @@ -0,0 +1,13 @@ + +from django.urls import path,include +from rest_framework import routers + +from vod.views import CourseViewSet, VideoViewSet, SignatureAPIView + +router = routers.DefaultRouter() +router.register('course', CourseViewSet, basename='course') +router.register('video', VideoViewSet, basename='video') +urlpatterns = [ + path('signature/', SignatureAPIView.as_view()), + path('', include(router.urls)), +] \ No newline at end of file diff --git a/test_server/vod/views.py b/test_server/vod/views.py new file mode 100644 index 0000000..ec0c200 --- /dev/null +++ b/test_server/vod/views.py @@ -0,0 +1,72 @@ +from django.shortcuts import render +from rest_framework.viewsets import ModelViewSet +from rest_framework.views import APIView +from vod.models import Course, Video +from rest_framework.response import Response +from vod.serializers import CourseSerializer, VideoSerializer +from vod.vodclient import getSignature +from utils.custom import CommonPagination +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.filters import OrderingFilter, SearchFilter +from django.db.models import Q +# Create your views here. + +class CourseViewSet(ModelViewSet): + queryset = Course.objects.all() + serializer_class = CourseSerializer + ordering = ['id'] + perms_map = [ + {'get': '*'}, {'post': 'vod'}, + {'put': 'vod'}, {'delete': 'vod'}] + def get_queryset(self): + queryset = self.queryset + if hasattr(self.get_serializer_class(), 'setup_eager_loading'): + queryset = self.get_serializer_class().setup_eager_loading(queryset) + if self.request.user.is_superuser: + return queryset + roles = self.request.user.roles.values_list('name', flat=True) + if '普通管理' in roles: + queryset = queryset.filter(Q(create_admin = self.request.user)|Q(create_admin=self.request.user)) + else: + return queryset.none() + return queryset + + def perform_create(self, serializer): + serializer.save(create_admin=self.request.user) + + def perform_update(self, serializer): + ret = serializer.validated_data + return super().perform_update(serializer) + +class VideoViewSet(ModelViewSet): + queryset = Video.objects.all() + filterset_fields = ['course'] + pagination_class = CommonPagination + serializer_class = VideoSerializer + filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter] + ordering = ['-id'] + perms_map = [ + {'get': '*'}, {'post': 'vod'}, + {'put': 'vod'}, {'delete': 'vod'}] + def get_queryset(self): + queryset = self.queryset + if hasattr(self.get_serializer_class(), 'setup_eager_loading'): + queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化 + if self.request.user.is_superuser: + return queryset + roles = self.request.user.roles.values_list('name', flat=True) + if '普通管理' in roles: + queryset = queryset.filter(course__create_admin = self.request.user) + else: + return queryset.none() + return queryset + + +class SignatureAPIView(APIView): + perms_map = [{'get': 'vod'}] + def get(self, request, format=None): + """ + 获取上传签名 + """ + signature = getSignature(procedure=request.query_params.get('procedure', None)) + return Response({'signature':signature}) \ No newline at end of file diff --git a/test_server/vod/vodclient.py b/test_server/vod/vodclient.py new file mode 100644 index 0000000..0d20aa7 --- /dev/null +++ b/test_server/vod/vodclient.py @@ -0,0 +1,73 @@ +import base64 +import hashlib +import hmac +import json +import random +import time + +from rest_framework.response import Response +from rest_framework.status import HTTP_400_BAD_REQUEST +from tencentcloud.common import credential +from tencentcloud.common.exception.tencent_cloud_sdk_exception import \ + TencentCloudSDKException +from tencentcloud.common.profile.client_profile import ClientProfile +from tencentcloud.common.profile.http_profile import HttpProfile +from tencentcloud.vod.v20180717 import models, vod_client + +SecretId = 'AKIDa8RTEiwsYw4uTlpc8NL2SbS2MO9droUu' +SecretKey = 'A3f04oHTO1NSGn20Xpqa2D8l8D2aqpXy' + +# 初始化点播client +def initClient(): + cred = credential.Credential(SecretId, SecretKey) + httpProfile = HttpProfile() + httpProfile.endpoint = "vod.tencentcloudapi.com" + clientProfile = ClientProfile() + clientProfile.httpProfile = httpProfile + client = vod_client.VodClient(cred, "", clientProfile) + return client + +def doResponse(res): + # 处理返回结果 + # 转变为常用返回Response + if hasattr(res, 'Error'): + return Response(res._serialize(allow_none=True), status=HTTP_400_BAD_REQUEST) + return Response(res._serialize(allow_none=True)) + +def getAllClass(params={}): + # 获取所有分类 + try: + client = initClient() + req = models.DescribeAllClassRequest() + req.from_json_string(json.dumps(params)) + resp = client.DescribeAllClass(req) + return doResponse(resp) + except TencentCloudSDKException as err: + print(err) + +def searchMedia(params={}): + try: + client = initClient() + req = models.SearchMediaRequest() + req.from_json_string(json.dumps(params)) + resp = client.SearchMedia(req) + return doResponse(resp) + except TencentCloudSDKException as err: + print(err) + +def getSignature(procedure=None): + """ + 获取上传签名 + 可指定 + """ + TimeStamp = int(time.time()) + ExpireTime = TimeStamp + 86400 * 365 * 10 + Random = random.randint(0, 999999) + Original = "secretId=" + SecretId + "¤tTimeStamp=" + str(TimeStamp) + "&expireTime=" + str(ExpireTime) + "&random=" + str(Random) + if procedure: + Original = Original + "&procedure="+procedure + Hmac = hmac.new(bytes(SecretKey, 'utf-8'), bytes(Original, 'utf-8'), hashlib.sha1) + Sha1 = Hmac.digest() + Signature = bytes(Sha1) + bytes(Original, 'utf-8') + Signature2 = base64.b64encode(Signature) + return str(Signature2, 'UTF-8')