Init
0 parents
Showing
38 changed files
with
9468 additions
and
0 deletions
.DS_Store
0 → 100644
No preview for this file type
.gitignore
0 → 100644
Dockerfile
0 → 100644
1 | # 使用方 Python 基础镜像作为基础 | ||
2 | FROM python:3.7.4 | ||
3 | |||
4 | # 设置工目录 | ||
5 | WORKDIR / | ||
6 | |||
7 | RUN apt-get update && apt-get install -y libsndfile1 ffmpeg | ||
8 | |||
9 | # 将 requirements.txt 复到容器中 | ||
10 | COPY requirements.txt . | ||
11 | |||
12 | # 安装赖包 | ||
13 | RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ | ||
14 | # 将整个项目复制到容器中 | ||
15 | COPY . . | ||
16 | |||
17 | # 运行 Django 服务器 | ||
18 | CMD python manage.py runserver 0.0.0.0:8000 | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
HisinApi/.DS_Store
0 → 100644
No preview for this file type
HisinApi/__init__.py
0 → 100644
HisinApi/asgi.py
0 → 100644
1 | """ | ||
2 | ASGI config for HisinApi project. | ||
3 | |||
4 | It exposes the ASGI callable as a module-level variable named ``application``. | ||
5 | |||
6 | For more information on this file, see | ||
7 | https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/ | ||
8 | """ | ||
9 | |||
10 | import os | ||
11 | |||
12 | from django.core.asgi import get_asgi_application | ||
13 | |||
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'HisinApi.settings') | ||
15 | |||
16 | application = get_asgi_application() |
HisinApi/urls.py
0 → 100644
1 | """HisinApi URL Configuration | ||
2 | |||
3 | The `urlpatterns` list routes URLs to views. For more information please see: | ||
4 | https://docs.djangoproject.com/en/4.0/topics/http/urls/ | ||
5 | Examples: | ||
6 | Function views | ||
7 | 1. Add an import: from my_app import views | ||
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') | ||
9 | Class-based views | ||
10 | 1. Add an import: from other_app.views import Home | ||
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') | ||
12 | Including another URLconf | ||
13 | 1. Import the include() function: from django.urls import include, path | ||
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) | ||
15 | """ | ||
16 | from django.contrib import admin | ||
17 | from django.urls import path | ||
18 | from api.ApiList import login,index,audition,my,notifications,appversion,community | ||
19 | |||
20 | urlpatterns = [ | ||
21 | #登录注册模块 | ||
22 | path('admin', admin.site.urls), | ||
23 | path('', index.index), | ||
24 | path('api/sendsms',login.sendsms), | ||
25 | path('api/v2/sendsms', login.v2sendsms), | ||
26 | path('api/login', login.user_login), | ||
27 | path('api/sms_verify/login', login.sms_verify_login), | ||
28 | path('api/wechat/auth', login.wechatAuth), | ||
29 | path('api/register', login.register), | ||
30 | path('api/v2/register', login.v2register), | ||
31 | path('api/v3/register', login.v3register), | ||
32 | path('api/reset', login.restPwd), | ||
33 | path('api/business_list', login.businessList), | ||
34 | #首页模块 | ||
35 | path('api/user', index.user), | ||
36 | path('api/activity/view', index.UserViewActivity), | ||
37 | path('api/examines', index.Examines.as_view()), #注册用户待审核列表 | ||
38 | path('api/activitys', index.GetActivitys.as_view()), | ||
39 | path('api/v2/activitys', index.V2GetActivitys.as_view()), #去掉收藏活动 | ||
40 | path('api/v3/activitys', index.V3GetActivitys.as_view()), #加入收藏活动 | ||
41 | path('api/examine_status', index.examineStatus.as_view()), | ||
42 | path('api/banner', index.banners), | ||
43 | path('api/v2/banner', index.v2banners), | ||
44 | path('api/banner/detail', index.bannerDetail), | ||
45 | path('api/activity/attend_user',index.GetActivityUser.as_view() ), | ||
46 | path('api/activity/unlike', index.Unlike.as_view()), | ||
47 | path('api/activity/completes', index.GetCompleteActivity.as_view()), | ||
48 | path('api/events', index.Events), | ||
49 | path('api/action', index.Action), | ||
50 | path('api/band_list', index.BandList.as_view()), | ||
51 | path('api/band_detail', index.BandDetail.as_view()), | ||
52 | path('api/band_link_activity', index.BandLinkActivity.as_view()), | ||
53 | path('api/activity/recommend', index.RecommenCasedList.as_view()), | ||
54 | |||
55 | #我的模块 | ||
56 | path('api/upload', my.upload), | ||
57 | path('api/user/avatar',my.updateUserAvatar), | ||
58 | path('api/user/activitys',my.MyActivitys.as_view()), | ||
59 | path('api/user/activity_detail', my.SaveOrSubmitList), | ||
60 | path('api/v2/user/activity_detail', my.V2SaveOrSubmitList), | ||
61 | path('api/user/activity_sumbit', my.UpdateSumbit), | ||
62 | path('api/user/submit_examine', my.SubmitExamine), | ||
63 | path('api/v2/user/submit_examine', my.V2SubmitExamine), | ||
64 | path('api/user/set_tag', my.SetUserTags), | ||
65 | path('api/user/tag_list', my.getUserTag), | ||
66 | path('api/user/unbind', my.unbind), | ||
67 | path('api/user/bind', my.bind), | ||
68 | path('api/admin/activitys', my.AdminActivitys.as_view()), | ||
69 | path('api/admin/submit_list', my.AdminSubmitList), | ||
70 | path('api/v2/admin/submit_list', my.V2AdminSubmitList), | ||
71 | path('api/user/singer_list', my.MySinget.as_view()), | ||
72 | path('api/user/singer', my.SingerInfo.as_view()), | ||
73 | path('api/v2/user/singer', my.SingerInfoV2.as_view()), | ||
74 | path('api/user/singer/avtivitys', my.SingerAvtivity.as_view()), | ||
75 | path('api/user/singer/complete', my.SingerComplete.as_view()), #我的歌手-被选中 | ||
76 | path('api/user/singer/avtivity_detail', my.AvtivityDetail.as_view()), | ||
77 | path('api/user/banner', my.banners), | ||
78 | path('api/user/listen', my.Listen.as_view()), | ||
79 | path('api/user/ta_collection', my.TaCollection.as_view()), | ||
80 | path('api/user/ta_audition', my.TaAudition.as_view()), | ||
81 | path('api/user/resume_like', my.ResumeLike.as_view()), | ||
82 | path('api/user/remove_save', my.remove_save), | ||
83 | path('api/user/editor', my.editor), | ||
84 | path('api/user/change_phone', my.change_phone), | ||
85 | path('api/user/sound', my.UserSound.as_view()), | ||
86 | path('api/user/home', my.UserHome.as_view()), | ||
87 | path('api/user/tidings', my.UserTidings.as_view()), | ||
88 | path('api/user/follow', my.UserFollow.as_view()), | ||
89 | path('api/user/following', my.UserFollowing.as_view()), | ||
90 | path('api/user/find_singer', my.FindSinger.as_view()), | ||
91 | path('api/user/visitors', my.Visitors.as_view()), | ||
92 | path('api/user/remove_device', my.RemoveDevice.as_view()), | ||
93 | path('api/user/avtivitys/price', my.AvtivitysPrice.as_view()), | ||
94 | path('api/avtivitys/price_info', my.AvtivitysPriceInfo.as_view()), | ||
95 | |||
96 | |||
97 | #管理员查看试唱确认合作 | ||
98 | path('api/admin/activity/confirm',my.ConfirmSinger), | ||
99 | #注销账号 | ||
100 | path('api/user/delete', my.UserDelete), | ||
101 | |||
102 | #试唱模块 | ||
103 | path('api/audition/materials', audition.AuditionMaterials), #小程序端物料,要升降调文件 | ||
104 | path('api/activity/materials', audition.ActivityMaterials), #app 端物料,无须升降调文件 | ||
105 | path('api/audition/send_materials', audition.SendMaterials), #自主上传方式发送物料 | ||
106 | path('api/audition/split_audio', audition.SplitAudio), | ||
107 | path('api/audition/auto_submit', audition.AotoSubmit), | ||
108 | path('api/audition/online_save', audition.OnlineSave), | ||
109 | path('api/audition/join', audition.JoinActivity), # APP线上保存或提交 | ||
110 | path('api/audition/upload', audition.UploadAudio), | ||
111 | path('api/audition/mixin_preview', audition.MixinPreview), | ||
112 | path('api/audition/part_preview', audition.PartPreview), | ||
113 | path('api/audition/mixin_check', audition.MixinCheck), | ||
114 | path('api/audition/collection', audition.Collection.as_view()), | ||
115 | path('api/audition/remove_collection', audition.cancelcollection), | ||
116 | #活动确定分享人 | ||
117 | path('api/audition/share_users_list', audition.ShareUsersList.as_view()), | ||
118 | path('api/audition/share_users', audition.ShareUsers.as_view()), | ||
119 | |||
120 | #社区模块 | ||
121 | path('api/community/tidings', community.Tidings.as_view()), | ||
122 | path('api/community/tidings/selete_activity', community.SeleteActivity.as_view()), | ||
123 | path('api/community/tidings_list', community.TidingsList.as_view()), | ||
124 | path('api/community/tidings/show', community.TidingsShow.as_view()), | ||
125 | path('api/community/tidings/limiting', community.TidingsLimiting.as_view()), | ||
126 | path('api/community/tidings/report', community.TidingsReport.as_view()), | ||
127 | path('api/community/tidings/record_user', community.RecordUser.as_view()), | ||
128 | path('api/community/tidings/interacts',community.TidingsInteracts.as_view()), | ||
129 | path('api/community/tidings/chat', community.TidingsChat.as_view()), | ||
130 | path('api/community/chat/relation', community.ChatRelation.as_view()), | ||
131 | path('api/community/chat/agent', community.ChatAgent.as_view()), | ||
132 | path('api/community/chat/agent_record', community.ChatAgentRecord.as_view()), | ||
133 | path('api/community/unlike', community.Unlike.as_view()), | ||
134 | path('api/community/tidings/comments', community.TidingsComments.as_view()), #动态评论 | ||
135 | |||
136 | #消息通知模块 | ||
137 | path('api/notifica/read_message', notifications.read), | ||
138 | path('api/notifica/system_message', notifications.SystemMessage.as_view()), | ||
139 | |||
140 | #极光推送 | ||
141 | path('api/notifica/push', notifications.push_notifications), | ||
142 | |||
143 | #积分接口 | ||
144 | path('api/user/point', my.UserPoint.as_view()), | ||
145 | |||
146 | # 用户协议 | ||
147 | path('h5/user_agreement', index.useragreement), | ||
148 | #分享活动页面 | ||
149 | path('h5/share/<id>/', index.songshare), | ||
150 | |||
151 | # 分享动态页面 | ||
152 | # path('h5/sharetidings/<id>/', index.tidingsshare), | ||
153 | # app分享页面 | ||
154 | path('h5/shareapp/', index.appshare), | ||
155 | #版本更新 | ||
156 | path('api/app/version', appversion.versioninfo), | ||
157 | |||
158 | #获取app分享内容 | ||
159 | path('api/share/dictionary_list', my.sharechildlist), | ||
160 | path('api/share/dictionary', my.sharechild), | ||
161 | |||
162 | |||
163 | #客服列表 | ||
164 | path('api/customer_service', my.CustomerService.as_view()), | ||
165 | ] | ||
166 |
HisinApi/wsgi.py
0 → 100644
1 | """ | ||
2 | WSGI config for HisinApi project. | ||
3 | |||
4 | It exposes the WSGI callable as a module-level variable named ``application``. | ||
5 | |||
6 | For more information on this file, see | ||
7 | https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ | ||
8 | """ | ||
9 | |||
10 | import os | ||
11 | |||
12 | from django.core.wsgi import get_wsgi_application | ||
13 | |||
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'HisinApi.settings') | ||
15 | |||
16 | application = get_wsgi_application() |
README.md
0 → 100644
1 | #### Python版本 | ||
2 | - Python 3.7.0 | ||
3 | |||
4 | #### 依赖安装 | ||
5 | - pip install -r requirements.txt | ||
6 | |||
7 | #### 本地项目启动命令 | ||
8 | - python manage.py runserver | ||
9 | |||
10 | |||
11 | #### 线上项目进程管理,启动/更新 | ||
12 | - 服务已经配置supervisor进程管理 | ||
13 | - git pull拉取代码后会更新服务 | ||
14 | |||
15 | #### 主要目录结构说明 | ||
16 | > HisinApi 文件主目录 | ||
17 | >> api 接口编写主目录 | ||
18 | > > > ApiList 接口模块列表 | ||
19 | > > > | ||
20 | > > > jobs 定时任务脚本 | ||
21 | > > > | ||
22 | > > > templates 页面文件 | ||
23 | > > > | ||
24 | > > > admin.py | ||
25 | > > > | ||
26 | > > > apps.py | ||
27 | > > > | ||
28 | > > > loggin.py 日志模块 | ||
29 | > > > | ||
30 | > > > models.py 数据表模型文件 | ||
31 | > > > | ||
32 | > > > serializers.py 接口返回数据序列化,定义返回字段和结构 | ||
33 | > > > | ||
34 | > > > tests.py | ||
35 | > > > | ||
36 | > > > verification.py 接口接受参数校验文件 | ||
37 | > > > | ||
38 | > > > views.py 接口通用方法都写在这里 | ||
39 | >> | ||
40 | >> HisinApi 项目环境配置 | ||
41 | > > > settings.py 环境配置文件 | ||
42 | > > > | ||
43 | > > > urls.py 接口路由定义文件 | ||
44 | > > | ||
45 | > > manage.py 项目启动文件 | ||
46 | > > | ||
47 | > > requirements.txt 项目依赖文件 | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/.DS_Store
0 → 100644
No preview for this file type
api/ApiList/appversion.py
0 → 100644
1 | from api import models | ||
2 | from api.views import ResponseFactory | ||
3 | from django.http import JsonResponse | ||
4 | from api import serializers | ||
5 | |||
6 | def versioninfo(requests): | ||
7 | """ | ||
8 | 版本更新信息 | ||
9 | :param requests: | ||
10 | :return: | ||
11 | """ | ||
12 | if requests.method != 'GET': | ||
13 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
14 | os = requests.GET['os'] | ||
15 | app_version = requests.GET['app_version'] | ||
16 | # verobject = models.AppVersion.objects.filter(os=os,app_ver__gt=app_version,deleted_at=None).first() | ||
17 | # if verobject:data = serializers.AppVersionSerializer(models.AppVersion.objects.filter(os=os,deleted_at=None).last(),many=False,context={"app_version":app_version,"os":os}).data | ||
18 | # else:data = serializers.AppVersionSerializer(models.AppVersion.objects.filter(os=os,deleted_at=None).last(),many=False,context={"app_version":app_version,"os":os}).data | ||
19 | data = serializers.AppVersionSerializer(models.AppVersion.objects.filter(os=os, deleted_at=None).last(), many=False,context={"app_version": app_version, "os": os}).data | ||
20 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/ApiList/audition.py
0 → 100644
1 | import json | ||
2 | from django.core.mail import send_mail | ||
3 | from django.http import JsonResponse | ||
4 | from api.views import ResponseFactory,PageNumberPagination,createMessage,deleteMessage,pushSubscribeMessage,get_oss_file | ||
5 | from api import models,serializers | ||
6 | from HisinApi import settings | ||
7 | from django.utils import timezone | ||
8 | from api.views import upload_audio,auto_upload_audio, AuthPermissionRequired,get_user_info,ChangeAudio,WeChatApi,user_point_record,JPush,user_permission | ||
9 | import threading | ||
10 | from api import verification | ||
11 | from rest_framework.views import APIView | ||
12 | from django.utils.decorators import method_decorator | ||
13 | from django.db import transaction | ||
14 | from api import loggin | ||
15 | import librosa | ||
16 | import pyroomacoustics as pra | ||
17 | import pydub | ||
18 | import numpy as np | ||
19 | import time | ||
20 | import os | ||
21 | import random | ||
22 | import shutil | ||
23 | from math import log | ||
24 | from django.db.models import Q | ||
25 | from django_redis import get_redis_connection | ||
26 | from api.loggin import logger | ||
27 | import requests | ||
28 | |||
29 | |||
30 | sem = threading.Semaphore(4) | ||
31 | |||
32 | con = get_redis_connection("default") | ||
33 | |||
34 | |||
35 | |||
36 | # 板式混响 | ||
37 | def plate_mixin(person_voice_path,result_file_path,mixin_ratio): | ||
38 | fs = 44100 | ||
39 | room_dim = [18 * mixin_ratio, 15 * mixin_ratio] # 房间尺寸米 | ||
40 | mic1_dim = [9 * mixin_ratio - 0.4, 7.5 * mixin_ratio, ] # 麦克风1位置 | ||
41 | mic2_dim = [9 * mixin_ratio + 0.4, 7.5 * mixin_ratio] # 麦克风2位置 | ||
42 | per_dim = [9 * mixin_ratio, 7.5 * mixin_ratio - 0.2] # 人声位置 | ||
43 | scattering = 'rpg_qrd' # 散射模式,可选项 rpg_skyline ,rpg_qrd | ||
44 | max_order = 20 # 最大反射次数 | ||
45 | absorption = False # 是否开启空气吸收 | ||
46 | humidity = 0 # 空气湿度 | ||
47 | |||
48 | room = pra.ShoeBox(room_dim, fs=fs, | ||
49 | materials=pra.Material(energy_absorption="hard_surface", scattering=scattering) | ||
50 | , max_order=max_order, air_absorption=absorption, humidity=humidity) | ||
51 | audio, _ = librosa.load(person_voice_path, sr=fs) # 导入一个单通道语音作为源信号 source signal | ||
52 | room.add_source(per_dim, signal=audio, delay=0) | ||
53 | mic_locs = np.c_[ | ||
54 | mic1_dim, # mic 1 | ||
55 | mic2_dim, # mic 2 | ||
56 | ] | ||
57 | room.add_microphone_array(mic_locs) # 最后将麦克风阵列放在房间里 | ||
58 | room.compute_rir() | ||
59 | room.simulate(reference_mic=0) | ||
60 | room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, ) | ||
61 | |||
62 | # room混响 | ||
63 | def room_mixin(person_voice_path,result_file_path): | ||
64 | mixin_ratio = 1 | ||
65 | fs = 44100 | ||
66 | rt60_tgt = 0.5 | ||
67 | room_dim = [9*mixin_ratio, 7.5*mixin_ratio, 3.5*mixin_ratio] | ||
68 | |||
69 | e_absorption, max_order = pra.inverse_sabine(rt60_tgt, room_dim) | ||
70 | room = pra.ShoeBox(room_dim, fs=fs, materials=pra.Material(e_absorption), max_order=max_order) | ||
71 | audio, _ = librosa.load(person_voice_path, sr=fs) | ||
72 | room.add_source([6.3*mixin_ratio, 4.9*mixin_ratio, 1.2], signal=audio, delay=0.3) | ||
73 | mic_locs = np.c_[ | ||
74 | [6.3*mixin_ratio, 4.87*mixin_ratio, 1.2], # mic 1 | ||
75 | [6.3*mixin_ratio, 4.93*mixin_ratio, 1.2], # mic 2 | ||
76 | ] | ||
77 | room.add_microphone_array(mic_locs) | ||
78 | room.compute_rir() | ||
79 | room.simulate(reference_mic=0) | ||
80 | room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, ) | ||
81 | |||
82 | # room混响 | ||
83 | def hall_mixin(person_voice_path, result_file_path): | ||
84 | mixin_ratio = 2 | ||
85 | fs = 44100 | ||
86 | rt60_tgt = 3 | ||
87 | room_dim = [6 * mixin_ratio, 6 * mixin_ratio, 3.5] | ||
88 | |||
89 | e_absorption, max_order = pra.inverse_sabine(rt60_tgt, room_dim) | ||
90 | room = pra.ShoeBox(room_dim, fs=fs, materials=pra.Material(e_absorption), max_order=30) | ||
91 | audio, _ = librosa.load(person_voice_path, sr=fs) | ||
92 | room.add_source([3 * mixin_ratio, 3*mixin_ratio , 1.2], signal=audio, delay=0) | ||
93 | |||
94 | mic_locs = np.c_[ | ||
95 | [3 * mixin_ratio, 2.95 * mixin_ratio, 1.2], # mic 1 | ||
96 | [3 * mixin_ratio, 3.05 * mixin_ratio, 1.2], # mic 2 | ||
97 | ] | ||
98 | room.add_microphone_array(mic_locs) | ||
99 | room.compute_rir() | ||
100 | room.simulate(reference_mic=0) | ||
101 | room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, ) | ||
102 | |||
103 | |||
104 | def mixin(person_voice_path,person_volume,bg_audio_path,bg_volume, mixin_ratio,offset,mixin_pre_id,remove_path): | ||
105 | """预览合成""" | ||
106 | with sem: | ||
107 | try: | ||
108 | t = str(int(time.time())) + str(random.randint(0, 10000000000)) | ||
109 | os.mkdir("./api/static/{}".format(t)) | ||
110 | base_path = "./api/static/{}".format(t) | ||
111 | mixin_output_path = base_path + '/mixin_out-{}.wav'.format(str(random.randint(0, 10000000000))) | ||
112 | out_path = base_path + '/compose_out.mp3'.format(str(random.randint(0, 10000000000))) | ||
113 | if mixin_ratio: | ||
114 | if mixin_ratio == 1: | ||
115 | room_mixin(person_voice_path, mixin_output_path) | ||
116 | elif mixin_ratio == 2: | ||
117 | plate_mixin(person_voice_path,mixin_output_path,1) | ||
118 | elif mixin_ratio == 3: | ||
119 | hall_mixin(person_voice_path,mixin_output_path) | ||
120 | compose(mixin_output_path,person_volume,bg_audio_path,bg_volume,offset,out_path,mixin_ratio) | ||
121 | else: | ||
122 | compose(person_voice_path, person_volume, bg_audio_path, bg_volume, offset, out_path,mixin_ratio) | ||
123 | with open(out_path, 'rb') as of: | ||
124 | file_data = of.read() | ||
125 | of.close() | ||
126 | demo_url = upload_audio(file_data) | ||
127 | # 删除零时文件 | ||
128 | shutil.rmtree(remove_path) | ||
129 | shutil.rmtree(base_path) | ||
130 | #修改合成状态和demo | ||
131 | models.MixinPreviews.objects.filter(id=mixin_pre_id).update(url=demo_url, syn_status=1,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
132 | except: | ||
133 | models.MixinPreviews.objects.filter(id=mixin_pre_id).update(url='',syn_status=3,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
134 | |||
135 | def mixin_save(person_voice_path,person_volume,bg_audio_path,bg_volume, mixin_ratio,offset,ahu_id,remove_path): | ||
136 | """保存合成""" | ||
137 | with sem: | ||
138 | try: | ||
139 | # 状态修改为合成中 | ||
140 | models.ActivityHasUsers.objects.filter(id=ahu_id).update(syn_status=2, updated_at=timezone.now().strftime( | ||
141 | "%Y-%m-%d %H:%M:%S")) | ||
142 | t = str(int(time.time())) + str(random.randint(0, 10000000000)) | ||
143 | os.mkdir("./api/static/{}".format(t)) | ||
144 | base_path = "./api/static/{}".format(t) | ||
145 | mixin_output_path = base_path + '/mixin_out-{}.wav'.format(str(random.randint(0, 10000000000))) | ||
146 | out_path = base_path + '/compose_out.wav'.format(str(random.randint(0, 10000000000))) | ||
147 | if mixin_ratio: | ||
148 | if mixin_ratio == 1: | ||
149 | plate_mixin(person_voice_path,mixin_output_path,1) | ||
150 | elif mixin_ratio == 2: | ||
151 | room_mixin(person_voice_path,mixin_output_path) | ||
152 | elif mixin_ratio == 3: | ||
153 | hall_mixin(person_voice_path,mixin_output_path) | ||
154 | compose(mixin_output_path,person_volume,bg_audio_path,bg_volume,offset,out_path,mixin_ratio) | ||
155 | else: | ||
156 | compose(person_voice_path, person_volume, bg_audio_path, bg_volume, offset, out_path,mixin_ratio) | ||
157 | with open(out_path, 'rb') as of: | ||
158 | file_data = of.read() | ||
159 | of.close() | ||
160 | #获取时长 | ||
161 | demo_music = pydub.AudioSegment.from_mp3(out_path) | ||
162 | duration = demo_music.duration_seconds | ||
163 | demo_url = upload_audio(file_data) | ||
164 | # 删除零时文件 | ||
165 | shutil.rmtree(base_path) | ||
166 | shutil.rmtree(remove_path) | ||
167 | #保存至参与活动表中 | ||
168 | models.ActivityHasUsers.objects.filter(id=ahu_id).update(demo_url=demo_url,durations=duration,syn_status=1,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
169 | except Exception as e: | ||
170 | models.ActivityHasUsers.objects.filter(id=ahu_id).update(demo_url='',syn_status=3,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
171 | |||
172 | |||
173 | def person_voice_mixin(person_voice_path,result_file_path,mixin_ratio): | ||
174 | fs = 44100 | ||
175 | room_dim = [18 * mixin_ratio, 15 * mixin_ratio] # 房间尺寸米 | ||
176 | mic1_dim = [9 * mixin_ratio - 0.4, 7.5 * mixin_ratio, ] # 麦克风1位置 | ||
177 | mic2_dim = [9 * mixin_ratio + 0.4, 7.5 * mixin_ratio] # 麦克风2位置 | ||
178 | per_dim = [9 * mixin_ratio, 7.5 * mixin_ratio - 0.2] # 人声位置 | ||
179 | scattering = 'rpg_qrd' # 散射模式,可选项 rpg_skyline ,rpg_qrd | ||
180 | max_order = 10 # 最大反射次数 | ||
181 | absorption = False # 是否开启空气吸收 | ||
182 | humidity = 0 # 空气湿度 | ||
183 | |||
184 | room = pra.ShoeBox(room_dim, fs=fs, | ||
185 | materials=pra.Material(energy_absorption="hard_surface", scattering=scattering) | ||
186 | , max_order=max_order, air_absorption=absorption, humidity=humidity) | ||
187 | audio, _ = librosa.load(person_voice_path, sr=fs) # 导入一个单通道语音作为源信号 source signal | ||
188 | room.add_source(per_dim, signal=audio, delay=0) | ||
189 | mic_locs = np.c_[ | ||
190 | mic1_dim, # mic 1 | ||
191 | mic2_dim, # mic 2 | ||
192 | ] | ||
193 | room.add_microphone_array(mic_locs) # 最后将麦克风阵列放在房间里 | ||
194 | room.compute_rir() | ||
195 | room.simulate(reference_mic=0) | ||
196 | room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, ) | ||
197 | |||
198 | # 将伴奏和人声合成 | ||
199 | def compose(person_voice_path,person_volume,bg_audio_path,bg_volume,offset,out_path,mixin_ratio): | ||
200 | |||
201 | if mixin_ratio : | ||
202 | per_sound = pydub.AudioSegment.from_wav(person_voice_path) | ||
203 | else: | ||
204 | per_sound = pydub.AudioSegment.from_mp3(person_voice_path) | ||
205 | |||
206 | audio_sound = pydub.AudioSegment.from_mp3(bg_audio_path) | ||
207 | |||
208 | audio_sound_length = audio_sound.duration_seconds * 1000 | ||
209 | |||
210 | per_sound_length = per_sound.duration_seconds * 1000 | ||
211 | |||
212 | |||
213 | if per_sound_length < audio_sound_length: | ||
214 | audio_sound = audio_sound[:int(per_sound_length)] | ||
215 | elif per_sound_length > audio_sound_length: | ||
216 | per_sound = per_sound[:int(audio_sound_length)] | ||
217 | |||
218 | |||
219 | per_dBFS = per_sound.dBFS | ||
220 | bg_dBFs = audio_sound.dBFS | ||
221 | per_radio = 10 ** (per_dBFS / 20) | ||
222 | bg_radio = 10 ** (bg_dBFs / 20) | ||
223 | |||
224 | |||
225 | to_per_radio = per_radio * person_volume | ||
226 | to_bg_radio = bg_radio * bg_volume | ||
227 | |||
228 | if to_per_radio == 0: | ||
229 | to_per_radio = 0.0001 | ||
230 | |||
231 | if to_bg_radio == 0: | ||
232 | to_bg_radio = 0.0001 | ||
233 | |||
234 | to_per_dbfs = 20 * log(to_per_radio, 10) | ||
235 | to_bg_dbfs = 20 * log(to_bg_radio, 10) | ||
236 | |||
237 | per_change_dBFS = to_per_dbfs - per_dBFS | ||
238 | bg_chang_dBFs = to_bg_dbfs - bg_dBFs | ||
239 | |||
240 | per_sound = per_sound.apply_gain(per_change_dBFS) | ||
241 | audio_sound = audio_sound.apply_gain(bg_chang_dBFs) | ||
242 | |||
243 | |||
244 | if offset>=0: | ||
245 | played_togther = per_sound.overlay(audio_sound,position=offset) | ||
246 | played_togther.export(out_path, format="mp3") | ||
247 | else: | ||
248 | played_togther = audio_sound.overlay(per_sound,position=-offset) | ||
249 | played_togther.export(out_path, format="mp3") | ||
250 | |||
251 | |||
252 | @AuthPermissionRequired() | ||
253 | def MixinPreview(request): | ||
254 | """ | ||
255 | 混响预览 | ||
256 | """ | ||
257 | if request.method == 'POST': | ||
258 | postdata = json.loads(request.body) | ||
259 | obj = verification.mixin_previews(postdata) | ||
260 | if obj.is_valid(): | ||
261 | data = obj.clean() | ||
262 | user = get_user_info(request) | ||
263 | t = str(int(time.time())) + str(random.randint(0, 10000000000)) | ||
264 | os.mkdir("./api/static/{}".format(t)) | ||
265 | base_path = "./api/static/{}".format(t) | ||
266 | person_voice_path = base_path + "/voice-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
267 | try: | ||
268 | # person_voice_file = requests.get(data.get('person_url'),verify=False).content | ||
269 | person_voice_file = get_oss_file(data.get('person_url')) | ||
270 | # bg_audio_file = requests.get(data.get('bg_url'),verify=False).content | ||
271 | bg_audio_file = get_oss_file(data.get('bg_url')) | ||
272 | |||
273 | except Exception as e: | ||
274 | return JsonResponse(ResponseFactory(code=201, message="上传物料链接获取不到资源,检查链接", data=None, status='fail')) | ||
275 | # #保存上传文件 | ||
276 | with open(person_voice_path, "wb") as f: | ||
277 | f.write(person_voice_file) | ||
278 | f.close() | ||
279 | bg_audio_path = base_path + "/bg-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
280 | # #保存上传文件 | ||
281 | with open(bg_audio_path, "wb") as ff: | ||
282 | ff.write(bg_audio_file) | ||
283 | ff.close() | ||
284 | person_volume = data.get('person_volume') | ||
285 | bg_volume = data.get('bg_volume') | ||
286 | mixin_ratio = data.get('mix_type') | ||
287 | offset = data.get('offset') | ||
288 | # 查看时候需要切片段 | ||
289 | begin_time = postdata.get('begin_time', '') | ||
290 | if begin_time != '': | ||
291 | # 获取人声音频时长 | ||
292 | person_input_music = pydub.AudioSegment.from_file(person_voice_path) | ||
293 | duration = person_input_music.duration_seconds | ||
294 | # #伴奏音频切片 | ||
295 | bg_input_music = pydub.AudioSegment.from_file(bg_audio_path) | ||
296 | # 截取音频 1000毫秒 = 1秒 | ||
297 | bg_output_music = bg_input_music[begin_time * 1000:begin_time * 1000 + duration * 1000] | ||
298 | # 保存音频,指定音频比特率为64k | ||
299 | bg_output_music.export(bg_audio_path, bitrate="64k") | ||
300 | |||
301 | mixin_pre = models.MixinPreviews.objects.create( | ||
302 | activity_id=data['activity_id'], | ||
303 | user_id=user['id'], | ||
304 | url='', | ||
305 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
306 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
307 | ) | ||
308 | t = threading.Thread(target=mixin,args=[person_voice_path,person_volume,bg_audio_path,bg_volume, mixin_ratio,offset,mixin_pre.id,base_path]) | ||
309 | t.setDaemon(True) | ||
310 | t.start() | ||
311 | data = {'id':mixin_pre.id,'activity_id':mixin_pre.activity_id,'url':mixin_pre.url} | ||
312 | return JsonResponse(ResponseFactory(code=200, message="音频合成中", data=data, status='success')) | ||
313 | |||
314 | else: | ||
315 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
316 | else: | ||
317 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
318 | |||
319 | |||
320 | @AuthPermissionRequired() | ||
321 | def PartPreview(request): | ||
322 | """ | ||
323 | 片段混响 | ||
324 | """ | ||
325 | if request.method == 'POST': | ||
326 | obj = verification.part_mixin_previews(json.loads(request.body)) | ||
327 | if obj.is_valid(): | ||
328 | data = obj.clean() | ||
329 | user = get_user_info(request) | ||
330 | t = str(int(time.time())) + str(random.randint(0, 10000000000)) | ||
331 | os.mkdir("./api/static/{}".format(t)) | ||
332 | base_path = "./api/static/{}".format(t) | ||
333 | person_voice_path = base_path + "/voice-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
334 | try: | ||
335 | # person_voice_file = requests.get(data.get('person_url')).content | ||
336 | person_voice_file = get_oss_file(data.get('person_url')) | ||
337 | # bg_audio_file = requests.get(data.get('bg_url')).content | ||
338 | bg_audio_file = get_oss_file(data.get('bg_url')) | ||
339 | except Exception as e: | ||
340 | return JsonResponse(ResponseFactory(code=201, message="上传物料链接获取不到资源,检查链接", data=None, status='fail')) | ||
341 | # #保存人声文件 | ||
342 | with open(person_voice_path, "wb") as f: | ||
343 | f.write(person_voice_file) | ||
344 | f.close() | ||
345 | bg_audio_path = base_path + "/bg-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
346 | # #保存伴奏文件 | ||
347 | with open(bg_audio_path, "wb") as ff: | ||
348 | ff.write(bg_audio_file) | ||
349 | ff.close() | ||
350 | |||
351 | #提取伴奏片段 | ||
352 | part_bg_path = base_path + "/part-bg-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
353 | input_music = pydub.AudioSegment.from_mp3(bg_audio_path) | ||
354 | # 截取音频 1000毫秒 = 1秒 | ||
355 | output_music = input_music[data.get('start_time')*1000:data.get('end_time')*1000] | ||
356 | # 保存音频,指定音频比特率为64k | ||
357 | output_music.export(part_bg_path, bitrate="64k") | ||
358 | |||
359 | person_volume = data.get('person_volume') | ||
360 | bg_volume = data.get('bg_volume') | ||
361 | mixin_ratio = data.get('mix_type') | ||
362 | offset = data.get('offset') | ||
363 | mixin_pre = models.MixinPreviews.objects.create( | ||
364 | activity_id=data['activity_id'], | ||
365 | user_id=user['id'], | ||
366 | url='', | ||
367 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
368 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
369 | ) | ||
370 | t = threading.Thread(target=mixin,args=[person_voice_path,person_volume,part_bg_path,bg_volume, mixin_ratio,offset,mixin_pre.id,base_path]) | ||
371 | t.setDaemon(True) | ||
372 | t.start() | ||
373 | data = {'id':mixin_pre.id,'activity_id':mixin_pre.activity_id,'url':mixin_pre.url} | ||
374 | return JsonResponse(ResponseFactory(code=200, message="音频合成中", data=data, status='success')) | ||
375 | |||
376 | else: | ||
377 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
378 | else: | ||
379 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
380 | |||
381 | @AuthPermissionRequired() | ||
382 | def MixinCheck(request): | ||
383 | if request.method == 'GET': | ||
384 | try: | ||
385 | id = int(request.GET['id']) | ||
386 | except Exception as e: | ||
387 | return JsonResponse(ResponseFactory(code=201, message="id参数错误", data=None, status='fail')) | ||
388 | mixin_pre = serializers.MixinPreviewsSerializer(models.MixinPreviews.objects.get(id=id,deleted_at=None),many=False) | ||
389 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=mixin_pre.data, status='success')) | ||
390 | else: | ||
391 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
392 | |||
393 | @AuthPermissionRequired() | ||
394 | def OnlineSave(request): | ||
395 | """ | ||
396 | 在线上传 | ||
397 | """ | ||
398 | if request.method == 'POST': | ||
399 | user = get_user_info(request) | ||
400 | try: | ||
401 | data = json.loads(request.body) | ||
402 | # 获取上次提交版本信息 | ||
403 | obj = models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=data['activity_id'],deleted_at=None).last() | ||
404 | if obj: | ||
405 | version = obj.version | ||
406 | if version: | ||
407 | version += 1 | ||
408 | else: | ||
409 | version = 1 | ||
410 | else: | ||
411 | version = 1 | ||
412 | #预览完成保存 | ||
413 | if data['demo_url'] != '': | ||
414 | #获取音频时长 | ||
415 | try: | ||
416 | # demo_data = requests.get(data['demo_url'],verify=False).content | ||
417 | demo_data = get_oss_file(data['demo_url']) | ||
418 | except Exception as e: | ||
419 | return JsonResponse(ResponseFactory(code=201, message="音频地址获取不到资源,检查链接", data=None, status='fail')) | ||
420 | # #保存demo文件获取时长 | ||
421 | demo_path = "./api/static/demo-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
422 | with open(demo_path, "wb") as f: | ||
423 | f.write(demo_data) | ||
424 | f.close() | ||
425 | demo_music = pydub.AudioSegment.from_mp3(demo_path) | ||
426 | duration = demo_music.duration_seconds | ||
427 | # 删除零时文件 | ||
428 | os.remove(demo_path) | ||
429 | ahu = models.ActivityHasUsers.objects.create( | ||
430 | activity_id=data['activity_id'], | ||
431 | user_id=user['id'], | ||
432 | demo_url=data['demo_url'], | ||
433 | durations = duration, | ||
434 | status=0, | ||
435 | syn_status=1, | ||
436 | syn_data=data, | ||
437 | type="Save", | ||
438 | version = version, | ||
439 | mode = 0, | ||
440 | sing_type=data.get('sing_type',None), | ||
441 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
442 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
443 | ) | ||
444 | data = {'id':ahu.id,'activity_id':ahu.activity_id,'demo_url':ahu.demo_url} | ||
445 | return JsonResponse(ResponseFactory(code=200, message="保存成功", data=data, status='success')) | ||
446 | #未预览保存 | ||
447 | else: | ||
448 | t = str(int(time.time())) + str(random.randint(0, 10000000000)) | ||
449 | os.mkdir( os.getcwd() + "/api/static/{}".format(t)) | ||
450 | base_path = os.getcwd() + "/api/static/{}".format(t) | ||
451 | person_voice_path = base_path + "/voice-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
452 | try: | ||
453 | # person_voice_file = requests.get(data.get('person_url'),verify=False).content | ||
454 | person_voice_file = get_oss_file(data.get('person_url')) | ||
455 | # bg_audio_file = requests.get(data.get('bg_url'),verify=False).content | ||
456 | bg_audio_file = get_oss_file(data.get('bg_url')) | ||
457 | except Exception as e: | ||
458 | return JsonResponse(ResponseFactory(code=201, message="上传物料链接获取不到资源,检查链接", data=None, status='fail')) | ||
459 | # #保存上传文件 | ||
460 | with open(person_voice_path, "wb") as f: | ||
461 | f.write(person_voice_file) | ||
462 | f.close() | ||
463 | bg_audio_path = base_path + "/bg-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
464 | # #保存上传文件 | ||
465 | with open(bg_audio_path, "wb") as ff: | ||
466 | ff.write(bg_audio_file) | ||
467 | ff.close() | ||
468 | person_volume = data.get('person_volume') | ||
469 | bg_volume = data.get('bg_volume') | ||
470 | mixin_ratio = data.get('mix_type') | ||
471 | offset = data.get('offset') | ||
472 | #查看时候需要切片段 | ||
473 | begin_time = data.get('begin_time','') | ||
474 | if begin_time != '' : | ||
475 | # 获取人声音频时长 | ||
476 | person_input_music = pydub.AudioSegment.from_mp3(person_voice_path) | ||
477 | duration = person_input_music.duration_seconds | ||
478 | # #伴奏音频切片 | ||
479 | bg_input_music = pydub.AudioSegment.from_file(bg_audio_path) | ||
480 | # 截取音频 1000毫秒 = 1秒 | ||
481 | bg_output_music = bg_input_music[begin_time*1000:begin_time*1000+duration*1000] | ||
482 | # 保存音频,指定音频比特率为64k | ||
483 | bg_output_music.export(bg_audio_path, bitrate="64k") | ||
484 | |||
485 | ahu = models.ActivityHasUsers.objects.create( | ||
486 | activity_id=data['activity_id'], | ||
487 | user_id=user['id'], | ||
488 | demo_url='', | ||
489 | syn_status = 0, | ||
490 | syn_data = data , | ||
491 | status=0, | ||
492 | type="Save", | ||
493 | mode=0, | ||
494 | version = version, | ||
495 | sing_type=data.get('sing_type', None), | ||
496 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
497 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
498 | ) | ||
499 | t = threading.Thread(target=mixin_save, | ||
500 | args=[person_voice_path, person_volume, bg_audio_path, bg_volume, mixin_ratio, offset, | ||
501 | ahu.id, base_path]) | ||
502 | t.setDaemon(True) | ||
503 | t.start() | ||
504 | data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url} | ||
505 | return JsonResponse(ResponseFactory(code=200, message="音频合成中,合成后会自动保存", data=data, status='success')) | ||
506 | except Exception as e: | ||
507 | logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(user['id'], request.body,e)) | ||
508 | else: | ||
509 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
510 | |||
511 | |||
512 | @AuthPermissionRequired() | ||
513 | def JoinActivity(request): | ||
514 | if request.method != 'POST': | ||
515 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
516 | user = get_user_info(request) | ||
517 | # 检查是否有提交权限 | ||
518 | permission = user_permission(user['id']) | ||
519 | if 2 not in permission: | ||
520 | return JsonResponse(ResponseFactory(code=400, message='用户无此权限', data=None, status='fail')) | ||
521 | post_data = json.loads(request.body) | ||
522 | dataobj = verification.join_activity(post_data) | ||
523 | if not dataobj.is_valid(): | ||
524 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(dataobj), data=None, status='fail')) | ||
525 | dataobj = dataobj.clean() | ||
526 | activity_id = dataobj.get('activity_id') | ||
527 | url = dataobj.get('url') | ||
528 | type = dataobj.get('join_type') | ||
529 | sing_type = dataobj.get('sing_type') | ||
530 | is_hide = post_data.get('is_hide',1) | ||
531 | # 判断活动状态 | ||
532 | activity_status = models.Activitys.objects.filter(id=activity_id).first().status | ||
533 | if activity_status != 1: | ||
534 | return JsonResponse(ResponseFactory(code=201, message="活动已结束", data=None, status='fail')) | ||
535 | self_price = post_data.get('self_price',None) | ||
536 | #校验自主报价参数 | ||
537 | if self_price: | ||
538 | ver = verification.SubmitPriceVerification(data=self_price) | ||
539 | if not ver.is_valid(): | ||
540 | return JsonResponse( | ||
541 | ResponseFactory(code=400, message=verification.error_message(ver), data=None, status='fail')) | ||
542 | if self_price['value']['amounts']: | ||
543 | if not (0 <= self_price['value']['amounts'] <= 9999999): return JsonResponse( | ||
544 | ResponseFactory(code=201, message="金额在0-9999999之间", data=None, status='fail')) | ||
545 | if self_price['value']['ratio']: | ||
546 | if not (0 <= self_price['value']['ratio'] <= 100): return JsonResponse( | ||
547 | ResponseFactory(code=201, message="分成比列在0%-100%之间", data=None, status='fail')) | ||
548 | try: | ||
549 | # 获取上次提交版本信息 | ||
550 | ahu_obj = models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=activity_id,deleted_at=None).last() | ||
551 | if ahu_obj: | ||
552 | version = ahu_obj.version | ||
553 | if version:version += 1 | ||
554 | else:version = 1 | ||
555 | else: | ||
556 | version = 1 | ||
557 | try: | ||
558 | demo_data = get_oss_file(url) | ||
559 | except Exception as e: | ||
560 | return JsonResponse(ResponseFactory(code=201, message="音频地址获取不到资源,检查链接", data=None, status='fail')) | ||
561 | # #保存demo文件获取时长 | ||
562 | file_type = url.split('.')[-1] | ||
563 | demo_path = "./api/static/demo-{}.{}".format(str(random.randint(0, 10000000000)), file_type) | ||
564 | with open(demo_path, "wb") as f: | ||
565 | f.write(demo_data) | ||
566 | f.close() | ||
567 | demo_music = pydub.AudioSegment.from_file(demo_path) | ||
568 | duration = demo_music.duration_seconds | ||
569 | # 删除零时文件 | ||
570 | os.remove(demo_path) | ||
571 | if type == 'Submit': | ||
572 | try: | ||
573 | with transaction.atomic(): | ||
574 | models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=activity_id).update(type="Save", updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
575 | ahu = models.ActivityHasUsers.objects.create( | ||
576 | activity_id=activity_id, | ||
577 | user_id=user['id'], | ||
578 | demo_url=url, | ||
579 | durations=duration, | ||
580 | status=0, | ||
581 | type=type, | ||
582 | open_id='', | ||
583 | syn_status=1, | ||
584 | mode=0, | ||
585 | is_hide = is_hide, | ||
586 | version=version, | ||
587 | sing_type=sing_type, | ||
588 | submit_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
589 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
590 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
591 | ) | ||
592 | #存入自主报价 | ||
593 | if self_price: | ||
594 | models.ActivityUserHasPrices.objects.update_or_create( | ||
595 | user_id=user['id'], activity_id=activity_id, | ||
596 | defaults={ | ||
597 | "value": self_price['value'], | ||
598 | "is_deduct": self_price['is_deduct'], | ||
599 | "is_talk": self_price['is_talk'], | ||
600 | "address_id": self_price['address_id'], | ||
601 | "is_accept_address": self_price['is_accept_address'], | ||
602 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
603 | "updated_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), }, | ||
604 | ) | ||
605 | # 更新到动态 | ||
606 | is_tidings = post_data.get("is_tidings", 0) | ||
607 | if is_tidings == 1: | ||
608 | models.UserHasTidings.objects.create(user_id=user['id'], activity_id=activity_id,type=2, url=url,created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
609 | |||
610 | # 提交作品计数 1.先检查用户对该作品之前是否有提交且未读的消息 | ||
611 | user_msg = models.UserMessages.objects.filter(is_read=0, sender_id=user['id'],activity_id=activity_id, deleted_at=None, type=3) | ||
612 | if user_msg: | ||
613 | user_msg.update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
614 | # 获取全体管理员和推荐人open_id | ||
615 | project_id = models.Activitys.objects.filter(id=activity_id).first().project_id | ||
616 | project = models.Projects.objects.filter(id=project_id).first() | ||
617 | project_user_ids = [] | ||
618 | if project: | ||
619 | if project.is_public:project_user_ids = list(models.UserHasProjects.objects.filter(project_id=project_id).values_list('user_id',flat=True)) | ||
620 | else:project_user_ids = [models.Activitys.objects.filter(id=activity_id).first().user_id] | ||
621 | project_user_unionid = list( | ||
622 | models.Users.objects.filter(id__in=project_user_ids, deleted_at=None, status=1).values_list( | ||
623 | 'unionid', flat=True)) | ||
624 | admin_unionid = list(models.Users.objects.filter(scope=1,deleted_at=None,status=1).values_list('unionid', flat=True)) | ||
625 | push_open_ids = list( | ||
626 | models.WechatOfficialUsers.objects.filter(union_id__in=admin_unionid + project_user_unionid,is_subscribe=1).values_list('open_id', flat=True)) | ||
627 | song_name = models.Activitys.objects.filter(id=activity_id).first().song_name | ||
628 | # 再创建消息 | ||
629 | business_id = user['business_id'] | ||
630 | if business_id: | ||
631 | # 获取推荐人公众号open_id | ||
632 | unionid = models.Users.objects.filter(id=business_id).values_list('unionid', flat=True) | ||
633 | wechat_official = models.WechatOfficialUsers.objects.filter(union_id__in=unionid,is_subscribe=1).last() | ||
634 | if wechat_official: | ||
635 | # 公众号推送 | ||
636 | p_data = {'channel': 'singer_related', 'open_id': [wechat_official.open_id], | ||
637 | 'data': {"title": "您的歌手参加了试唱歌曲", | ||
638 | "name": user['nick_name'] + "("+user['real_name']+")", | ||
639 | "intro": "参加了试唱歌曲《{}》".format(song_name), | ||
640 | "remark": "点击前往 >", | ||
641 | "page": "/packageMy/pages/like?tab=2"}} | ||
642 | pushSubscribeMessage(p_data) | ||
643 | # 发给绑定的推荐人 | ||
644 | m_data = {'sender_id': user['id'], 'receivers': [business_id], | ||
645 | 'activity_id': activity_id, 'type': 3, 'is_bind': 1} | ||
646 | createMessage(m_data) | ||
647 | |||
648 | # 极光推送-提交作品推荐人 | ||
649 | j_title = "您的歌手参加了试唱" | ||
650 | j_content = "您的歌手{}参加了试唱活动《{}》".format(user['nick_name'], song_name) | ||
651 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
652 | "receiver_value": [business_id], | ||
653 | "extras": {"type": "ToTaSing", "value": ""}} | ||
654 | JPush().jpush_v3(jdata) | ||
655 | |||
656 | # 给全体管理员和项目管理员推服务号消息 | ||
657 | p_data = {'channel': 'activity_join', 'open_id': push_open_ids, | ||
658 | 'data': { | ||
659 | "first": "{}({})提交了试唱作品".format(user['nick_name'], user['real_name']), | ||
660 | "keyword1": "《"+song_name+"》", | ||
661 | "keyword2": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
662 | "remark": "点击试听 >", "page": "/pages/index/index"} | ||
663 | } | ||
664 | pushSubscribeMessage(p_data) | ||
665 | |||
666 | # 外部管理员id | ||
667 | activity_manage_ids = list( | ||
668 | models.UserManageActivitie.objects.filter(activity_id=activity_id).values_list( | ||
669 | 'user_id', flat=True)) | ||
670 | # 发送系统消息(平台管理员+项目管理员+外部管理员) | ||
671 | receivers = list(models.Users.objects.filter(scope=1).values_list('id', flat=True)) | ||
672 | receivers = list(set(receivers + project_user_ids +activity_manage_ids)) | ||
673 | m_data = {'sender_id': user['id'], 'receivers': receivers, | ||
674 | 'activity_id': activity_id, | ||
675 | 'type': 3, 'is_bind': 0} | ||
676 | createMessage(m_data) | ||
677 | |||
678 | # 极光推送-提交作品全体管理员 | ||
679 | j_title = "有新用户提交试唱" | ||
680 | j_content = "{}参与了试唱《{}》".format(user['nick_name'], song_name) | ||
681 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
682 | "receiver_value": receivers, | ||
683 | "extras": {"type": "ToPlatfromSing", "value": ""}} | ||
684 | JPush().jpush_v3(jdata) | ||
685 | except Exception as e: | ||
686 | return JsonResponse(ResponseFactory(code=201, message="提交失败:{}".format(e), data=None, status='fail')) | ||
687 | if sing_type == 'Part': | ||
688 | # 歌手积分 | ||
689 | user_point_record(user_id=user['id'], type='SubmitPart', activity_id=activity_id) | ||
690 | # 推荐人积分 | ||
691 | if user['business_id']: | ||
692 | user_point_record(user_id=user['business_id'], type='SingerSubmitPart',activity_id=activity_id,singer_id=user['id']) | ||
693 | else: | ||
694 | # 歌手积分 | ||
695 | user_point_record(user_id=user['id'], type='SubmitFull', activity_id=activity_id,) | ||
696 | # 推荐人积分 | ||
697 | if user['business_id']: | ||
698 | user_point_record(user_id=user['business_id'], type='SingerSubmitFull',activity_id=activity_id,singer_id=user['id']) | ||
699 | data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url} | ||
700 | return JsonResponse(ResponseFactory(code=200, message="提交成功", data=data, status='success')) | ||
701 | else: | ||
702 | ahu = models.ActivityHasUsers.objects.create( | ||
703 | activity_id=activity_id, | ||
704 | user_id=user['id'], | ||
705 | demo_url=url, | ||
706 | durations=duration, | ||
707 | status=0, | ||
708 | type=type, | ||
709 | open_id='', | ||
710 | mode=0, | ||
711 | syn_status = 1, | ||
712 | version=version, | ||
713 | sing_type=sing_type, | ||
714 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
715 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
716 | ) | ||
717 | data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url} | ||
718 | return JsonResponse(ResponseFactory(code=200, message="保存成功", data=data, status='success')) | ||
719 | except Exception as e: | ||
720 | logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(user['id'], request.body, e)) | ||
721 | return JsonResponse(ResponseFactory(code=201, message="服务器网络波动,请稍后重试", data=None, status='fail')) | ||
722 | |||
723 | |||
724 | @AuthPermissionRequired() | ||
725 | def AuditionMaterials(request): | ||
726 | if request.method == 'GET': | ||
727 | activity_id = request.GET['activity_id'] | ||
728 | user_id = get_user_info(request)['id'] | ||
729 | queryset = models.Activitys.objects.filter(id=activity_id).first() | ||
730 | activity_ser = serializers.ActivityDetailSerializer(queryset,many=False,context={"user_id":user_id,"project_many":False}, | ||
731 | fields=['id','song_name','lyric','clip_lyric','cover','status','project_id','sex','mark','speed','lang','guide_duration','guide_clip_duration','is_collection','is_confirm_share','project','tags','is_promote','estimate_release_at','publish_at','comfirm_time','total_song_count','online_song_count','public_audio_count','arranger']) | ||
732 | activity = activity_ser.data | ||
733 | #活动配置信息 | ||
734 | config_ids = list(models.SystemConfig.objects.filter(identifier__in=['activity_lang', 'activity_speed', 'activity_sex','activity_mark']).values_list('id',flat=True).all()) | ||
735 | configs = models.SystemConfig.objects.filter(parent_id__in=config_ids).values_list('identifier','name','content') | ||
736 | lang = activity['lang'] if activity['lang'] else [] | ||
737 | langs = [] | ||
738 | for config in configs: | ||
739 | if config[0] == activity['sex']: | ||
740 | activity['sex'] = config[1] if activity['sex'] else None | ||
741 | if config[0] == activity['mark']: | ||
742 | activity['mark'] = config[2] if activity['mark'] else None | ||
743 | if config[0] == activity['speed']: | ||
744 | activity['speed'] = config[1] if activity['speed'] else None | ||
745 | if config[0] in lang: | ||
746 | langs.append(config[1]) | ||
747 | activity['lang'] = langs | ||
748 | ser = serializers.ActivityMaterialsSerializer(models.ActivityMaterials.objects.filter(activity_id=activity_id,deleted_at=None),many=True) | ||
749 | data = {'activity':activity,'materials':ser.data} | ||
750 | # 积分 | ||
751 | user_point_record(user_id=user_id, type='Listen',activity_id=activity_id) | ||
752 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
753 | else: | ||
754 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
755 | |||
756 | |||
757 | @AuthPermissionRequired() | ||
758 | def ActivityMaterials(request): | ||
759 | if request.method == 'GET': | ||
760 | activity_id = request.GET['activity_id'] | ||
761 | user_id = get_user_info(request)['id'] | ||
762 | queryset = models.Activitys.objects.filter(id=activity_id).first() | ||
763 | activity_ser = serializers.ActivityDetailSerializer(queryset, many=False, context={"user_id": user_id,"project_many":False}, | ||
764 | fields=['id','song_name','lyric','sex','mark','speed','lang','guide','guide_duration','guide_clip','guide_clip_duration','karaoke','karaoke_clip','clip_lyric','cover','status','project_id','is_collection','is_confirm_share','project','tags','is_promote','estimate_release_at','publish_at','guide_duration','guide_clip_duration','comfirm_time','total_song_count','online_song_count','public_audio_count','arranger']) | ||
765 | activity = activity_ser.data | ||
766 | # 活动配置信息 | ||
767 | config_ids = list(models.SystemConfig.objects.filter( | ||
768 | identifier__in=['activity_lang', 'activity_speed', 'activity_sex', 'activity_mark']).values_list('id', | ||
769 | flat=True).all()) | ||
770 | configs = models.SystemConfig.objects.filter(parent_id__in=config_ids).values_list('identifier', 'name', | ||
771 | 'content') | ||
772 | lang = activity['lang'] if activity['lang'] else [] | ||
773 | langs = [] | ||
774 | for config in configs: | ||
775 | if config[0] == activity['sex']: | ||
776 | activity['sex'] = config[1] if activity['sex'] else None | ||
777 | if config[0] == activity['mark']: | ||
778 | activity['mark'] = config[2] if activity['mark'] else None | ||
779 | if config[0] == activity['speed']: | ||
780 | activity['speed'] = config[1] if activity['speed'] else None | ||
781 | if config[0] in lang: | ||
782 | langs.append(config[1]) | ||
783 | activity['lang'] = langs | ||
784 | data = {'activity':activity} | ||
785 | # 积分 | ||
786 | user_point_record(user_id=user_id, type='Listen',activity_id=activity_id) | ||
787 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
788 | else: | ||
789 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
790 | |||
791 | def SendEmail(request,user): | ||
792 | activity_id = request.GET['activity_id'] | ||
793 | activity = models.Activitys.objects.filter(id=activity_id).first() | ||
794 | subject = '【海星试唱】-' + activity.song_name + '-试唱物料资源' | ||
795 | message = '{},您好:\n' \ | ||
796 | '\n 【海星试唱】-{}-物料资源如下,包含导唱(含人声)、伴奏(不含人声)、歌词内容。请复制下方链接内容在浏览器打开进行下载。\n' \ | ||
797 | '\n导唱(含人声):{}' \ | ||
798 | '\n' \ | ||
799 | '\n伴奏(不含人声):{}' \ | ||
800 | '\n' \ | ||
801 | '\n《歌词》:\n' \ | ||
802 | '{}' \ | ||
803 | '\n' \ | ||
804 | '\n 1.本邮件含有保密信息,仅限于收件人所用。禁止任何人未经发件人许可以任何形式(包括但不限于部分地泄露、复制或散发)不当地使用本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件。' \ | ||
805 | '\n 2.本公司员工存在受贿、索贿、贪污、盗窃、挪用资金等行为,请将相关证据以邮件形式发送至公司反腐败举报邮箱:service@hikoon.com' \ | ||
806 | '\n' \ | ||
807 | '\n' \ | ||
808 | '对于您通过本邮件所获取的试唱资料(包括但不限于歌词、伴奏、音频等)及/或您录制的试唱音视频,您仅能用于个人试唱录制使用,并仅能上传至海星试唱平台,未经海星试唱平台书面同意,您不得泄露给任何第三方或发布在任何其他平台,试唱资料及您使用试唱资料制作的全部音乐作品/录音录像制品/视听作品的完整著作权和邻接权均归属于北京海葵科技有限公司(以下简称“海葵”)或其指定的第三方,您不得抄袭、模仿或提前泄露在短视频或音乐平台,也不可在未取得海葵书面许可的情况下翻唱、二次创作。如因您未按规定使用试唱资料及/或您录制的试唱音视频,海葵或其指定的第三方有权要求您赔偿因此造成的一切直接损失、间接损失(包括但不限于词曲成本、软件运营成本、海葵支付的差旅费、律师费、公证费、诉讼/仲裁费、保全费、鉴定费等)。' \ | ||
809 | .format(user['nick_name'], activity.song_name, activity.expand['guide_source']['url'],activity.expand['karaoke_source']['url'], | ||
810 | activity.lyric) | ||
811 | send_mail( | ||
812 | subject=subject, | ||
813 | message=message, | ||
814 | from_email=settings.EMAIL_HOST_USER, | ||
815 | recipient_list=[user['email'], settings.EMAIL_HOST_USER] # 接收者的邮箱账号 | ||
816 | ) | ||
817 | |||
818 | @AuthPermissionRequired() | ||
819 | def SendMaterials(request): | ||
820 | if request.method != 'GET': | ||
821 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
822 | user = get_user_info(request) | ||
823 | if not user['email']: | ||
824 | return JsonResponse(ResponseFactory(code=201, message="请先绑定邮箱", data=None, status='success')) | ||
825 | t = threading.Thread(target=SendEmail, | ||
826 | args=[request,user]) | ||
827 | t.setDaemon(True) | ||
828 | t.start() | ||
829 | return JsonResponse(ResponseFactory(code=200, message="发送中,请稍等片刻...", data=None, status='success')) | ||
830 | |||
831 | |||
832 | |||
833 | def SplitAudio(request): | ||
834 | """ | ||
835 | 音频文件拆分 | ||
836 | """ | ||
837 | post_data = json.loads(request.body) | ||
838 | obj = verification.SplitAudio(data=post_data) | ||
839 | loggin.logger.info('拆分参数:{}'.format(post_data)) | ||
840 | if not obj.is_valid(): | ||
841 | return JsonResponse({"code":"400", "message":verification.error_message(obj), "data":None, "status":"fail"}) | ||
842 | id = obj.data['activity_id'] | ||
843 | status = obj.data['status'] | ||
844 | data = str({"id":id,"status":status,"time":timezone.now().strftime("%Y-%m-%d %H:%M:%S")}) | ||
845 | con.lpush('split_audio_queue',data) | ||
846 | return JsonResponse({"code":"200", "message":"已添加到拆分队列中", "data":None, "status":":success"}) | ||
847 | |||
848 | @AuthPermissionRequired() | ||
849 | def AotoSubmit(request): | ||
850 | """ | ||
851 | 自主提交 | ||
852 | """ | ||
853 | if request.method == "POST": | ||
854 | user = get_user_info(request) | ||
855 | #检查是否有提交权限 | ||
856 | permission = user_permission(user['id']) | ||
857 | if 2 not in permission: | ||
858 | return JsonResponse(ResponseFactory(code=400, message='用户无此权限', data=None, status='fail')) | ||
859 | post_data = json.loads(request.body) | ||
860 | obj = verification.aoto_submit(post_data) | ||
861 | is_hide = post_data.get('is_hide', 1) | ||
862 | if obj.is_valid(): | ||
863 | data = obj.clean() | ||
864 | type = data['type'] | ||
865 | # 校验自主报价参数 | ||
866 | self_price = post_data.get('self_price', None) | ||
867 | if self_price: | ||
868 | ver = verification.SubmitPriceVerification(data=self_price) | ||
869 | if not ver.is_valid(): | ||
870 | return JsonResponse( | ||
871 | ResponseFactory(code=400, message=verification.error_message(ver), data=None, status='fail')) | ||
872 | if self_price['value']['amounts']: | ||
873 | if not (0 <= self_price['value']['amounts'] <= 9999999): return JsonResponse( | ||
874 | ResponseFactory(code=201, message="金额在0-9999999之间", data=None, status='fail')) | ||
875 | if self_price['value']['ratio']: | ||
876 | if not (0 <= self_price['value']['ratio'] <= 100): return JsonResponse( | ||
877 | ResponseFactory(code=201, message="分成比列在0%-100%之间", data=None, status='fail')) | ||
878 | |||
879 | #判断活动状态 | ||
880 | activity_status = models.Activitys.objects.filter(id = data['activity_id']).first().status | ||
881 | if activity_status != 1: | ||
882 | return JsonResponse(ResponseFactory(code=201, message="活动已结束", data=None, status='fail')) | ||
883 | #获取小程序openid | ||
884 | try: | ||
885 | vx_code = post_data.get("vx_code","") | ||
886 | open_id, unionid = WeChatApi(vx_code) | ||
887 | except: | ||
888 | open_id = '' | ||
889 | # 获取上次提交版本信息 | ||
890 | obj = models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=data['activity_id'],deleted_at=None).last() | ||
891 | if obj: | ||
892 | version = obj.version | ||
893 | if version: | ||
894 | version += 1 | ||
895 | else: | ||
896 | version = 1 | ||
897 | else: | ||
898 | version = 1 | ||
899 | try: | ||
900 | demo_data = get_oss_file(data['url']) | ||
901 | except Exception as e: | ||
902 | return JsonResponse(ResponseFactory(code=201, message="音频地址获取不到资源,检查链接", data=None, status='fail')) | ||
903 | # #保存demo文件获取时长 | ||
904 | demo_path = "./api/static/demo-{}.mp3".format(str(random.randint(0, 10000000000))) | ||
905 | with open(demo_path, "wb") as f: | ||
906 | f.write(demo_data) | ||
907 | f.close() | ||
908 | |||
909 | duration = librosa.get_duration(filename=demo_path) | ||
910 | |||
911 | # 删除零时文件 | ||
912 | os.remove(demo_path) | ||
913 | try: | ||
914 | with transaction.atomic(): | ||
915 | if type == 'Submit': | ||
916 | models.ActivityHasUsers.objects.filter(user_id=user['id'],activity_id=data['activity_id']).update(type="Save",updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
917 | ahu = models.ActivityHasUsers.objects.create( | ||
918 | activity_id = data['activity_id'], | ||
919 | user_id = user['id'], | ||
920 | demo_url = data['url'], | ||
921 | durations=duration, | ||
922 | wav_url = post_data.get("wav_url",""), | ||
923 | wav_durations=post_data.get("wav_durations", 0), | ||
924 | status = 0, | ||
925 | syn_status = 1, | ||
926 | type = type, | ||
927 | open_id = open_id, | ||
928 | is_hide = is_hide, | ||
929 | mode = 1, | ||
930 | version = version, | ||
931 | submit_at= timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
932 | created_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
933 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
934 | ) | ||
935 | # 存入自主报价 | ||
936 | if self_price: | ||
937 | models.ActivityUserHasPrices.objects.update_or_create( | ||
938 | user_id=user['id'],activity_id=data['activity_id'], | ||
939 | defaults={ | ||
940 | "value": self_price['value'], | ||
941 | "is_deduct": self_price['is_deduct'], | ||
942 | "is_talk": self_price['is_talk'], | ||
943 | "address_id": self_price['address_id'], | ||
944 | "is_accept_address": self_price['is_accept_address'], | ||
945 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
946 | "updated_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), }, | ||
947 | ) | ||
948 | |||
949 | #更新到动态 | ||
950 | is_tidings = post_data.get("is_tidings", 0) | ||
951 | if is_tidings == 1: | ||
952 | models.UserHasTidings.objects.create(user_id=user['id'],activity_id=data['activity_id'],type=2,url=data['url'], created_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
953 | # 提交作品计数 1.先检查用户对该作品之前是否有提交且未读的消息 | ||
954 | user_msg = models.UserMessages.objects.filter(is_read=0, sender_id=user['id'],activity_id=data['activity_id'], deleted_at=None, type=3) | ||
955 | if user_msg: | ||
956 | user_msg.update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
957 | |||
958 | # 获取全体管理员和推荐人和项目管理员open_id | ||
959 | project_id = models.Activitys.objects.filter(id=data['activity_id']).first().project_id | ||
960 | project = models.Projects.objects.filter(id=project_id).first() | ||
961 | project_user_ids = [] | ||
962 | if project: | ||
963 | if project.is_public:project_user_ids = list(models.UserHasProjects.objects.filter(project_id=project_id).values_list('user_id',flat=True)) | ||
964 | else:project_user_ids = [models.Activitys.objects.filter(id=data['activity_id']).first().user_id] | ||
965 | project_user_unionid = list(models.Users.objects.filter(id__in=project_user_ids,deleted_at=None,status=1).values_list('unionid', flat=True)) | ||
966 | admin_unionid = list(models.Users.objects.filter(scope=1,deleted_at=None,status=1).values_list('unionid', flat=True)) | ||
967 | push_open_ids = list(models.WechatOfficialUsers.objects.filter(union_id__in=admin_unionid+project_user_unionid,is_subscribe=1).values_list('open_id', flat=True)) | ||
968 | song_name = models.Activitys.objects.filter(id=data['activity_id']).first().song_name | ||
969 | # 再创建消息 | ||
970 | business_id = user['business_id'] | ||
971 | if business_id: | ||
972 | #获取推荐人公众号open_id | ||
973 | unionid = models.Users.objects.filter(id=business_id).values_list('unionid', flat=True) | ||
974 | wechat_official = models.WechatOfficialUsers.objects.filter(union_id__in=unionid,is_subscribe=1).last() | ||
975 | if wechat_official: | ||
976 | # 公众号推送 | ||
977 | p_data = {'channel': 'singer_related', 'open_id': [wechat_official.open_id], | ||
978 | 'data': {"title": "您的歌手参加了试唱歌曲", "name": user['nick_name']+"("+user['real_name']+")", | ||
979 | "intro": "参加了试唱歌曲《{}》".format(song_name), | ||
980 | "remark": "点击前往 >", | ||
981 | "page": "/packageMy/pages/like?tab=2"}} | ||
982 | pushSubscribeMessage(p_data) | ||
983 | #发给绑定的推荐人 | ||
984 | m_data = {'sender_id': user['id'], 'receivers': [business_id], 'activity_id': data['activity_id'],'type': 3,'is_bind':1} | ||
985 | createMessage(m_data) | ||
986 | |||
987 | # 极光推送-提交作品推荐人 | ||
988 | j_title = "您的歌手参加了试唱" | ||
989 | j_content = "您的歌手{}参加了试唱活动《{}》".format(user['nick_name'], song_name) | ||
990 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
991 | "receiver_value": [business_id], | ||
992 | "extras": {"type": "ToTaSing", "value": ""}} | ||
993 | JPush().jpush_v3(jdata) | ||
994 | |||
995 | #给全体管理员和项目管理员推服务号消息 | ||
996 | p_data = {'channel': 'activity_join', 'open_id': push_open_ids, | ||
997 | 'data': {"first":"{}({})提交了试唱作品".format(user['nick_name'],user['real_name']),"keyword1": "《"+song_name+"》", "keyword2": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
998 | "remark": "点击试听 >","page":"/pages/index/index"} | ||
999 | } | ||
1000 | pushSubscribeMessage(p_data) | ||
1001 | |||
1002 | #外部管理员id | ||
1003 | activity_manage_ids = list(models.UserManageActivitie.objects.filter(activity_id=data['activity_id']).values_list('user_id',flat=True)) | ||
1004 | # 发送系统消息(平台管理员+项目管理员+外部管理员) | ||
1005 | receivers = list(models.Users.objects.filter(scope=1).values_list('id', flat=True)) | ||
1006 | receivers = list(set(receivers+project_user_ids+activity_manage_ids)) | ||
1007 | m_data = {'sender_id': user['id'], 'receivers': receivers,'activity_id': data['activity_id'], 'type': 3,'is_bind':0} | ||
1008 | createMessage(m_data) | ||
1009 | |||
1010 | # 极光推送-提交作品全体管理员 | ||
1011 | j_title = "有新用户提交试唱" | ||
1012 | j_content = "{}参与了试唱《{}》".format(user['nick_name'],song_name) | ||
1013 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
1014 | "receiver_value": receivers, | ||
1015 | "extras": {"type": "ToPlatfromSing", "value": ""}} | ||
1016 | JPush().jpush_v3(jdata) | ||
1017 | # 歌手积分 | ||
1018 | user_point_record(user_id=user['id'], type='AutoSubmit', activity_id=data['activity_id']) | ||
1019 | # 推荐人积分 | ||
1020 | if user['business_id']: | ||
1021 | user_point_record(user_id=user['business_id'], type='SingerAutoSubmit', | ||
1022 | activity_id=data['activity_id'], singer_id=user['id']) | ||
1023 | data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url} | ||
1024 | return JsonResponse(ResponseFactory(code=200, message="提交成功", data=data, status='success')) | ||
1025 | else: | ||
1026 | ahu = models.ActivityHasUsers.objects.create( | ||
1027 | activity_id=data['activity_id'], | ||
1028 | user_id=user['id'], | ||
1029 | demo_url=data['url'], | ||
1030 | durations=duration, | ||
1031 | wav_url=post_data.get("wav_url", ""), | ||
1032 | wav_durations=post_data.get("wav_durations", 0), | ||
1033 | status=0, | ||
1034 | syn_status=1, | ||
1035 | type=type, | ||
1036 | open_id=open_id, | ||
1037 | is_hide=is_hide, | ||
1038 | mode=1, | ||
1039 | version=version, | ||
1040 | submit_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
1041 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
1042 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
1043 | ) | ||
1044 | data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url} | ||
1045 | return JsonResponse(ResponseFactory(code=200, message="保存成功", data=data, status='success')) | ||
1046 | except Exception as e: | ||
1047 | logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(user['id'], request.body, e)) | ||
1048 | return JsonResponse(ResponseFactory(code=201, message="提交失败:{}".format(e), data=None, status='fail')) | ||
1049 | else: | ||
1050 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1051 | else: | ||
1052 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
1053 | |||
1054 | |||
1055 | def toFileData(file_name,file_type): | ||
1056 | path = './api/static/' | ||
1057 | t = str(int(time.time())) + str(random.randint(0, 10000000000)) | ||
1058 | file_path = path + t + "." + file_type | ||
1059 | os.system("ffmpeg -i "+ path+file_name+ " " + file_path) | ||
1060 | with open(file_path, 'rb') as f: | ||
1061 | fileData = f.read() | ||
1062 | f.close() | ||
1063 | #删除零时文件 | ||
1064 | os.remove(file_path) | ||
1065 | return fileData | ||
1066 | |||
1067 | |||
1068 | # @AuthPermissionRequired() | ||
1069 | def UploadAudio(request): | ||
1070 | if request.method == "POST": | ||
1071 | fileData = request.FILES.get('file') | ||
1072 | if not fileData: | ||
1073 | return JsonResponse(ResponseFactory(code=400, message="未读取到上传文件", data=None, status='fail')) | ||
1074 | file_type = fileData.name.split('.')[1] | ||
1075 | if file_type == 'mp3': | ||
1076 | file_url = auto_upload_audio(fileData.read(),'mp3') | ||
1077 | else: | ||
1078 | path = './api/static/' | ||
1079 | t = str(int(time.time())) + str(random.randint(0, 10000000000)) | ||
1080 | filename = t + "." + file_type | ||
1081 | with open(path + filename, "wb") as f: | ||
1082 | f.write(fileData.read()) | ||
1083 | f.close() | ||
1084 | fileData = toFileData(filename,'mp3') | ||
1085 | file_url = auto_upload_audio(fileData,'mp3') | ||
1086 | os.remove(path + filename) | ||
1087 | data = {"type": "mp3", "name": "", "url": file_url, "size": "", "disk": "oss", "created_at": "", "id": 0} | ||
1088 | return JsonResponse(ResponseFactory(code=200, message="上传成功", data=data, status='success')) | ||
1089 | else: | ||
1090 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
1091 | |||
1092 | |||
1093 | class Collection(APIView): | ||
1094 | @method_decorator(AuthPermissionRequired()) | ||
1095 | def get(self,request): | ||
1096 | status = request.GET.get('status','all') #默认所有 | ||
1097 | text = request.GET.get('text') #默认所有 | ||
1098 | user_id = get_user_info(request)['id'] | ||
1099 | ids = list(models.UserActivityCollections.objects.filter(user_id=user_id,deleted_at=None).order_by('-created_at').values_list('activity_id',flat=True)) | ||
1100 | idList = ",".join('%s' % id for id in ids) | ||
1101 | kwargs = {"deleted_at":None,"id__in":ids} | ||
1102 | if status == 'active':kwargs['status'] = 1 | ||
1103 | if text:kwargs['song_name__icontains'] = text | ||
1104 | queryset = models.Activitys.objects.filter(**kwargs).extra(select={'m': 'FIELD(id,{})'.format(idList)}, order_by=['m']) | ||
1105 | page_obj = PageNumberPagination() | ||
1106 | page_data = page_obj.paginate_queryset(queryset, request) | ||
1107 | activitys = serializers.CollectionActivitysSerializer(page_data, many=True, context={"user_id": user_id}).data | ||
1108 | # 活动配置信息 | ||
1109 | config_ids = list(models.SystemConfig.objects.filter( | ||
1110 | identifier__in=['activity_lang', 'activity_speed', 'activity_sex', 'activity_mark']).values_list('id', | ||
1111 | flat=True).all()) | ||
1112 | configs = models.SystemConfig.objects.filter(parent_id__in=config_ids).values_list('identifier', 'name', | ||
1113 | 'content') | ||
1114 | for activity in activitys: | ||
1115 | lang = activity['lang'] if activity['lang'] else [] | ||
1116 | langs = [] | ||
1117 | for config in configs: | ||
1118 | if config[0] == activity['sex']: | ||
1119 | activity['sex'] = config[1] if activity['sex'] else None | ||
1120 | if config[0] == activity['mark']: | ||
1121 | activity['mark'] = config[2] if activity['mark'] else None | ||
1122 | if config[0] == activity['speed']: | ||
1123 | activity['speed'] = config[1] if activity['speed'] else None | ||
1124 | if config[0] in lang: | ||
1125 | langs.append(config[1]) | ||
1126 | activity['lang'] = langs | ||
1127 | data = {"activitys": activitys, "count": len(queryset)} | ||
1128 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
1129 | |||
1130 | @method_decorator(AuthPermissionRequired()) | ||
1131 | def post(self,request): | ||
1132 | obj = verification.collection(json.loads(request.body)) | ||
1133 | if obj.is_valid(): | ||
1134 | data = json.loads(request.body) | ||
1135 | user = get_user_info(request) | ||
1136 | is_active = models.UserActivityCollections.objects.filter(user_id=user['id'],activity_id=data['activity_id'], deleted_at=None) | ||
1137 | if is_active: | ||
1138 | return JsonResponse(ResponseFactory(code=400, message='请勿重复收藏', data=None, status='fail')) | ||
1139 | try: | ||
1140 | with transaction.atomic(): | ||
1141 | models.UserActivityCollections.objects.create( | ||
1142 | user_id=user['id'], | ||
1143 | activity_id=data['activity_id'], | ||
1144 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
1145 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
1146 | ) | ||
1147 | # 消息计数 | ||
1148 | business_id = user['business_id'] | ||
1149 | role = user['role'] | ||
1150 | #有商务且为歌手 | ||
1151 | if business_id and role=='Singer': | ||
1152 | m_data = {'receivers': [business_id], 'sender_id': user['id'],'activity_id':data['activity_id'], 'type': 2,'is_bind':1} | ||
1153 | createMessage(m_data) | ||
1154 | # 推送消息给推荐人 | ||
1155 | business_unionid = models.Users.objects.filter(id=business_id).first().unionid | ||
1156 | business_wechat_official = models.WechatOfficialUsers.objects.filter(union_id=business_unionid,is_subscribe=1).last() | ||
1157 | song_name = models.Activitys.objects.filter(id=data['activity_id']).first().song_name | ||
1158 | if business_wechat_official: | ||
1159 | business_open_id = business_wechat_official.open_id | ||
1160 | name = user['nick_name'] + "({})".format(user['real_name']) | ||
1161 | p_data = {'channel': 'singer_related', 'open_id': [business_open_id], | ||
1162 | 'data': {"title": "您的歌手收藏了试唱活动", "name": name, "intro": "收藏了试唱活动《{}》".format(song_name), | ||
1163 | "remark": "点击前往 >", | ||
1164 | "page": "packageMy/pages/like?tab=1"}} | ||
1165 | pushSubscribeMessage(p_data) | ||
1166 | # 极光推送-歌手收藏 | ||
1167 | j_title = "您的歌手收藏了试唱" | ||
1168 | j_content = "您的歌手{}收藏了试唱活动《{}》".format( user['nick_name'],song_name) | ||
1169 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
1170 | "receiver_value": [business_id], | ||
1171 | "extras": {"type": "ToTaCollection", "value": ""}} | ||
1172 | JPush().jpush_v3(jdata) | ||
1173 | except Exception as e: | ||
1174 | return JsonResponse(ResponseFactory(code=201, message="收藏失败。请联系管理员", data=None, status='fail')) | ||
1175 | return JsonResponse(ResponseFactory(code=200, message="收藏成功", data=None, status='success')) | ||
1176 | else: | ||
1177 | return JsonResponse( | ||
1178 | ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1179 | |||
1180 | @method_decorator(AuthPermissionRequired()) | ||
1181 | def delete(self,request): | ||
1182 | obj = verification.collection(json.loads(request.body)) | ||
1183 | if obj.is_valid(): | ||
1184 | data = json.loads(request.body) | ||
1185 | user = get_user_info(request) | ||
1186 | is_active = models.UserActivityCollections.objects.filter( user_id=user['id'],activity_id=data['activity_id'],deleted_at=None) | ||
1187 | if is_active: | ||
1188 | try: | ||
1189 | with transaction.atomic(): | ||
1190 | is_active.update(updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),deleted_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S") ) | ||
1191 | #取消收藏取消计数 | ||
1192 | m_data = {"sender_id":user['id'],"activity_id":data['activity_id'],"type":2} | ||
1193 | deleteMessage(m_data) | ||
1194 | except Exception as e: | ||
1195 | return JsonResponse(ResponseFactory(code=201, message="取消失败。请联系管理员", data=None, status='fail')) | ||
1196 | return JsonResponse(ResponseFactory(code=200, message="已取消收藏", data=None, status='success')) | ||
1197 | else: | ||
1198 | return JsonResponse(ResponseFactory(code=400, message='未收藏不能取消', data=None, status='fail')) | ||
1199 | else: | ||
1200 | return JsonResponse( | ||
1201 | ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1202 | |||
1203 | |||
1204 | def cancelcollection(request): | ||
1205 | if request.method == "POST": | ||
1206 | obj = verification.collection(json.loads(request.body)) | ||
1207 | if obj.is_valid(): | ||
1208 | data = json.loads(request.body) | ||
1209 | user = get_user_info(request) | ||
1210 | is_active = models.UserActivityCollections.objects.filter(user_id=user['id'],activity_id=data['activity_id'], deleted_at=None) | ||
1211 | if is_active: | ||
1212 | try: | ||
1213 | with transaction.atomic(): | ||
1214 | is_active.update(updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
1215 | # 取消收藏取消计数 | ||
1216 | m_data = {"sender_id": user['id'], "activity_id": data['activity_id'], "type": 2} | ||
1217 | deleteMessage(m_data) | ||
1218 | except: | ||
1219 | return JsonResponse(ResponseFactory(code=201, message="取消失败。请联系管理员", data=None, status='fail')) | ||
1220 | return JsonResponse(ResponseFactory(code=200, message="已取消收藏", data=None, status='success')) | ||
1221 | else: | ||
1222 | return JsonResponse(ResponseFactory(code=400, message='未收藏不能取消', data=None, status='fail')) | ||
1223 | else: | ||
1224 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1225 | else: | ||
1226 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
1227 | |||
1228 | class ShareUsersList(APIView): | ||
1229 | @method_decorator(AuthPermissionRequired()) | ||
1230 | def get(self,request): | ||
1231 | text = request.GET.get('text','') | ||
1232 | if text: | ||
1233 | user_id = get_user_info(request)['id'] | ||
1234 | queryset = models.Users.objects.filter(Q(nick_name__icontains=text) | Q(real_name__icontains=text),~Q(id=user_id),audit_status=1,status=1,deleted_at=None) | ||
1235 | else: | ||
1236 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=[], status='success')) | ||
1237 | users = serializers.BusinessSerializer(queryset,many=True).data | ||
1238 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=users, status='success')) | ||
1239 | |||
1240 | class ShareUsers(APIView): | ||
1241 | @method_decorator(AuthPermissionRequired()) | ||
1242 | def post(self,request): | ||
1243 | try: | ||
1244 | post_data = json.loads(request.body) | ||
1245 | except: | ||
1246 | return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
1247 | obj = verification.ShareUsersVerify(data=post_data) | ||
1248 | if not obj.is_valid(): | ||
1249 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1250 | user_id = get_user_info(request)['id'] | ||
1251 | activity_id = obj.data.get('activity_id') | ||
1252 | share_id = obj.data.get('share_id') | ||
1253 | models.ActivityShareUsers.objects.update_or_create( | ||
1254 | activity_id=activity_id, user_id=user_id, | ||
1255 | defaults={'share_id': share_id,'created_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S"),'updated_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S")}, | ||
1256 | ) | ||
1257 | return JsonResponse(ResponseFactory(code=200, message="保存成功", data=None, status='success')) | ||
1258 | |||
1259 | def test(request): | ||
1260 | if request.method == "POST": | ||
1261 | fileData = json.loads(request.body).get('file') | ||
1262 | print (type(fileData),fileData) | ||
1263 | import numpy as np | ||
1264 | data = np.array(fileData.get('data')) | ||
1265 | data.tofile('./ttt.mp3') | ||
1266 | return JsonResponse(ResponseFactory(code=200, message="上传成功", data=fileData, status='success')) | ||
1267 | else: | ||
1268 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
1269 |
api/ApiList/community.py
0 → 100644
1 | import json | ||
2 | from django.http import JsonResponse | ||
3 | from api import models | ||
4 | from api import serializers | ||
5 | from rest_framework.views import APIView | ||
6 | from api import verification | ||
7 | from django.db import transaction | ||
8 | from django.utils import timezone | ||
9 | from django.utils.decorators import method_decorator | ||
10 | from api.views import ResponseFactory,PageNumberPagination,createMessage,pushSubscribeMessage,JPush,get_user_info,AuthPermissionRequired,senstive_word_check | ||
11 | from ratelimit.decorators import ratelimit | ||
12 | from django.db.models import Q | ||
13 | from api import loggin | ||
14 | |||
15 | |||
16 | |||
17 | class Tidings(APIView): | ||
18 | |||
19 | @method_decorator(AuthPermissionRequired()) | ||
20 | # @method_decorator(rate_limit()) | ||
21 | @method_decorator(ratelimit(key='ip',rate='1/1s', block=True)) | ||
22 | def post(self,request): | ||
23 | """发布动态""" | ||
24 | post_data = json.loads(request.body) | ||
25 | obj = verification.TidingsVerify(data=post_data) | ||
26 | if not obj.is_valid(): | ||
27 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
28 | title = obj.data.get('title') | ||
29 | activity_ids = obj.data.get('activity_ids') | ||
30 | singer_ids = obj.data.get('singer_ids') | ||
31 | sounds = obj.data.get('sounds') | ||
32 | photos = obj.data.get('photos') | ||
33 | type= obj.data.get('type') | ||
34 | #获取用户信息 | ||
35 | user = get_user_info(request) | ||
36 | user_id = user['id'] | ||
37 | role = user['role'] | ||
38 | #活动动态除歌手以外都能发 | ||
39 | if type == 4 and role == 'Singer': | ||
40 | return JsonResponse(ResponseFactory(code=400, message='歌手不能发布活动动态', data=None, status='fail')) | ||
41 | if title==activity_ids==singer_ids==sounds==photos==None: | ||
42 | return JsonResponse(ResponseFactory(code=400, message='发布内容不能为空', data=None, status='fail')) | ||
43 | #创建动态 | ||
44 | try: | ||
45 | with transaction.atomic(): | ||
46 | #创建动态 | ||
47 | tidings=models.UserHasTidings.objects.create( | ||
48 | title=title, | ||
49 | user_id=user_id, | ||
50 | type =type, | ||
51 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
52 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
53 | ) | ||
54 | #补充关联数据-推荐活动 | ||
55 | items_list = [singer_ids,activity_ids,sounds,photos] | ||
56 | save_list = [] | ||
57 | for items in items_list: | ||
58 | if items: | ||
59 | for value in items: | ||
60 | saveobj = models.TidingsHasContents( | ||
61 | tidings_id = tidings.id, | ||
62 | type = items_list.index(items)+1, | ||
63 | value = value, | ||
64 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
65 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
66 | ) | ||
67 | save_list.append(saveobj) | ||
68 | models.TidingsHasContents.objects.bulk_create(save_list) | ||
69 | except Exception as e: | ||
70 | return JsonResponse(ResponseFactory(code=400, message='发布动态失败:{}'.format(e), data=None, status='fail')) | ||
71 | return JsonResponse(ResponseFactory(code=200, message="发布成功", data=None, status='success')) | ||
72 | |||
73 | class TidingsList(APIView): | ||
74 | def get(self, request): | ||
75 | kwargs = dict() | ||
76 | type = int(request.GET.get('type',3)) | ||
77 | try: | ||
78 | user = get_user_info(request) | ||
79 | user_id = user['id'] | ||
80 | scope = user['scope'] | ||
81 | except: | ||
82 | user_id = 0 | ||
83 | scope = 0 | ||
84 | #去掉不感兴趣的 | ||
85 | tidings_ids = list(models.UserUnlikeTidings.objects.filter(user_id=user_id).values_list('tidings_id',flat=True)) | ||
86 | orderbyList = ['-is_top','-created_at'] | ||
87 | kwargs['deleted_at'] = None | ||
88 | #用户没删除且状态为启用中 | ||
89 | kwargs['user__deleted_at'] = None | ||
90 | kwargs['user__status'] = 1 | ||
91 | if scope != 1: | ||
92 | kwargs['status'] = 0 | ||
93 | if type == 4: | ||
94 | kwargs['type'] = 4 | ||
95 | queryset = models.UserHasTidings.objects.filter(~Q(id__in=tidings_ids),**kwargs).order_by(*orderbyList) | ||
96 | else: | ||
97 | queryset = models.UserHasTidings.objects.filter(~Q(type=4),~Q(type=2),~Q(id__in=tidings_ids),**kwargs).order_by(*orderbyList) | ||
98 | page_obj = PageNumberPagination() | ||
99 | page_data = page_obj.paginate_queryset(queryset, request) | ||
100 | ser_obj = serializers.CommunityTidingsSerializer(page_data, many=True, context={"user_id": user_id}) | ||
101 | data = {"data": ser_obj.data, "count": queryset.count()} | ||
102 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
103 | |||
104 | |||
105 | class TidingsLimiting(APIView): | ||
106 | @method_decorator(AuthPermissionRequired()) | ||
107 | def put(self,request): | ||
108 | scope = get_user_info(request)['scope'] | ||
109 | if scope != 1: | ||
110 | return JsonResponse(ResponseFactory(code=400, message="你不是管理员,无此权限", data=None, status='fail')) | ||
111 | try:post_data = json.loads(request.body) | ||
112 | except: return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
113 | obj = verification.TidingsLimitVerify(data=post_data) | ||
114 | if not obj.is_valid(): | ||
115 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
116 | tidings_id = obj.data.get('tidings_id') | ||
117 | status = obj.data.get('status') | ||
118 | #限流或者解除限流 | ||
119 | models.UserHasTidings.objects.filter(id=tidings_id).update(status=status) | ||
120 | message = "已解除限流" if status == 0 else "已限流" | ||
121 | |||
122 | #创建消息内容组装 | ||
123 | user = get_user_info(request) | ||
124 | user_id = user['id'] | ||
125 | tidings = models.UserHasTidings.objects.filter(id=tidings_id).first() | ||
126 | auther = models.Users.objects.filter(id=tidings.user_id).first() | ||
127 | title = "您发布的动态已被解除限流" if status == 0 else "您的发布动态被限制查看.如有疑问请联系微信LZX19960101" | ||
128 | send_type = 9 if status == 0 else 8 | ||
129 | if tidings.type == 2: | ||
130 | activity = models.Activitys.objects.filter(id=tidings.activity_id).first() | ||
131 | content = "《{}》{}".format(activity.song_name, auther.nick_name) | ||
132 | elif tidings.type in [3,4] : | ||
133 | tidings_has_content = serializers.SystemMsgTidingsSerializer(tidings, many=False).data | ||
134 | content = "{}".format(tidings.title) | ||
135 | for recommend_activity in tidings_has_content['recommend_activitys']: | ||
136 | content = content + "[试唱活动《{}》]".format(recommend_activity['song_name']) | ||
137 | for recommend_singer in tidings_has_content['recommend_singers']: | ||
138 | content = content + "[{}的名片]".format(recommend_singer['nick_name']) | ||
139 | if tidings_has_content['photos']: | ||
140 | content = content + "[图片]" | ||
141 | if tidings_has_content['sounds']: | ||
142 | content = content + "[音频]" | ||
143 | # 极光推送 | ||
144 | j_title = "您发布的动态被平台解除限流" if status == 0 else "您发布的动态被平台限流" | ||
145 | jdata = {"title": j_title, "content": content, "content_type": "text", | ||
146 | "receiver_value": [tidings.user_id], | ||
147 | "extras": {"type": "ToSystemMsg", "value": ""}} | ||
148 | JPush().jpush_v3(jdata) | ||
149 | #服务号推送 | ||
150 | wechat_data = models.WechatOfficialUsers.objects.filter(union_id=auther.unionid).first() | ||
151 | if wechat_data: | ||
152 | p_data = {'channel': 'square_result', 'open_id': [wechat_data.open_id], | ||
153 | 'data': {"first": j_title, "keyword1": content, | ||
154 | "keyword2": str(tidings.created_at), 'keyword3': auther.nick_name} | ||
155 | } | ||
156 | pushSubscribeMessage(p_data) | ||
157 | #创建消息 | ||
158 | m_data = {"title": title, "content": content, 'receivers': [tidings.user_id], "activity_id": tidings_id, | ||
159 | 'sender_id': user_id, 'type': send_type} | ||
160 | createMessage(m_data) | ||
161 | return JsonResponse(ResponseFactory(code=200, message=message, data=None, status='success')) | ||
162 | |||
163 | class TidingsReport(APIView): | ||
164 | @method_decorator(AuthPermissionRequired()) | ||
165 | def post(self,request): | ||
166 | try:post_data = json.loads(request.body) | ||
167 | except: return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
168 | obj = verification.TidingsReportVerify(data=post_data) | ||
169 | if not obj.is_valid(): | ||
170 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
171 | user = get_user_info(request) | ||
172 | user_id = user['id'] | ||
173 | if user['audit_status'] in [0, 2]: | ||
174 | return JsonResponse(ResponseFactory(code=400, message="请等待账号审核通过后再操作", data=None, status='fail')) | ||
175 | tidings_id = obj.data.get('tidings_id',0) | ||
176 | comment_id = post_data.get('comment_id', 0) | ||
177 | person_id = post_data.get('person_id', 0) | ||
178 | reason = obj.data.get('reason') | ||
179 | type = post_data.get('type',1) | ||
180 | desc = post_data.get('desc',None) | ||
181 | if tidings_id: | ||
182 | is_exists = models.TidingsHasReports.objects.filter(tidings_id=tidings_id,user_id=user_id,type=type,status=0).exists() | ||
183 | if is_exists: | ||
184 | return JsonResponse(ResponseFactory(code=400, message="已举报,请勿重复操作", data=None, status='fail')) | ||
185 | if person_id: | ||
186 | is_exists = models.TidingsHasReports.objects.filter(person_id=person_id,user_id=user_id,status=0).exists() | ||
187 | if is_exists: | ||
188 | return JsonResponse(ResponseFactory(code=400, message="平台已接收到您提交的举报信息,正在处理中 ~", data=None, status='fail')) | ||
189 | models.TidingsHasReports.objects.create( | ||
190 | tidings_id=tidings_id, | ||
191 | comment_id = comment_id, | ||
192 | reason=reason, | ||
193 | user_id=user_id, | ||
194 | person_id = person_id, | ||
195 | desc = desc, | ||
196 | type = type, | ||
197 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
198 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
199 | ) | ||
200 | return JsonResponse(ResponseFactory(code=200, message="举报成功", data=None, status='success')) | ||
201 | |||
202 | class RecordUser(APIView): | ||
203 | @method_decorator(AuthPermissionRequired()) | ||
204 | def post(self,request): | ||
205 | try:post_data = json.loads(request.body) | ||
206 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
207 | obj = verification.TidingsRecordUserVerify(data=post_data) | ||
208 | if not obj.is_valid(): | ||
209 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
210 | tidings_ids = obj.data.get('tidings_id') | ||
211 | user_id = get_user_info(request)['id'] | ||
212 | save_list = [] | ||
213 | for tidings_id in tidings_ids: | ||
214 | is_exists = models.UserViewTidings.objects.filter(tidings_id=tidings_id, user_id=user_id).exists() | ||
215 | if not is_exists: | ||
216 | save_data = models.UserViewTidings( | ||
217 | tidings_id=tidings_id, | ||
218 | user_id=user_id, | ||
219 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
220 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
221 | ) | ||
222 | save_list.append(save_data) | ||
223 | models.UserViewTidings.objects.bulk_create(save_list) | ||
224 | return JsonResponse(ResponseFactory(code=200, message="记录成功", data=None, status='success')) | ||
225 | |||
226 | |||
227 | class TidingsInteracts(APIView): | ||
228 | @method_decorator(AuthPermissionRequired()) | ||
229 | @method_decorator(ratelimit(key='ip',rate='1/1s', block=True)) | ||
230 | # @method_decorator(rate_limit()) | ||
231 | def post(self,request): | ||
232 | """互动""" | ||
233 | try:post_data = json.loads(request.body) | ||
234 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
235 | obj = verification.TidingsInteractsVerify(data=post_data) | ||
236 | if not obj.is_valid(): | ||
237 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
238 | type_id = obj.data.get('type_id') | ||
239 | type = obj.data.get('type') | ||
240 | status= obj.data.get('status') | ||
241 | user = get_user_info(request) | ||
242 | if user['audit_status'] in [0,2]: | ||
243 | return JsonResponse(ResponseFactory(code=400, message="请等待账号审核通过后再操作", data=None, status='fail')) | ||
244 | user_id = user['id'] | ||
245 | is_exists = models.TidingsHasInteracts.objects.filter(type_id=type_id, type=type,user_id=user_id,status=status,deleted_at=None).exists() | ||
246 | if is_exists: | ||
247 | return JsonResponse(ResponseFactory(code=400, message="重复数据", data=None, status='fail')) | ||
248 | #创建消息内容组装 | ||
249 | if type == 1: | ||
250 | tidings = models.UserHasTidings.objects.filter(id=type_id).first() | ||
251 | auther = models.Users.objects.filter(id=tidings.user_id).first() | ||
252 | tidings_has_content = serializers.SystemMsgTidingsSerializer(tidings, many=False).data | ||
253 | receivers = tidings.user_id | ||
254 | if tidings.type == 2: | ||
255 | activity = models.Activitys.objects.filter(id=tidings.activity_id).first() | ||
256 | if status == 1: | ||
257 | send_type = 6 | ||
258 | title = "{}觉得好听".format(user["nick_name"]) | ||
259 | else: | ||
260 | send_type = 7 | ||
261 | title = "{}觉得很开心".format(user["nick_name"]) | ||
262 | content = "《{}》{}".format(activity.song_name, auther.nick_name) | ||
263 | elif tidings.type == 3: | ||
264 | title = "{}觉得很赞".format(user["nick_name"]) | ||
265 | send_type = 5 | ||
266 | content = "{}".format(tidings.title) | ||
267 | for recommend_activity in tidings_has_content['recommend_activitys']: | ||
268 | content = content + "[试唱活动《{}》]".format(recommend_activity['song_name']) | ||
269 | for recommend_singer in tidings_has_content['recommend_singers']: | ||
270 | content = content + "[{}的名片]".format(recommend_singer['nick_name']) | ||
271 | if tidings_has_content['photos']: | ||
272 | content = content + "[图片]" | ||
273 | if tidings_has_content['sounds']: | ||
274 | content = content + "[音频]" | ||
275 | # 生成消息通知 | ||
276 | m_data = {"title": title, "content": content, 'receivers': [receivers], "activity_id": type_id, | ||
277 | 'sender_id': user_id, 'type': send_type} | ||
278 | createMessage(m_data) | ||
279 | if type == 3: | ||
280 | auther = models.Users.objects.filter(id=type_id).first() | ||
281 | if not auther.sound: | ||
282 | return JsonResponse(ResponseFactory(code=400, message="用户还未上传声音", data=None, status='fail')) | ||
283 | receivers = auther.id | ||
284 | title = "{}觉得你的声音很赞".format(user["nick_name"]) | ||
285 | send_type = 4 | ||
286 | content = "[{}的声音]".format(auther.nick_name) | ||
287 | |||
288 | # 生成消息通知 | ||
289 | m_data = {"title": title, "content": content, 'receivers': [receivers], "activity_id": type_id, | ||
290 | 'sender_id': user_id, 'type': send_type} | ||
291 | createMessage(m_data) | ||
292 | |||
293 | #极光推送 | ||
294 | # j_title = "有人回复了您的动态" | ||
295 | # jdata = {"title": j_title, "content": content, "content_type": "text", | ||
296 | # "receiver_value": [tidings.user_id], | ||
297 | # "extras": {"type": "ToSystemMsg", "value": ""}} | ||
298 | # JPush().jpush_v3(jdata) | ||
299 | # #服务号推送 | ||
300 | # wechat_data = models.WechatOfficialUsers.objects.filter(union_id = auther.unionid).first() | ||
301 | # if wechat_data: | ||
302 | # p_data = {'channel': 'square_result', 'open_id': [wechat_data.open_id], | ||
303 | # 'data': {"first": j_title, "keyword1":content , | ||
304 | # "keyword2": str(tidings.created_at),'keyword3':auther.nick_name} | ||
305 | # } | ||
306 | # pushSubscribeMessage(p_data) | ||
307 | models.TidingsHasInteracts.objects.create( | ||
308 | type_id=type_id, | ||
309 | type=type, | ||
310 | user_id=user_id, | ||
311 | status=status, | ||
312 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
313 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
314 | ) | ||
315 | return JsonResponse(ResponseFactory(code=200, message="记录成功", data=None, status='success')) | ||
316 | |||
317 | @method_decorator(AuthPermissionRequired()) | ||
318 | def put(self,request): | ||
319 | """取消互动""" | ||
320 | try: | ||
321 | post_data = json.loads(request.body) | ||
322 | except: | ||
323 | return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
324 | obj = verification.InteractsDeleteVerify(data=post_data) | ||
325 | if not obj.is_valid(): | ||
326 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
327 | type_id = obj.data.get('type_id') | ||
328 | type = obj.data.get('type') | ||
329 | status = obj.data.get('status') | ||
330 | user = get_user_info(request) | ||
331 | user_id = user['id'] | ||
332 | is_exists = models.TidingsHasInteracts.objects.filter(type_id=type_id, type=type, user_id=user_id,status=status, deleted_at=None) | ||
333 | if not is_exists: | ||
334 | return JsonResponse(ResponseFactory(code=400, message="不存在的数据", data=None, status='fail')) | ||
335 | #删除操作 | ||
336 | is_exists.update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
337 | return JsonResponse(ResponseFactory(code=200, message="取消成功", data=None, status='success')) | ||
338 | |||
339 | |||
340 | class SeleteActivity(APIView): | ||
341 | @method_decorator(AuthPermissionRequired()) | ||
342 | def get(self,request): | ||
343 | text = request.GET.get('text', '') | ||
344 | orderbyList = ['-weight', '-created_at'] | ||
345 | if text: | ||
346 | queryset = models.Activitys.objects.filter(status=1,song_name__icontains=text,audit_status=1,deleted_at=None).order_by(*orderbyList) | ||
347 | else: | ||
348 | queryset = models.Activitys.objects.filter(status=1,audit_status=1,deleted_at=None).order_by(*orderbyList) | ||
349 | page_obj = PageNumberPagination() | ||
350 | page_data = page_obj.paginate_queryset(queryset, request) | ||
351 | ser_obj = serializers.TidingsSeleteActivitySerializer(page_data, many=True) | ||
352 | data = {"activitys": ser_obj.data, "count": queryset.count()} | ||
353 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
354 | |||
355 | class TidingsShow(APIView): | ||
356 | def get(self,request): | ||
357 | id = request.GET.get('id') | ||
358 | try:user_id = get_user_info(request)['id'] | ||
359 | except:user_id=0 | ||
360 | tidings = models.UserHasTidings.objects.filter(id=id,deleted_at=None).first() | ||
361 | if not tidings: | ||
362 | return JsonResponse(ResponseFactory(code=200, message="内容已被删除", data=None, status='fail')) | ||
363 | data = serializers.CommunityTidingsSerializer(tidings,many=False,context={'user_id':user_id}).data | ||
364 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
365 | |||
366 | |||
367 | |||
368 | class TidingsChat(APIView): | ||
369 | @method_decorator(AuthPermissionRequired()) | ||
370 | def post(self,request): | ||
371 | """ | ||
372 | 记录动态私聊用户 | ||
373 | :param request: | ||
374 | :return: | ||
375 | """ | ||
376 | try: | ||
377 | post_data = json.loads(request.body) | ||
378 | except: | ||
379 | return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
380 | obj = verification.TidingsChatVerify(data=post_data) | ||
381 | if not obj.is_valid(): | ||
382 | return JsonResponse( | ||
383 | ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
384 | tidings_id = obj.data.get('tidings_id') | ||
385 | user_id = get_user_info(request)['id'] | ||
386 | models.TidingsHasChat.objects.update_or_create( | ||
387 | user_id=user_id, tidings_id=tidings_id, | ||
388 | defaults={ | ||
389 | "created_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
390 | "updated_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S")}, | ||
391 | ) | ||
392 | return JsonResponse(ResponseFactory(code=200, message="记录成功", data=None, status='success')) | ||
393 | |||
394 | |||
395 | |||
396 | class ChatRelation(APIView): | ||
397 | @method_decorator(AuthPermissionRequired()) | ||
398 | def get(self,request): | ||
399 | receiver_id = request.GET.get('id') | ||
400 | sender = get_user_info(request) | ||
401 | query = models.Users.objects.filter(id=receiver_id) | ||
402 | data = serializers.ChatRelationSerializer(query, many=False, context={"sender": sender,"receiver_id":receiver_id}).data | ||
403 | return JsonResponse(ResponseFactory(code=200, message="查询成功", data=data, status='success')) | ||
404 | |||
405 | |||
406 | class ChatAgent(APIView): | ||
407 | @method_decorator(AuthPermissionRequired()) | ||
408 | def get(self,request): | ||
409 | receiver_id = request.GET.get('id') | ||
410 | receiver = models.Users.objects.filter(id=receiver_id).first() | ||
411 | send_id = get_user_info(request)['id'] | ||
412 | if receiver: | ||
413 | data = serializers.ChatAgentSerializer(receiver,many=False,context={"send_id":send_id}).data | ||
414 | return JsonResponse(ResponseFactory(code=200, message="查询成功", data=data, status='success')) | ||
415 | else:return JsonResponse(ResponseFactory(code=400, message="不存在的用户", data=None, status='fail')) | ||
416 | |||
417 | class ChatAgentRecord(APIView): | ||
418 | @method_decorator(AuthPermissionRequired()) | ||
419 | def post(self,request): | ||
420 | """ | ||
421 | 记录代理私聊信息 | ||
422 | :param request: | ||
423 | :return: | ||
424 | """ | ||
425 | try:post_data = json.loads(request.body) | ||
426 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
427 | obj = verification.ChatAgentRecordVerify(data=post_data) | ||
428 | if not obj.is_valid(): | ||
429 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
430 | send_id = get_user_info(request)['id'] | ||
431 | user_id = obj.data.get('user_id') | ||
432 | business_id = models.Users.objects.filter(id=user_id).first().business_id | ||
433 | models.UserChatAgentRecords.objects.update_or_create( | ||
434 | user_id=user_id, send_id=send_id,business_id=business_id, | ||
435 | defaults={ | ||
436 | "created_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
437 | "updated_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S")}, | ||
438 | ) | ||
439 | return JsonResponse(ResponseFactory(code=200, message="记录成功", data=None, status='success')) | ||
440 | |||
441 | |||
442 | class Unlike(APIView): | ||
443 | @method_decorator(AuthPermissionRequired()) | ||
444 | def post(self,request): | ||
445 | """用户不感兴趣动态""" | ||
446 | try:post_data = json.loads(request.body) | ||
447 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
448 | obj = verification.UnlikeTidingsVerify(data=post_data) | ||
449 | if not obj.is_valid(): | ||
450 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
451 | tidings_id = obj.data.get('tidings_id') | ||
452 | user_id = get_user_info(request)['id'] | ||
453 | models.UserUnlikeTidings.objects.update_or_create( | ||
454 | user_id=user_id, tidings_id=tidings_id, | ||
455 | defaults={ | ||
456 | "created_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
457 | "updated_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S")}, | ||
458 | ) | ||
459 | return JsonResponse(ResponseFactory(code=200, message="记录成功", data=None, status='success')) | ||
460 | |||
461 | class TidingsComments(APIView): | ||
462 | def get(self,request): | ||
463 | """ | ||
464 | 动态评论列表 | ||
465 | :param request: | ||
466 | :return: | ||
467 | """ | ||
468 | id= request.GET.get('id') | ||
469 | orderbyList = ['-created_at'] | ||
470 | queryset = models.TidingsHasComments.objects.filter(tidings_id=id,deleted_at=None).order_by(*orderbyList) | ||
471 | page_obj = PageNumberPagination() | ||
472 | page_data = page_obj.paginate_queryset(queryset, request) | ||
473 | ser_obj = serializers.TidingsHasCommentsSerializer(page_data, many=True) | ||
474 | data = {"comments": ser_obj.data, "count": queryset.count()} | ||
475 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
476 | |||
477 | @method_decorator(AuthPermissionRequired()) | ||
478 | def post(self,request): | ||
479 | """ | ||
480 | 发布评论 | ||
481 | :param request: | ||
482 | :return: | ||
483 | """ | ||
484 | try:post_data = json.loads(request.body) | ||
485 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
486 | obj = verification.PushTidingsCommentsVerify(data=post_data) | ||
487 | if not obj.is_valid(): | ||
488 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
489 | user = get_user_info(request) | ||
490 | user_id = user['id'] | ||
491 | tidings_id = obj.data.get('tidings_id') | ||
492 | parent_id = int(post_data.get('parent_id',0)) | ||
493 | content = obj.data.get('content') | ||
494 | is_senstive = senstive_word_check(content) | ||
495 | if is_senstive: | ||
496 | return JsonResponse(ResponseFactory(code=400, message='评论包含敏感词,请检查', data=None, status='fail')) | ||
497 | try: | ||
498 | with transaction.atomic(): | ||
499 | if parent_id: | ||
500 | title = '{}回复了您的评论'.format(user['nick_name']) | ||
501 | receivers_id = models.TidingsHasComments.objects.filter(id=parent_id).first().user_id | ||
502 | data = {"title":title , "content": content, 'receivers': [receivers_id], "activity_id": tidings_id,'sender_id': user_id, 'type': 12} | ||
503 | else: | ||
504 | title = '{}评论您的动态'.format(user['nick_name']) | ||
505 | receivers_id = models.UserHasTidings.objects.filter(id=tidings_id).first().user_id | ||
506 | data = {"title": title, "content": content, 'receivers': [receivers_id], "activity_id": tidings_id,'sender_id': user_id, 'type': 13} | ||
507 | #自己给自己恢复不发系统消息 | ||
508 | if user_id != receivers_id: | ||
509 | createMessage(data) | ||
510 | models.TidingsHasComments.objects.create( | ||
511 | user_id=user_id, | ||
512 | tidings_id=tidings_id, | ||
513 | parent_id = parent_id, | ||
514 | content = content, | ||
515 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
516 | updated_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
517 | ) | ||
518 | except Exception as e: | ||
519 | loggin.logger.info('评论失败:{}'.format(e)) | ||
520 | return JsonResponse(ResponseFactory(code=400, message='失败,请联系管理员', data=None, status='fail')) | ||
521 | return JsonResponse(ResponseFactory(code=200, message="记录成功", data=None, status='success')) | ||
522 | |||
523 | |||
524 | @method_decorator(AuthPermissionRequired()) | ||
525 | def put(self,request): | ||
526 | try:post_data = json.loads(request.body) | ||
527 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
528 | obj = verification.DeleCommentsVerify(data=post_data) | ||
529 | if not obj.is_valid(): | ||
530 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
531 | user = get_user_info(request) | ||
532 | comment_id = obj.data.get('comment_id') | ||
533 | comment = models.TidingsHasComments.objects.filter(id=comment_id).first() | ||
534 | author_id = comment.user_id | ||
535 | if not (user['id'] == author_id or user['scope'] == 1): | ||
536 | return JsonResponse(ResponseFactory(code=400, message='无此权限', data=None, status='fail')) | ||
537 | try: | ||
538 | with transaction.atomic(): | ||
539 | title = '您的评论被删除' | ||
540 | if user['id'] != author_id: | ||
541 | data = {"title": title, "content": comment.content, 'receivers': [author_id], "activity_id":comment.tidings_id ,'sender_id': user['id'], 'type': 14} | ||
542 | createMessage(data) | ||
543 | models.TidingsHasComments.objects.filter(id=comment_id).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
544 | return JsonResponse(ResponseFactory(code=200, message="删除成功", data=None, status='success')) | ||
545 | except Exception as e: | ||
546 | return JsonResponse(ResponseFactory(code=400, message='失败,请联系管理员{}'.format(e), data=None, status='fail')) | ||
547 | |||
548 |
api/ApiList/index.py
0 → 100644
1 | import json | ||
2 | from django.http import JsonResponse | ||
3 | from api import models | ||
4 | from api.views import AuthPermissionRequired,get_user_info | ||
5 | from django.utils import timezone | ||
6 | from django.db import transaction | ||
7 | from api import serializers | ||
8 | from api.views import ResponseFactory,PageNumberPagination,GetWxToken,pushSubscribeMessage,WeChatApi,createMessage,user_point_record,JPush | ||
9 | from rest_framework.views import APIView | ||
10 | from django.utils.decorators import method_decorator | ||
11 | from api import verification | ||
12 | from api.loggin import logger | ||
13 | from django.shortcuts import render | ||
14 | from django.db.models import Q | ||
15 | from HisinApi import settings | ||
16 | import requests | ||
17 | |||
18 | |||
19 | def useragreement(request): | ||
20 | return render(request, 'user_agreement.html') | ||
21 | |||
22 | def appshare(request): | ||
23 | return render(request, 'appshare.html') | ||
24 | |||
25 | def songshare(request,id): | ||
26 | activity = models.Activitys.objects.filter(id=id).first() | ||
27 | data = {"song_name": activity.song_name,"cover":activity.cover,"clip_lyric":activity.clip_lyric,"guide_clip":activity.guide_clip} | ||
28 | return render(request,'share.html',{"data":json.dumps(data)}) | ||
29 | |||
30 | def tidingsshare(request,id): | ||
31 | tidings = models.UserHasTidings.objects.filter(id=id).first() | ||
32 | data = {} | ||
33 | return render(request,'tidingsShare.html',{"data":json.dumps(data)}) | ||
34 | |||
35 | def index(request): | ||
36 | return render(request, 'index.html') | ||
37 | |||
38 | @AuthPermissionRequired() | ||
39 | def user(request): | ||
40 | if request.method == 'GET': | ||
41 | #转发接口 | ||
42 | url = "{domain}/app/auth".format(domain=settings.SERVICE_DOMAOIN) | ||
43 | headers = { | ||
44 | 'Content-Type': 'application/json', | ||
45 | 'Authorization': request.META.get('HTTP_AUTHORIZATION') | ||
46 | } | ||
47 | resp = requests.request("GET", url, headers=headers,verify=False) | ||
48 | return JsonResponse(ResponseFactory(code=resp.json()['code'], message=resp.json()['message'], data=resp.json()['data'], | ||
49 | status=resp.json()['status'])) | ||
50 | # | ||
51 | # user = get_user_info(request) | ||
52 | # user_id = user['id'] | ||
53 | # #获取正在进行的活动id | ||
54 | # activity_ids = list(models.Activitys.objects.filter(status=1,deleted_at=None).values_list('id',flat=True)) | ||
55 | # # # 获取所有活动id | ||
56 | # all_activity_ids = list(models.Activitys.objects.filter(deleted_at=None).values_list('id', flat=True)) | ||
57 | # userData = serializers.UsersSerializer(models.Users.objects.get(id=user_id),many=False,context={"activity_ids":activity_ids,"all_activity_ids":all_activity_ids}).data | ||
58 | # return JsonResponse(ResponseFactory(code=200, message="获取成功", data=userData, status='success')) | ||
59 | else: | ||
60 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
61 | |||
62 | class Examines(APIView): | ||
63 | @method_decorator(AuthPermissionRequired()) | ||
64 | def get(self,request): | ||
65 | userData = get_user_info(request) | ||
66 | if userData['scope'] == 1: | ||
67 | user_ids = list(models.Users.objects.filter(audit_status=0,deleted_at=None).values_list('id',flat=True)) | ||
68 | queset = models.UserExamines.objects.filter(user_id__in=user_ids,status=0,deleted_at=None).order_by('-created_at') | ||
69 | page_obj = PageNumberPagination() | ||
70 | page_data = page_obj.paginate_queryset(queset, request) | ||
71 | serializer = serializers.UserExaminesSerializer(page_data, many=True) | ||
72 | data = {"data":serializer.data,"count":queset.count()} | ||
73 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data= data, status='success')) | ||
74 | else: | ||
75 | return JsonResponse(ResponseFactory(code=201, message="用户不是管理员身份", data=None, status='fail')) | ||
76 | |||
77 | class GetActivitys(APIView): | ||
78 | """ | ||
79 | 首页活动推荐: | ||
80 | 1.根据用户标签推送 | ||
81 | 2.无标签用户根据创建时间倒序 | ||
82 | 3.增加活动名搜索 | ||
83 | """ | ||
84 | def get(self, request): | ||
85 | try:tag_ids = eval(request.GET.get('tag_id')) | ||
86 | except :tag_ids = [] | ||
87 | text = request.GET.get('text','') | ||
88 | orderbyList = ['-weight','-created_at'] | ||
89 | try:user_id = get_user_info(request)['id'] | ||
90 | except:user_id = 0 | ||
91 | if len(tag_ids) > 0 and not text: | ||
92 | activitys_ids = models.ActivityHasTags.objects.filter(tag_id__in=tag_ids,deleted_at=None).values_list('activity_id',flat=True) | ||
93 | queryset = models.Activitys.objects.filter(status=1,audit_status=1,song_name__icontains=text,id__in=activitys_ids,deleted_at=None).order_by(*orderbyList) | ||
94 | else: | ||
95 | #活动名查询 | ||
96 | activitys_ids1 = list(models.Activitys.objects.filter(status=1,audit_status=1,song_name__icontains=text,deleted_at=None).order_by(*orderbyList).values_list('id',flat=True)) | ||
97 | # 项目名关联活动查询 | ||
98 | project_ids = list(models.Projects.objects.filter(status=1, name__icontains=text, deleted_at=None).values_list('id',flat=True)) | ||
99 | activitys_ids2 = list(models.Activitys.objects.filter(status=1, audit_status=1,project_id__in=project_ids, deleted_at=None).order_by(*orderbyList).values_list('id',flat=True)) | ||
100 | #去重 | ||
101 | activitys_ids3 = activitys_ids1 + activitys_ids2 | ||
102 | activitys_ids = list(set(activitys_ids3)) | ||
103 | activitys_ids.sort(key=activitys_ids3.index) | ||
104 | activity_id_str = ",".join('%s' % id for id in activitys_ids) | ||
105 | queryset = models.Activitys.objects.filter(status=1,audit_status=1,id__in=activitys_ids,deleted_at=None).extra(select={'m':'FIELD(id,{})'.format(activity_id_str)},order_by=['m']) | ||
106 | page_obj = PageNumberPagination() | ||
107 | page_data = page_obj.paginate_queryset(queryset, request) | ||
108 | ser_obj = serializers.ActivitysSerializer(page_data, many=True,context={"user_id":user_id}) | ||
109 | data = {"has_activitys":ser_obj.data,"count":len(queryset)} | ||
110 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
111 | |||
112 | class V2GetActivitys(APIView): | ||
113 | def get(self,request): | ||
114 | tag_ids = eval(request.GET['tag_id']) | ||
115 | text = request.GET.get('text', '') | ||
116 | orderbyList = ['-weight','-created_at'] | ||
117 | try:user_id = get_user_info(request)['id'] | ||
118 | except:user_id = 0 | ||
119 | if len(tag_ids) > 0 and not text: #搜索text搜索全局,不考虑tag_ids限制,活动是推荐活动is_recommend=1 | ||
120 | activitys_ids1 = list(models.ActivityHasTags.objects.filter(tag_id__in=tag_ids, activity__is_recommend=1,deleted_at=None).values_list('activity_id', flat=True)) | ||
121 | # 去掉不喜欢标签和已收藏的 | ||
122 | collection_activitys_ids = list(models.UserActivityCollections.objects.filter(user_id=user_id, deleted_at=None).values_list('activity_id', flat=True)) | ||
123 | unlike_activitys_ids = list(models.UserActivityUnlikes.objects.filter(user_id=user_id, deleted_at=None).values_list('activity_id',flat=True)) | ||
124 | delete_list = collection_activitys_ids + unlike_activitys_ids | ||
125 | activitys_ids = [x for x in activitys_ids1 if x not in delete_list] | ||
126 | else: | ||
127 | #活动名查询 | ||
128 | activitys_ids1 = list(models.Activitys.objects.filter(status=1,audit_status=1,song_name__icontains=text,deleted_at=None).order_by(*orderbyList).values_list('id',flat=True)) | ||
129 | # 项目名关联活动查询 | ||
130 | project_ids = list(models.Projects.objects.filter(status=1, name__icontains=text, deleted_at=None).values_list('id',flat=True)) | ||
131 | activitys_ids2 = list(models.Activitys.objects.filter(status=1, audit_status=1,project_id__in=project_ids, deleted_at=None).order_by(*orderbyList).values_list('id',flat=True)) | ||
132 | #去重 | ||
133 | activitys_ids3 = activitys_ids1 + activitys_ids2 | ||
134 | activitys_ids = list(set(activitys_ids3)) | ||
135 | activitys_ids.sort(key=activitys_ids3.index) | ||
136 | if len(activitys_ids) == 0 : | ||
137 | data = {"has_activitys": [], "count": 0} | ||
138 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
139 | idList = ",".join('%s' % id for id in activitys_ids) | ||
140 | sql = """ | ||
141 | select | ||
142 | activitys.id,activitys.song_name,activitys.project_id,activitys.sub_title,activitys.created_at, | ||
143 | IF(uva.id IS NULL,0,1) AS `is_listen`, | ||
144 | IF(ahu.id IS NULL,0,1) AS `is_submit`, | ||
145 | IF(uac.id IS NULL,0,1) AS `is_collection`, | ||
146 | IF(ahu.`status`=1,1,0) AS `is_take`, | ||
147 | (select count(*) from user_view_activitys where user_view_activitys.activity_id = activitys.id ) as view_count, | ||
148 | (select count(*) from activity_has_users where activity_has_users.activity_id = activitys.id and activity_has_users.type='Submit' AND activity_has_users.deleted_at is NULL ) as attend_count | ||
149 | from `activitys` | ||
150 | left join `user_activity_collections` as uac on `uac`.`activity_id` = `activitys`.`id` and `uac`.user_id={user_id} and `uac`.deleted_at is NULL | ||
151 | left join `user_view_activitys` as uva on `uva`.`activity_id` = `activitys`.`id` and `uva`.user_id={user_id} | ||
152 | left join `activity_has_users` as ahu on `ahu`.`activity_id` = `activitys`.`id` and `ahu`.user_id={user_id} and `ahu`.`type`='Submit' and `ahu`.deleted_at is NULL | ||
153 | where activitys.id IN ({activitys_id}) AND activitys.`status`=1 AND audit_status=1 AND activitys.deleted_at is NULL GROUP BY activitys.id order by is_listen asc,is_submit asc,is_collection asc,activitys.weight desc,activitys.created_at desc | ||
154 | """.format(activitys_id = idList, user_id=user_id) | ||
155 | queryset = models.Activitys.objects.raw(sql) | ||
156 | page_obj = PageNumberPagination() | ||
157 | page_data = page_obj.paginate_queryset(queryset, request) | ||
158 | ser_obj = serializers.V2ActivitysSerializer(page_data, many=True, context={"user_id": user_id}) | ||
159 | data = {"has_activitys": ser_obj.data, "count":len(queryset)} | ||
160 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
161 | |||
162 | class V3GetActivitys(APIView): | ||
163 | def get(self,request): | ||
164 | tag_ids = eval(request.GET['tag_id']) | ||
165 | text = request.GET.get('text', '') | ||
166 | orderbyList = ['-weight','-created_at'] | ||
167 | try:user_id = get_user_info(request)['id'] | ||
168 | except:user_id = 0 | ||
169 | if len(tag_ids) > 0 and not text: | ||
170 | #活动是推荐活动is_recommend=1 | ||
171 | activitys_ids1 = list(models.ActivityHasTags.objects.filter(tag_id__in=tag_ids,activity__is_recommend=1, deleted_at=None).values_list('activity_id', flat=True)) | ||
172 | # 去掉不喜欢标签和已收藏的 | ||
173 | unlike_activitys_ids = list(models.UserActivityUnlikes.objects.filter(user_id=user_id, deleted_at=None).values_list('activity_id',flat=True)) | ||
174 | activitys_ids = [x for x in activitys_ids1 if x not in unlike_activitys_ids] | ||
175 | else: | ||
176 | # 活动名查询 | ||
177 | activitys_ids1 = list(models.Activitys.objects.filter(status=1, audit_status=1, song_name__icontains=text,deleted_at=None).order_by(*orderbyList).values_list('id', flat=True)) | ||
178 | # 项目名关联活动查询 | ||
179 | project_ids = list(models.Projects.objects.filter(status=1, name__icontains=text, deleted_at=None).values_list('id',flat=True)) | ||
180 | activitys_ids2 = list(models.Activitys.objects.filter(status=1, audit_status=1, project_id__in=project_ids,deleted_at=None).order_by(*orderbyList).values_list('id', flat=True)) | ||
181 | # 去重 | ||
182 | activitys_ids3 = activitys_ids1 + activitys_ids2 | ||
183 | activitys_ids = list(set(activitys_ids3)) | ||
184 | activitys_ids.sort(key=activitys_ids3.index) | ||
185 | if len(activitys_ids) == 0 : | ||
186 | data = {"has_activitys": [], "count": 0} | ||
187 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
188 | idList = ",".join('%s' % id for id in activitys_ids) | ||
189 | sql = """ | ||
190 | select | ||
191 | activitys.id,activitys.song_name,activitys.project_id,activitys.sub_title,activitys.created_at, | ||
192 | IF(uva.id IS NULL,0,1) AS `is_listen`, | ||
193 | IF(ahu.id IS NULL,0,1) AS `is_submit`, | ||
194 | IF(uac.id IS NULL,0,1) AS `is_collection`, | ||
195 | IF(ahu.`status`=1,1,0) AS `is_take`, | ||
196 | (select count(*) from user_view_activitys where user_view_activitys.activity_id = activitys.id ) as view_count, | ||
197 | (select count(*) from activity_has_users where activity_has_users.activity_id = activitys.id and activity_has_users.type='Submit' AND activity_has_users.deleted_at is NULL ) as attend_count | ||
198 | from `activitys` | ||
199 | left join `user_activity_collections` as uac on `uac`.`activity_id` = `activitys`.`id` and `uac`.user_id={user_id} and `uac`.deleted_at is NULL | ||
200 | left join `user_view_activitys` as uva on `uva`.`activity_id` = `activitys`.`id` and `uva`.user_id={user_id} | ||
201 | left join `activity_has_users` as ahu on `ahu`.`activity_id` = `activitys`.`id` and `ahu`.user_id={user_id} and `ahu`.`type`='Submit' and `ahu`.deleted_at is NULL | ||
202 | where activitys.id IN ({activitys_id}) AND activitys.`status`=1 AND audit_status=1 AND activitys.deleted_at is NULL GROUP BY activitys.id order by is_listen asc,is_submit asc,is_collection asc,activitys.weight desc,activitys.created_at desc | ||
203 | """.format(activitys_id = idList, user_id=user_id) | ||
204 | queryset = models.Activitys.objects.raw(sql) | ||
205 | page_obj = PageNumberPagination() | ||
206 | page_data = page_obj.paginate_queryset(queryset, request) | ||
207 | ser_obj = serializers.V2ActivitysSerializer(page_data, many=True, context={"user_id": user_id}) | ||
208 | data = {"has_activitys": ser_obj.data, "count":len(queryset)} | ||
209 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
210 | |||
211 | |||
212 | class GetActivityUser(APIView): | ||
213 | """ | ||
214 | 获取参加活动所有用户 | ||
215 | """ | ||
216 | def get(self,request): | ||
217 | activity_id = request.GET['activity_id'] | ||
218 | queryset = models.ActivityHasUsers.objects.filter(activity_id=activity_id,deleted_at=None).values('user_id').distinct() | ||
219 | page_obj = PageNumberPagination() | ||
220 | page_data = page_obj.paginate_queryset(queryset, request) | ||
221 | ids = [] | ||
222 | for user in page_data: | ||
223 | ids.append(user['user_id']) | ||
224 | data = serializers.UserListSerializer (models.Users.objects.in_bulk(ids).values(),many=True).data | ||
225 | data = {'data':data,'count':queryset.count()} | ||
226 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
227 | |||
228 | class examineStatus(APIView): | ||
229 | """ | ||
230 | 2种身份,2种审核状态,判断是否已审核 | ||
231 | 歌手审核: | ||
232 | 1.通过:查看关联商务已关联人数,不满10人则通过,修改审核表状态,用户表状态且用户表关联商务 | ||
233 | 2.拒绝:直接改变审核表审核状态,用户表状态且用户表 | ||
234 | 商务审核: | ||
235 | 1.通过:修改审核表状态,用户表状态 | ||
236 | 2.拒绝:直接改变审核表审核状态,用户表状态且用户表 | ||
237 | :param requests: | ||
238 | :return: | ||
239 | """ | ||
240 | @method_decorator(AuthPermissionRequired()) | ||
241 | def put(self,request): | ||
242 | put_data = json.loads(request.body) | ||
243 | logger.info(put_data) | ||
244 | obj = verification.examine_verification(put_data) | ||
245 | if not obj.is_valid(): | ||
246 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
247 | obj = obj.clean() | ||
248 | examine_id = obj.get('examine_id') | ||
249 | examine_status = obj.get('examine_status') | ||
250 | examine_info = put_data.get('examine_info','') #非必传 | ||
251 | business_id = put_data.get('business_id',0) #非必传 | ||
252 | |||
253 | #判断是否已审核 | ||
254 | is_examines = models.Users.objects.filter(id = examine_id,audit_status=1,deleted_at=None) | ||
255 | if is_examines: | ||
256 | return JsonResponse(ResponseFactory(code=201, message="用户已被审核通过,请勿重复审核", data=None, status='fail')) | ||
257 | # 获取管理员身份 | ||
258 | userData = get_user_info(request) | ||
259 | # 获取被审核人身份 | ||
260 | examine_user = models.Users.objects.filter(id=examine_id, deleted_at=None).first() | ||
261 | if not examine_user: | ||
262 | return JsonResponse(ResponseFactory(code=201, message="不存在的用户,无法审核", data=None, status='fail')) | ||
263 | #获取审核表对象 | ||
264 | examine_item = models.UserExamines.objects.filter(user_id=examine_id, status=0, deleted_at=None).order_by('-created_at').first() | ||
265 | open_id = examine_item.open_id | ||
266 | if examine_status == 2: | ||
267 | models.UserExamines.objects.filter(user_id=examine_id, status=0, deleted_at=None).update( | ||
268 | admin_id = userData.get('id'), | ||
269 | examine_info = examine_info, | ||
270 | status = examine_status, | ||
271 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
272 | ) | ||
273 | models.Users.objects.filter(id=examine_id, deleted_at=None).update(audit_status=examine_status,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
274 | elif examine_status == 1: | ||
275 | #判断是歌手还是商务 | ||
276 | if examine_user.role == "Singer" and business_id : | ||
277 | business_has_singer = models.Users.objects.filter(business_id=business_id,status=1,audit_status=1,deleted_at=None).count() | ||
278 | if business_has_singer >= 999: | ||
279 | return JsonResponse(ResponseFactory(code=201, message="该商务已关联超过999人", data=None, status='fail')) | ||
280 | try: | ||
281 | with transaction.atomic(): | ||
282 | # # 修改审核信息 | ||
283 | models.UserExamines.objects.filter(user_id=examine_id, status=0, deleted_at=None).update(admin_id=userData.get('id'),examine_info=examine_info,status=examine_status,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
284 | models.Users.objects.filter(id=examine_id,deleted_at=None).update(audit_status=examine_status,business_id=business_id,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
285 | # 消息计数 | ||
286 | m_data = {'receivers':[business_id],'sender_id':examine_id,'type':1,'is_bind':1} | ||
287 | createMessage(m_data) | ||
288 | # 推送消息给推荐人 | ||
289 | business_unionid = models.Users.objects.filter(id=business_id).first().unionid | ||
290 | business_wechat_official = models.WechatOfficialUsers.objects.filter(union_id=business_unionid,is_subscribe=1).last() | ||
291 | if business_wechat_official: | ||
292 | business_open_id = business_wechat_official.open_id | ||
293 | name = examine_item.user_info['nick_name']+"({})".format(examine_item.user_info['real_name']) | ||
294 | data = {'channel': 'singer_related', 'open_id': [business_open_id], | ||
295 | 'data': {"title":"您有新的歌手入驻平台成功","name":name,"intro":"通过【海星试唱】平台审核","remark":"欢迎{}入驻平台,快去为ta挑选合适的歌曲吧~".format(name),"page":"packageMy/pages/like?tab=0"}} | ||
296 | pushSubscribeMessage(data) | ||
297 | #极光推送-绑定歌手 | ||
298 | j_title = "您有歌手入驻平台" | ||
299 | j_content = "您的歌手{}已入驻平台,快去为ta挑歌吧~".format(examine_item.user_info['nick_name']) | ||
300 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
301 | "receiver_value": [business_id], "extras": {"type": "ToMySinger", "value": ""}} | ||
302 | JPush().jpush_v3(jdata) | ||
303 | #绑定歌手成功,推荐人积分 | ||
304 | user_point_record(user_id=business_id, singer_id=examine_id,type='BindSinger') | ||
305 | except Exception as e: | ||
306 | return JsonResponse(ResponseFactory(code=201, message="审核失败。请联系管理员", data=None, status='fail')) | ||
307 | else: | ||
308 | try: | ||
309 | with transaction.atomic(): | ||
310 | # 修改审核信息 | ||
311 | models.UserExamines.objects.filter(user_id=examine_id, status=0, deleted_at=None).update(admin_id=userData.get('id'),examine_info=examine_info,status=examine_status,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
312 | models.Users.objects.filter(id=examine_id, deleted_at=None).update(audit_status=examine_status,business_id=None,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
313 | except Exception as e: | ||
314 | return JsonResponse(ResponseFactory(code=201, message="审核失败。请联系管理员", data=None, status='fail')) | ||
315 | # #推送审核消息通知用户 | ||
316 | if open_id: | ||
317 | result = "通过" if examine_status == 1 else "拒绝" | ||
318 | if examine_info == "": | ||
319 | examine_info = "审核通过,快去寻找适合你的Demo吧!" | ||
320 | data = {'channel':'register_audit','open_id':[open_id] , 'data': { "nick_name": examine_user.nick_name, "status": result,"msg": examine_info}} | ||
321 | pushSubscribeMessage(data) | ||
322 | #极光推送-歌手审核 | ||
323 | j_title = "注册申请已通过" if examine_status == 1 else "注册申请未通过" | ||
324 | j_content = "点击前往海星试唱挑选歌曲" if examine_status == 1 else "点击查看详情" | ||
325 | j_type = "OpenSelectTag" if examine_status == 1 else "OpenApp" | ||
326 | jdata = {"title": j_title, "content": j_content, "content_type": "text", "receiver_value": [examine_id],"extras": {"type": j_type, "value": ""}} | ||
327 | JPush().jpush_v3(jdata) | ||
328 | return JsonResponse(ResponseFactory(code=200, message="审核完成", data=None, status='success')) | ||
329 | |||
330 | |||
331 | |||
332 | def banners(request): | ||
333 | if request.method == 'GET': | ||
334 | user = dict() | ||
335 | try: | ||
336 | user = get_user_info(request) | ||
337 | # 记录用户审核完成访问小程序 | ||
338 | is_record = models.Actions.objects.filter(event_name='audited_visit',user_id=user.get('id')).exists() | ||
339 | if not is_record: | ||
340 | models.Actions.objects.create(event_name='audited_visit', | ||
341 | user_id=user['id'], | ||
342 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
343 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
344 | except Exception as e: | ||
345 | user['role'] = 'Visitor' #游客 | ||
346 | # sql = """ SELECT * FROM banners where type=1 and status=1 and | ||
347 | # deleted_at is null and json_contains(banners.role,CONCAT('"',"{}",'"')) | ||
348 | # and json_contains(banners.scope,JSON_Array({})) | ||
349 | # ORDER BY `weight` DESC,`created_at` DESC """.format(user['role'],user['scope']) | ||
350 | |||
351 | sql = """ SELECT * FROM banners where scope=1 and status=1 and | ||
352 | deleted_at is null and json_contains(banners.role,CONCAT('"',"{}",'"')) | ||
353 | ORDER BY `weight` DESC,`created_at` DESC """.format(user['role']) | ||
354 | |||
355 | queset = models.Banners.objects.raw(sql) | ||
356 | ser = serializers.BanneraSerializer(queset,many=True) | ||
357 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=ser.data, status='success')) | ||
358 | else: | ||
359 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
360 | |||
361 | |||
362 | |||
363 | def v2banners(request): | ||
364 | if request.method == 'GET': | ||
365 | scope = request.GET.get('type',1) | ||
366 | try: | ||
367 | user = get_user_info(request) | ||
368 | # 记录用户审核完成访问小程序 | ||
369 | is_record = models.Actions.objects.filter(event_name='audited_visit',user_id=user.get('id')).exists() | ||
370 | if not is_record: | ||
371 | models.Actions.objects.create(event_name='audited_visit', | ||
372 | user_id=user['id'], | ||
373 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
374 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
375 | roleDict = {"0": ["Visitor"], "1": ["Singer"], "2": ["Business"], | ||
376 | "3": ["Singer","Business"]} | ||
377 | scopeDict = {"1":["System"],"2":["Project"]} | ||
378 | my_list = roleDict[str(user['identity'])] | ||
379 | if user['scope']: | ||
380 | my_list = my_list + scopeDict[str(user['scope'])] | ||
381 | except Exception as e: | ||
382 | my_list = ["UnLogin"]#游客 | ||
383 | query = Q() | ||
384 | for value in my_list: | ||
385 | query |= Q(role__contains=[value]) | ||
386 | queset = models.Banners.objects.filter(query,scope=scope,status=1,deleted_at=None).order_by(*['-weight','-created_at']) | ||
387 | ser = serializers.BanneraSerializer(queset,many=True,fields=['id','name','cover','content_picture','type']) | ||
388 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=ser.data, status='success')) | ||
389 | else: | ||
390 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
391 | |||
392 | def bannerDetail(request): | ||
393 | if request.method != 'GET': | ||
394 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
395 | id = request.GET.get('id') | ||
396 | queryset = models.Banners.objects.filter(id=id).first() | ||
397 | data =serializers.BanneraSerializer(queryset,many=False,fields=['id','name','cover','type','content']).data | ||
398 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
399 | |||
400 | |||
401 | @AuthPermissionRequired() | ||
402 | def UserViewActivity(request): | ||
403 | if request.method == 'POST': | ||
404 | obj = verification.view_activity_verification(json.loads(request.body)) | ||
405 | if obj.is_valid(): | ||
406 | data = obj.clean() | ||
407 | user_id = get_user_info(request)['id'] | ||
408 | item = models.UserViewActivity.objects.filter(user_id=user_id,activity_id=data.get('activity_id')) | ||
409 | if not item: | ||
410 | models.UserViewActivity.objects.create( | ||
411 | user_id=user_id, | ||
412 | activity_id=data.get('activity_id'), | ||
413 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
414 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
415 | ) | ||
416 | else: | ||
417 | item.update( | ||
418 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
419 | ) | ||
420 | return JsonResponse(ResponseFactory(code=200, message='记录成功', data=None, status='success')) | ||
421 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
422 | else: | ||
423 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
424 | |||
425 | |||
426 | |||
427 | class Unlike(APIView): | ||
428 | @method_decorator(AuthPermissionRequired()) | ||
429 | def get(self,request): | ||
430 | user_id = get_user_info(request)['id'] | ||
431 | ids = list(models.UserActivityUnlikes.objects.filter(user_id=user_id,deleted_at=None).order_by('-created_at').values_list('activity_id',flat=True)) | ||
432 | if ids != []: | ||
433 | idList = ",".join('%s' %id for id in ids) | ||
434 | sql = """select * from activitys where id in ({}) order by field(id,{})""".format(idList,idList) | ||
435 | queryset = models.Activitys.objects.raw(sql) | ||
436 | page_obj = PageNumberPagination() | ||
437 | page_data = page_obj.paginate_queryset(queryset, request) | ||
438 | ser_obj = serializers.ActivitysSerializer(page_data, many=True, context={"user_id": user_id}) | ||
439 | data = {"activitys": ser_obj.data, "count": len(ids)} | ||
440 | else: | ||
441 | data = {"activitys": [], "count": len(ids)} | ||
442 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
443 | |||
444 | @method_decorator(AuthPermissionRequired()) | ||
445 | def post(self,request): | ||
446 | obj = verification.user_activity_unlike(json.loads(request.body)) | ||
447 | if obj.is_valid(): | ||
448 | data = json.loads(request.body) | ||
449 | user = get_user_info(request) | ||
450 | models.UserActivityUnlikes.objects.create( | ||
451 | user_id=user['id'], | ||
452 | activity_id=data['activity_id'], | ||
453 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
454 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
455 | ) | ||
456 | return JsonResponse(ResponseFactory(code=200, message="设置完成", data=None, status='success')) | ||
457 | else: | ||
458 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
459 | |||
460 | |||
461 | class GetCompleteActivity(APIView): | ||
462 | """ | ||
463 | 获取确认歌手的活动 | ||
464 | """ | ||
465 | def get(self,request): | ||
466 | queryset = models.Activitys.objects.filter(status=3,deleted_at=None).order_by('-updated_at') | ||
467 | page_obj = PageNumberPagination() | ||
468 | page_data = page_obj.paginate_queryset(queryset, request) | ||
469 | ser_data = serializers.CompleteActivity(page_data,many=True) | ||
470 | data = {'data':ser_data.data,'count':queryset.count()} | ||
471 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
472 | |||
473 | def Events(request): | ||
474 | if request.method == 'GET': | ||
475 | data = serializers.Events(models.Events.objects.all(),many=True).data | ||
476 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
477 | else: | ||
478 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
479 | |||
480 | def Action(request): | ||
481 | if request.method == 'POST': | ||
482 | postdata = json.loads(request.body) | ||
483 | try:user_id = get_user_info(request)['id'] | ||
484 | except:user_id=0 | ||
485 | vx_code = postdata.get('vx_code','') | ||
486 | if vx_code:open_id, unionid = WeChatApi(vx_code) | ||
487 | else:open_id = '' | ||
488 | now = timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
489 | models.Actions.objects.create( | ||
490 | event_name = postdata.get('event_name',''), | ||
491 | open_id = open_id, | ||
492 | user_id=user_id, | ||
493 | activity_id=postdata.get('activity_id', 0), | ||
494 | start_at=postdata.get('start_at', None), | ||
495 | end_at=postdata.get('end_at', None), | ||
496 | created_at=now, | ||
497 | updated_at=now | ||
498 | ) | ||
499 | return JsonResponse(ResponseFactory(code=200, message="记录成功", data='', status='success')) | ||
500 | else: | ||
501 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
502 | |||
503 | |||
504 | class BandList(APIView): | ||
505 | def get(self,request): | ||
506 | """厂牌列表:厂牌发布过试唱""" | ||
507 | is_recommend = int(request.GET.get('is_recommend',0)) | ||
508 | project_id = models.Activitys.objects.filter(deleted_at=None,audit_status=1).values_list('project_id',flat=True) | ||
509 | if is_recommend: | ||
510 | orderbyList = ['-r_weight', '-created_at'] | ||
511 | kwargs = {"status":1,"r_status":1,"deleted_at":None} | ||
512 | else: | ||
513 | orderbyList = ['-r_status','-r_weight','-weight', '-created_at'] | ||
514 | kwargs = {"status":1,"deleted_at":None} | ||
515 | kwargs['id__in'] = project_id | ||
516 | queryset = models.Projects.objects.filter(**kwargs).order_by(*orderbyList) | ||
517 | page_obj = PageNumberPagination() | ||
518 | page_data = page_obj.paginate_queryset(queryset, request) | ||
519 | ser_data = serializers.ProjectsSerializer(page_data, many=True) | ||
520 | data = {'data': ser_data.data, 'count': queryset.count()} | ||
521 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
522 | |||
523 | |||
524 | class BandDetail(APIView): | ||
525 | @method_decorator(AuthPermissionRequired()) | ||
526 | def get(self,request): | ||
527 | """厂牌详情""" | ||
528 | id = int(request.GET.get('id')) | ||
529 | user_id = get_user_info(request)['id'] | ||
530 | queryset = models.Projects.objects.filter(id=id,status=1,deleted_at=None).first() | ||
531 | if not queryset: | ||
532 | return JsonResponse(ResponseFactory(code=400, message="厂牌已被禁用或删除", data=None, status='fail')) | ||
533 | projects = serializers.ProjectsSerializer(queryset, many=False) | ||
534 | #记录访问信息 | ||
535 | models.ProjectVisitors.objects.create(project_id=id,user_id=user_id, created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
536 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=projects.data, status='success')) | ||
537 | |||
538 | class BandLinkActivity(APIView): | ||
539 | @method_decorator(AuthPermissionRequired()) | ||
540 | def get(self,request): | ||
541 | """厂牌关联活动""" | ||
542 | try:user_id = get_user_info(request)['id'] | ||
543 | except:user_id = 0 | ||
544 | id = int(request.GET.get('id')) | ||
545 | activityid_list = [] | ||
546 | kwargs = {"project_id":id,"audit_status":1,"status":1,"song_type":1,"deleted_at":None} | ||
547 | activity_ids = models.Activitys.objects.filter(**kwargs).values_list('id',flat=True) | ||
548 | #去掉不喜欢的标签 | ||
549 | unlike_activitys_ids = list(models.UserActivityUnlikes.objects.filter(user_id=user_id, deleted_at=None).values_list('activity_id',flat=True)) | ||
550 | for m in activity_ids: | ||
551 | if m not in unlike_activitys_ids: | ||
552 | activityid_list.append(m) | ||
553 | if len(activityid_list) == 0: | ||
554 | data = {"data": None, "count": 0} | ||
555 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
556 | idList = ",".join('%s' % id for id in activityid_list) | ||
557 | sql = """ | ||
558 | select | ||
559 | activitys.id,activitys.song_name,activitys.project_id,activitys.sub_title,activitys.created_at, | ||
560 | IF(uva.id IS NULL,0,1) AS `is_listen`, | ||
561 | IF(ahu.id IS NULL,0,1) AS `is_submit`, | ||
562 | IF(uac.id IS NULL,0,1) AS `is_collection`, | ||
563 | IF(ahu.`status`=1,1,0) AS `is_take`, | ||
564 | (select count(*) from user_view_activitys where user_view_activitys.activity_id = activitys.id ) as view_count, | ||
565 | (select count(*) from activity_has_users where activity_has_users.activity_id = activitys.id and activity_has_users.type='Submit' AND activity_has_users.deleted_at is NULL ) as attend_count | ||
566 | from `activitys` | ||
567 | left join `user_activity_collections` as uac on `uac`.`activity_id` = `activitys`.`id` and `uac`.user_id={user_id} and `uac`.deleted_at is NULL | ||
568 | left join `user_view_activitys` as uva on `uva`.`activity_id` = `activitys`.`id` and `uva`.user_id={user_id} | ||
569 | left join `activity_has_users` as ahu on `ahu`.`activity_id` = `activitys`.`id` and `ahu`.user_id={user_id} and `ahu`.`type`='Submit' and `ahu`.deleted_at is NULL | ||
570 | where activitys.id IN ({activitys_id}) AND activitys.`status`=1 AND audit_status=1 AND activitys.deleted_at is NULL GROUP BY activitys.id order by p_is_top desc,is_listen asc,activitys.weight desc,activitys.created_at desc | ||
571 | """.format(activitys_id=idList, user_id=user_id) | ||
572 | queryset = models.Activitys.objects.raw(sql) | ||
573 | page_obj = PageNumberPagination() | ||
574 | page_data = page_obj.paginate_queryset(queryset, request) | ||
575 | activitys = serializers.BandActivitySerializer(page_data, many=True,context={"user_id":user_id,"project_many":True}, fields=['id','song_name','sub_title','lyric','sex','mark','speed','lang','guide','guide_duration','guide_clip','guide_clip_duration','karaoke','karaoke_clip','clip_lyric','cover','status','project_id','is_collection','status_tag','is_confirm_share','project','tags','is_promote','estimate_release_at','publish_at','guide_duration','guide_clip_duration','comfirm_time','total_song_count','online_song_count','public_audio_count','arranger','is_master','p_is_top']).data | ||
576 | # 活动配置信息 | ||
577 | config_ids = list(models.SystemConfig.objects.filter(identifier__in=['activity_lang', 'activity_speed', 'activity_sex', 'activity_mark']).values_list('id',flat=True).all()) | ||
578 | configs = models.SystemConfig.objects.filter(parent_id__in=config_ids).values_list('identifier', 'name','content') | ||
579 | for activity in activitys: | ||
580 | lang = activity['lang'] if activity['lang'] else [] | ||
581 | langs =[] | ||
582 | for config in configs: | ||
583 | if config[0] == activity['sex']: | ||
584 | activity['sex'] = config[1] if activity['sex'] else None | ||
585 | if config[0] == activity['mark']: | ||
586 | activity['mark'] = config[2] if activity['mark'] else None | ||
587 | if config[0] == activity['speed']: | ||
588 | activity['speed'] = config[1] if activity['speed'] else None | ||
589 | if config[0] in lang: | ||
590 | langs.append(config[1]) | ||
591 | activity['lang'] = langs | ||
592 | data = {'data': activitys, "count":len(queryset)} | ||
593 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
594 | |||
595 | class RecommenCasedList(APIView): | ||
596 | def get(self,request): | ||
597 | is_recommend = int(request.GET.get('is_recommend', 0)) | ||
598 | if is_recommend: | ||
599 | kwargs = {"audit_status":1,"status": 5, "r_status": 1, "deleted_at": None} #已发行 | ||
600 | orderbyList = ['-r_weight', '-updated_at'] | ||
601 | else: | ||
602 | kwargs = {"audit_status": 1, "status__in": [3,5], "deleted_at": None} #已发行或确认合作 | ||
603 | orderbyList = ['-r_status', '-r_weight', '-updated_at'] | ||
604 | queryset = models.Activitys.objects.filter(**kwargs).order_by(*orderbyList) | ||
605 | page_obj = PageNumberPagination() | ||
606 | page_data = page_obj.paginate_queryset(queryset, request) | ||
607 | ser_data = serializers.RecommendActivitySerializer(page_data, many=True) | ||
608 | data = {'data': ser_data.data, 'count': queryset.count()} | ||
609 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/ApiList/login.py
0 → 100644
1 | # Create your views here | ||
2 | import json | ||
3 | from django.utils import timezone | ||
4 | from api import models | ||
5 | from aliyunsdkcore.client import AcsClient | ||
6 | from aliyunsdkcore.request import CommonRequest | ||
7 | from django.contrib.auth.hashers import make_password | ||
8 | from HisinApi import settings | ||
9 | from django.contrib.auth.backends import ModelBackend | ||
10 | from django.db.models import Q | ||
11 | from django.conf import settings | ||
12 | from django.http import JsonResponse | ||
13 | from django.contrib.auth import get_user_model | ||
14 | from django.core.cache import caches | ||
15 | import random | ||
16 | import re | ||
17 | from api.views import ResponseFactory,WeChatApi,pushSubscribeMessage,AppWechatApi,JPush | ||
18 | from django.db import transaction | ||
19 | from api.serializers import SystemBusinessSerializer,WeiXinAuthUser | ||
20 | from api import verification | ||
21 | from twilio.rest import Client | ||
22 | |||
23 | UserModel = get_user_model() | ||
24 | |||
25 | |||
26 | class CustomBackend(ModelBackend): | ||
27 | def authenticate(self,username=None, password=None, **kwargs): | ||
28 | """ | ||
29 | 登录校验逻辑,重写authenticate | ||
30 | """ | ||
31 | try: | ||
32 | user = models.Users.objects.filter(deleted_at=None).get(Q(phone=username)|Q(email=username)) | ||
33 | if user.status: | ||
34 | if user.check_password(password): | ||
35 | return user | ||
36 | else: | ||
37 | return None | ||
38 | return 'User.Disable' | ||
39 | except Exception as e: | ||
40 | return None | ||
41 | |||
42 | def v2authenticate(self,username=None, **kwargs): | ||
43 | """ | ||
44 | 登录校验逻辑,重写authenticate | ||
45 | """ | ||
46 | try: | ||
47 | user = models.Users.objects.filter(deleted_at=None).get(Q(phone=username)|Q(email=username)) | ||
48 | if user.status: | ||
49 | return user | ||
50 | return 'User.Disable' | ||
51 | except Exception as e: | ||
52 | return None | ||
53 | |||
54 | def cntw_sms_server(template,phone, area_code): | ||
55 | account_sid = 'AC556f91c359069fb23b608cb7852d98cf' | ||
56 | auth_token = '65ee1a4b53c4387b1b5049e83e37dabe' | ||
57 | client = Client(account_sid, auth_token) | ||
58 | message = client.messages.create( | ||
59 | messaging_service_sid='MG5c28f0230f888e02fe0ec47b0eea4c15', | ||
60 | body='[海星试唱] 验证码{}'.format(template['code']), | ||
61 | to='+{}{}'.format(area_code,phone) | ||
62 | ) | ||
63 | if message.status == 'accepted':response = b'{"Code":"OK"}' | ||
64 | else:response = b'{"Code":"fail"}' | ||
65 | return response | ||
66 | |||
67 | def send_sms(template, phone, area_code): | ||
68 | """ | ||
69 | 阿里云短信服务SDK | ||
70 | """ | ||
71 | client = AcsClient(settings.ALY_ACCESS_KEY_ID, settings.ALY_ACCESS_KEY_SECRET, 'default') | ||
72 | request = CommonRequest() | ||
73 | request.set_accept_format('json') | ||
74 | request.set_domain('dysmsapi.aliyuncs.com') | ||
75 | request.set_method('POST') | ||
76 | request.set_protocol_type('http') # https | http | ||
77 | request.set_version('2017-05-25') | ||
78 | request.set_action_name('SendSms') | ||
79 | request.add_query_param('RegionId', "default") | ||
80 | request.add_query_param('SignName', settings.ALY_SIGN_NAME) | ||
81 | if area_code == 86: | ||
82 | #国内 | ||
83 | request.add_query_param('TemplateCode', settings.ALY_REGISTER_TEMPLATE) | ||
84 | elif area_code == 886: | ||
85 | response = cntw_sms_server(template, phone, area_code) | ||
86 | return response | ||
87 | else: | ||
88 | # 国外 | ||
89 | phone = str(area_code) + str(phone) | ||
90 | request.add_query_param('TemplateCode', settings.ALY_REGISIER_TEMPLATE2) | ||
91 | request.add_query_param('PhoneNumbers', phone) | ||
92 | request.add_query_param('TemplateParam', template) | ||
93 | response = client.do_action_with_exception(request) | ||
94 | return response | ||
95 | |||
96 | |||
97 | def gen_mobile_code(length=6): | ||
98 | all_charts = '123456789' | ||
99 | return ''.join(random.choices(all_charts,k = length)) | ||
100 | |||
101 | def v2sendsms(request): | ||
102 | """ | ||
103 | 国际,国内 | ||
104 | :param request: | ||
105 | :return: | ||
106 | """ | ||
107 | if request.method == 'POST': | ||
108 | post_data = json.loads(request.body) | ||
109 | obj = verification.v2SendVerify(data=post_data) | ||
110 | if obj.is_valid(): | ||
111 | phone = obj.data.get('phone') | ||
112 | type = post_data.get('type','') | ||
113 | area_code = obj.data.get('area_code') | ||
114 | if type == 'login': | ||
115 | user = models.Users.objects.filter(phone=phone,deleted_at=None) | ||
116 | if not user: | ||
117 | return JsonResponse(ResponseFactory(code=201, message="用户不存在,请先注册", data=None, status='fail')) | ||
118 | if type == 'register': | ||
119 | user = models.Users.objects.filter(phone=phone,deleted_at=None) | ||
120 | if user: | ||
121 | return JsonResponse(ResponseFactory(code=201, message="您的手机号码已经注册,无法再次注册", data=None, status='fail')) | ||
122 | if type == 'change': | ||
123 | user = models.Users.objects.filter(phone=phone,deleted_at=None) | ||
124 | if user: | ||
125 | return JsonResponse(ResponseFactory(code=201, message="手机号已经注册,请使用其它手机号码", data=None, status='fail')) | ||
126 | if caches['default'].get(f'voteapp: polls:block: {phone}'): # 获取缓存中是否有保存的电话号码 | ||
127 | return JsonResponse(ResponseFactory(code=204, message="请不要短时间内重复发送短信验证码", data=None, status='fail')) | ||
128 | else: | ||
129 | code = gen_mobile_code() # 随机生成指定位数的数字 | ||
130 | template = {'code': code} | ||
131 | result = json.loads(send_sms(template, phone,area_code=area_code)) # 调用三方平台的接口 | ||
132 | if result['Code'] == "OK": | ||
133 | caches['default'].add(f'voteapp: polls:block: {phone}', int(code), 60) # 设置60秒内勿重复发短信 | ||
134 | caches['default'].set(f'voteapp: polls:valid: {phone}', int(code), 60*10) # 缓存中保存发送的验证码并设置短信的过期时间 | ||
135 | return JsonResponse(ResponseFactory(code=200, message="发送成功", data=None, status='success')) | ||
136 | else: | ||
137 | return JsonResponse(ResponseFactory(code=201, message="发送失败", data=None, status='fail')) | ||
138 | else: | ||
139 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
140 | else: | ||
141 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
142 | |||
143 | def sendsms(request): | ||
144 | """短信发送接口""" | ||
145 | if request.method == 'POST': | ||
146 | obj = verification.SendVerify(data=json.loads(request.body)) | ||
147 | if obj.is_valid(): | ||
148 | phone = obj.data.get('phone') | ||
149 | TEL_PATTERN = re.compile(r'^(1[0-9])[0-9]{9}$') | ||
150 | if TEL_PATTERN.match(phone): | ||
151 | if caches['default'].get(f'voteapp: polls:block: {phone}'): # 获取缓存中是否有保存的电话号码 | ||
152 | return JsonResponse(ResponseFactory(code=204, message="请不要短时间内重复发送短信验证码", data=None, status='fail')) | ||
153 | else: | ||
154 | code = gen_mobile_code() # 随机生成指定位数的数字 | ||
155 | template = {'code': code} | ||
156 | result = json.loads(send_sms(template, phone,area_code=86)) # 调用三方平台的接口 | ||
157 | if result['Code'] == "OK": | ||
158 | caches['default'].add(f'voteapp: polls:block: {phone}', int(code), 60) # 设置60秒内勿重复发短信 | ||
159 | caches['default'].set(f'voteapp: polls:valid: {phone}', int(code), 60*10) # 缓存中保存发送的验证码并设置短信的过期时间 | ||
160 | return JsonResponse(ResponseFactory(code=200, message="发送成功", data=None, status='success')) | ||
161 | else: | ||
162 | return JsonResponse(ResponseFactory(code=201, message="发送失败", data=None, status='fail')) | ||
163 | else: | ||
164 | return JsonResponse(ResponseFactory(code=203, message="手机号码无效", data=None, status='fail')) | ||
165 | else: | ||
166 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
167 | else: | ||
168 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
169 | |||
170 | |||
171 | def user_login(request): | ||
172 | """用户登录""" | ||
173 | if request.method == 'POST': | ||
174 | obj = verification.LoginVerify(data=json.loads(request.body)) | ||
175 | if obj.is_valid(): | ||
176 | user = CustomBackend().authenticate(username=obj.data.get('phone'), password=obj.data.get('password')) | ||
177 | if user == 'User.Disable': | ||
178 | return JsonResponse(ResponseFactory(code=201, message="登录失败,用户已被禁用", data=None, status='fail')) | ||
179 | if user is not None: | ||
180 | return JsonResponse(ResponseFactory(code=200, message="登录成功", data={'token':user.token}, status='success')) | ||
181 | else: | ||
182 | return JsonResponse(ResponseFactory(code=204, message="用户名或密码错误", data=None, status='fail')) | ||
183 | else: | ||
184 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
185 | else: | ||
186 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
187 | |||
188 | def sms_verify_login(request): | ||
189 | if request.method == 'POST': | ||
190 | obj = verification.V2LoginVerify(data=json.loads(request.body)) | ||
191 | if obj.is_valid(): | ||
192 | # 获取缓存中的验证码 | ||
193 | obj = obj.data | ||
194 | mob = caches['default'].get(f'voteapp: polls:valid: {obj.get("phone")}') | ||
195 | # is_dev = int(obj.get('sms_code')) == 123456 and settings.ENV == 'dev' | ||
196 | is_dev = int(obj.get('sms_code')) == 966446 #暂时正式环境也加万能验证码 | ||
197 | if mob == int(obj.get('sms_code')) or is_dev: | ||
198 | user = CustomBackend().v2authenticate(username=obj.get('phone')) | ||
199 | if user == 'User.Disable': | ||
200 | return JsonResponse(ResponseFactory(code=201, message="登录失败,用户已被禁用", data=None, status='fail')) | ||
201 | if user is not None: | ||
202 | caches['default'].delete(f'paopao: polls:valid: {obj.get("phone")}') | ||
203 | return JsonResponse(ResponseFactory(code=200, message="登录成功", data={'token': user.token}, status='success')) | ||
204 | else: | ||
205 | return JsonResponse(ResponseFactory(code=204, message="此用户不存在", data=None, status='fail')) | ||
206 | else: | ||
207 | return JsonResponse(ResponseFactory(code=204, message="验证码错误", data=None, status='fail')) | ||
208 | else: | ||
209 | return JsonResponse( | ||
210 | ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
211 | else: | ||
212 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
213 | |||
214 | def register(request): | ||
215 | """用户注册""" | ||
216 | if request.method == 'POST': | ||
217 | post_data = json.loads(request.body) | ||
218 | role = post_data.get('role') | ||
219 | if role == "Singer": | ||
220 | obj = verification.SingerRegister(post_data) | ||
221 | elif role == "Business" : | ||
222 | obj = verification.BusinessRegister(post_data) | ||
223 | if obj.is_valid(): | ||
224 | obj = obj.clean() | ||
225 | if obj.get("password") == obj.get("confirm_password",''): | ||
226 | re_phone = models.Users.objects.filter(phone=obj.get("phone"),deleted_at=None).exists() | ||
227 | if re_phone: | ||
228 | return JsonResponse(ResponseFactory(code=400, message="手机号码已被注册", data=None, status='fail')) | ||
229 | re_email = models.Users.objects.filter(email=obj.get("email"),deleted_at=None).exists() | ||
230 | if re_email: | ||
231 | return JsonResponse(ResponseFactory(code=400, message="邮箱已被注册", data=None, status='fail')) | ||
232 | re_nick_name = models.Users.objects.filter(nick_name=obj.get("nick_name"),deleted_at=None).exists() | ||
233 | if re_nick_name: | ||
234 | return JsonResponse(ResponseFactory(code=400, message="艺名已被注册", data=None, status='fail')) | ||
235 | #获取缓存中的验证码 | ||
236 | mob = caches['default'].get(f'voteapp: polls:valid: {obj.get("phone")}') | ||
237 | is_dev = int(obj.get('sms_code')) == 123456 and settings.ENV == 'dev' | ||
238 | if mob == int(obj.get('sms_code')) or is_dev: | ||
239 | try: | ||
240 | with transaction.atomic(): | ||
241 | # 获取微信openid | ||
242 | open_id, unionid = WeChatApi(post_data.get("vx_code", "")) | ||
243 | #生成用户信息 | ||
244 | # 歌手 | ||
245 | if role == "Singer": | ||
246 | user = models.Users.objects.create( | ||
247 | nick_name=obj.get("nick_name"), | ||
248 | real_name=obj.get("real_name"), | ||
249 | phone=obj.get("phone"), | ||
250 | email=obj.get("email"), | ||
251 | province=obj.get("province"), | ||
252 | city=obj.get("city"), | ||
253 | is_referee=obj.get("is_referee"), | ||
254 | password=make_password(obj.get("password")), | ||
255 | role=role, | ||
256 | audit_status=0, | ||
257 | status=1, | ||
258 | open_id = open_id, | ||
259 | unionid = unionid, | ||
260 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
261 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
262 | ) | ||
263 | user_info = {"email": obj.get("email"), "phone": obj.get("phone"), | ||
264 | "nick_name": obj.get("nick_name"), | ||
265 | "business_id": post_data.get("business_id",None), "role": role, | ||
266 | "province": obj.get("province"), "city": obj.get("city"), | ||
267 | "remarks":post_data.get('remarks',''), | ||
268 | "is_referee": obj.get("is_referee"), "real_name": obj.get("real_name"), | ||
269 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
270 | else : | ||
271 | user = models.Users.objects.create( | ||
272 | nick_name=obj.get("nick_name"), | ||
273 | real_name=obj.get("real_name"), | ||
274 | phone=obj.get("phone"), | ||
275 | email=obj.get("email"), | ||
276 | password=make_password(obj.get("password")), | ||
277 | role=role, | ||
278 | audit_status=0, | ||
279 | status=1, | ||
280 | open_id=open_id, | ||
281 | unionid=unionid, | ||
282 | company = obj.get("company"), | ||
283 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
284 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
285 | ) | ||
286 | user_info = {"email": obj.get("email"), "phone": obj.get("phone"), | ||
287 | "nick_name": obj.get("nick_name"),"role": role,"real_name": obj.get("real_name"),"company":obj.get("company"), | ||
288 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
289 | # 生成待审核信息 | ||
290 | models.UserExamines.objects.create( | ||
291 | user_id=user.id, | ||
292 | type = role, | ||
293 | admin_id = 0, | ||
294 | open_id = open_id if obj.get("is_push") else None, | ||
295 | business_id=post_data.get("business_id",None), | ||
296 | user_info=user_info, | ||
297 | status=0, | ||
298 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
299 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
300 | ) | ||
301 | except Exception as e: | ||
302 | return JsonResponse(ResponseFactory(code=201, message="注册失败:{}".format(e), data=None, status='fail')) | ||
303 | userdata = {"id": user.id, "nick_name": user.nick_name, "real_name": user.real_name, | ||
304 | 'token': user.token} | ||
305 | #给全体管理员推送注册信息 | ||
306 | admin_unionid = list(models.Users.objects.filter(scope=1).values_list('unionid', flat=True)) | ||
307 | admin_open_ids = list(models.WechatOfficialUsers.objects.filter(union_id__in=admin_unionid,is_subscribe=1).values_list('open_id', flat=True)) | ||
308 | data = {'channel': 'register_create', 'open_id': admin_open_ids, | ||
309 | 'data': {"nick_name":user.nick_name,"real_name": user.real_name,"time":user.created_at} | ||
310 | } | ||
311 | pushSubscribeMessage(data) | ||
312 | return JsonResponse( | ||
313 | ResponseFactory(code=200, message="注册成功", data=userdata, status='success')) | ||
314 | |||
315 | else: | ||
316 | return JsonResponse(ResponseFactory(code=201, message="验证码不正确或已失效", data=None, status='fail')) | ||
317 | else: | ||
318 | return JsonResponse(ResponseFactory(code=400, message="2次输入的密码不一致", data=None, status='fail')) | ||
319 | else: | ||
320 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
321 | else: | ||
322 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
323 | |||
324 | |||
325 | def v2register(request): | ||
326 | """V2用户注册""" | ||
327 | if request.method == 'POST': | ||
328 | post_data = json.loads(request.body) | ||
329 | role = post_data.get('role') | ||
330 | if role == "Singer":obj = verification.V2SingerRegister(post_data) | ||
331 | else:obj = verification.V2BusinessRegister(post_data) | ||
332 | if obj.is_valid(): | ||
333 | obj = obj.clean() | ||
334 | re_phone = models.Users.objects.filter(phone=obj.get("phone"),deleted_at=None).exists() | ||
335 | if re_phone: | ||
336 | return JsonResponse(ResponseFactory(code=400, message="手机号码已被注册", data=None, status='fail')) | ||
337 | re_email = models.Users.objects.filter(email=obj.get("email"),deleted_at=None).exists() | ||
338 | reg = "\w+[@][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+" | ||
339 | valid = re.findall(reg, obj.get("email")) | ||
340 | if re_email or not valid: | ||
341 | return JsonResponse(ResponseFactory(code=400, message="邮箱已被注册或格式不正确", data=None, status='fail')) | ||
342 | re_nick_name = models.Users.objects.filter(nick_name=obj.get("nick_name"),deleted_at=None).exists() | ||
343 | if re_nick_name: | ||
344 | return JsonResponse(ResponseFactory(code=400, message="艺名已被注册", data=None, status='fail')) | ||
345 | #获取缓存中的验证码 | ||
346 | mob = caches['default'].get(f'voteapp: polls:valid: {obj.get("phone")}') | ||
347 | is_dev = int(obj.get('sms_code')) == 123456 and settings.ENV == 'dev' | ||
348 | if mob == int(obj.get('sms_code')) or is_dev: | ||
349 | try: | ||
350 | with transaction.atomic(): | ||
351 | # 获取微信openid | ||
352 | open_id, unionid = WeChatApi(post_data.get("vx_code", "")) | ||
353 | #生成用户信息 | ||
354 | # 歌手 | ||
355 | if role == "Singer": | ||
356 | user = models.Users.objects.create( | ||
357 | nick_name=obj.get("nick_name"), | ||
358 | real_name=obj.get("real_name"), | ||
359 | area_code = obj.get("area_code"), | ||
360 | phone=obj.get("phone"), | ||
361 | email=obj.get("email"), | ||
362 | is_referee=obj.get("is_referee"), | ||
363 | role=role, | ||
364 | audit_status=0, | ||
365 | status=1, | ||
366 | open_id = open_id, | ||
367 | unionid = unionid, | ||
368 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
369 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
370 | ) | ||
371 | user_info = {"email": obj.get("email"), "phone": obj.get("phone"), | ||
372 | "nick_name": obj.get("nick_name"), | ||
373 | "business_id": post_data.get("business_id",None), "role": role, | ||
374 | "sound":post_data.get('sound',''), | ||
375 | "remarks":post_data.get('remarks',''), | ||
376 | "is_referee": obj.get("is_referee"), "real_name": obj.get("real_name"), | ||
377 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
378 | else : | ||
379 | user = models.Users.objects.create( | ||
380 | nick_name=obj.get("nick_name"), | ||
381 | real_name=obj.get("real_name"), | ||
382 | area_code=obj.get("area_code"), | ||
383 | phone=obj.get("phone"), | ||
384 | email=obj.get("email"), | ||
385 | role=role, | ||
386 | audit_status=0, | ||
387 | status=1, | ||
388 | open_id=open_id, | ||
389 | unionid=unionid, | ||
390 | company = obj.get("company"), | ||
391 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
392 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
393 | ) | ||
394 | user_info = {"email": obj.get("email"), "phone": obj.get("phone"), | ||
395 | "nick_name": obj.get("nick_name"),"role": role,"real_name": obj.get("real_name"),"company":obj.get("company"), | ||
396 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
397 | # 生成待审核信息 | ||
398 | models.UserExamines.objects.create( | ||
399 | user_id=user.id, | ||
400 | type = role, | ||
401 | admin_id = 0, | ||
402 | open_id = open_id if post_data.get("is_push","") else None, | ||
403 | business_id=post_data.get("business_id",None), | ||
404 | user_info=user_info, | ||
405 | status=0, | ||
406 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
407 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
408 | ) | ||
409 | except Exception as e: | ||
410 | return JsonResponse(ResponseFactory(code=201, message="注册失败:{}".format(e), data=None, status='fail')) | ||
411 | userdata = {'token': user.token} | ||
412 | #给全体管理员推送注册信息 | ||
413 | admin_ids = list(models.Users.objects.filter(scope=1).values_list('id', flat=True)) | ||
414 | admin_unionid = list(models.Users.objects.filter(scope=1).values_list('unionid', flat=True)) | ||
415 | admin_open_ids = list(models.WechatOfficialUsers.objects.filter(union_id__in=admin_unionid,is_subscribe=1).values_list('open_id', flat=True)) | ||
416 | data = {'channel': 'register_create', 'open_id': admin_open_ids, | ||
417 | 'data': {"nick_name":user.nick_name,"real_name": user.real_name,"time":user.created_at} | ||
418 | } | ||
419 | pushSubscribeMessage(data) | ||
420 | # 极光推送-注册 | ||
421 | j_title = "有新用户注册账号" | ||
422 | role_dict = {"Singer":"歌手","Business":"推荐人"} | ||
423 | j_content = "{}{}提交了注册申请".format(role_dict[role],obj.get("nick_name")) | ||
424 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
425 | "receiver_value": admin_ids, | ||
426 | "extras": {"type": "ToExamine", "value": ""}} | ||
427 | JPush().jpush_v3(jdata) | ||
428 | return JsonResponse( | ||
429 | ResponseFactory(code=200, message="注册成功", data=userdata, status='success')) | ||
430 | else: | ||
431 | return JsonResponse(ResponseFactory(code=201, message="验证码不正确或已失效", data=None, status='fail')) | ||
432 | else: | ||
433 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
434 | else: | ||
435 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
436 | |||
437 | def v3register(request): | ||
438 | """V3用户注册""" | ||
439 | if not request.method == 'POST': | ||
440 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
441 | post_data = json.loads(request.body) | ||
442 | obj = verification.V3UserRegister(post_data) | ||
443 | if not obj.is_valid(): | ||
444 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
445 | obj = obj.clean() | ||
446 | re_phone = models.Users.objects.filter(phone=obj.get("phone"), deleted_at=None).exists() | ||
447 | if re_phone: | ||
448 | return JsonResponse(ResponseFactory(code=400, message="手机号码已被注册", data=None, status='fail')) | ||
449 | re_email = models.Users.objects.filter(email=obj.get("email"), deleted_at=None).exists() | ||
450 | reg = "\w+[@][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+" | ||
451 | valid = re.findall(reg, obj.get("email")) | ||
452 | if re_email or not valid: | ||
453 | return JsonResponse(ResponseFactory(code=400, message="邮箱已被注册或格式不正确", data=None, status='fail')) | ||
454 | re_nick_name = models.Users.objects.filter(nick_name=obj.get("nick_name"), deleted_at=None).exists() | ||
455 | if re_nick_name: | ||
456 | return JsonResponse(ResponseFactory(code=400, message="艺名已被注册", data=None, status='fail')) | ||
457 | # 获取缓存中的验证码 | ||
458 | mob = caches['default'].get(f'voteapp: polls:valid: {obj.get("phone")}') | ||
459 | is_dev = int(obj.get('sms_code')) == 123456 and settings.ENV == 'dev' | ||
460 | if not (mob == int(obj.get('sms_code')) or is_dev): | ||
461 | return JsonResponse(ResponseFactory(code=201, message="验证码不正确或已失效", data=None, status='fail')) | ||
462 | try: | ||
463 | with transaction.atomic(): | ||
464 | # 获取微信openid | ||
465 | open_id, unionid = WeChatApi(post_data.get("vx_code", "")) | ||
466 | limit_config = models.SystemConfig.objects.filter(identifier='svMC9TNFz2Acx8ccPdAIH').first() | ||
467 | business_singer_limit = limit_config.content if limit_config else 0 | ||
468 | user = models.Users.objects.create( | ||
469 | nick_name=obj.get("nick_name"), | ||
470 | real_name=obj.get("real_name"), | ||
471 | area_code=obj.get("area_code"), | ||
472 | phone=obj.get("phone"), | ||
473 | email=obj.get("email"), | ||
474 | audit_status=1, | ||
475 | status=1, | ||
476 | open_id=open_id, | ||
477 | unionid=unionid, | ||
478 | business_singer_limit = business_singer_limit, | ||
479 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
480 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
481 | ) | ||
482 | except Exception as e: | ||
483 | return JsonResponse(ResponseFactory(code=201, message="注册失败:{}".format(e), data=None, status='fail')) | ||
484 | userdata = {'token': user.token} | ||
485 | return JsonResponse(ResponseFactory(code=200, message="注册成功", data=userdata, status='success')) | ||
486 | |||
487 | |||
488 | def restPwd(request): | ||
489 | if request.method == 'PUT': | ||
490 | obj = verification.reset_verification(json.loads(request.body)) | ||
491 | if obj.is_valid(): | ||
492 | obj = obj.clean() | ||
493 | mob = caches['default'].get(f'voteapp: polls:valid: {obj.get("phone")}') | ||
494 | if obj.get('password') == obj.get('confirm_password'): | ||
495 | is_dev = int(obj.get('sms_code')) == 123456 and settings.ENV == 'dev' | ||
496 | if mob == int(obj.get('sms_code')) or is_dev: | ||
497 | user = models.Users.objects.filter(phone=obj.get("phone"),deleted_at=None) | ||
498 | if user: | ||
499 | user.update(password=make_password(obj.get("password"))) | ||
500 | return JsonResponse(ResponseFactory(code=200, message="修改完成", data=None, status='success')) | ||
501 | else: | ||
502 | return JsonResponse(ResponseFactory(code=201, message="不存在此账号,请检查手机号", data=None, status='success')) | ||
503 | else: | ||
504 | return JsonResponse(ResponseFactory(code=201, message="验证码不正确,请重新输入", data=None, status='fail')) | ||
505 | else: | ||
506 | return JsonResponse(ResponseFactory(code=400, message="2次输入的密码不一致", data=None, status='fail')) | ||
507 | else: | ||
508 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
509 | else: | ||
510 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
511 | |||
512 | |||
513 | def businessList(request): | ||
514 | if request.method == 'GET': | ||
515 | ser = SystemBusinessSerializer(models.Users.objects.filter(role='Business',status=1,audit_status=1,deleted_at=None),many=True) | ||
516 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=ser.data, status='success')) | ||
517 | else: | ||
518 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
519 | |||
520 | |||
521 | def wechatAuth(request): | ||
522 | if request.method == 'POST': | ||
523 | obj = verification.WechatAuth(json.loads(request.body)) | ||
524 | if obj.is_valid(): | ||
525 | platform = obj.clean().get('platform') | ||
526 | vx_code = obj.clean().get('vx_code') | ||
527 | if platform == 'app': | ||
528 | open_id, unionid = AppWechatApi(vx_code) | ||
529 | elif platform == 'applet': | ||
530 | open_id, unionid = WeChatApi(vx_code) | ||
531 | if open_id is not None and unionid is not None: | ||
532 | users = WeiXinAuthUser(models.Users.objects.filter(unionid=unionid,status=1,deleted_at=None),many=True).data | ||
533 | if users: | ||
534 | return JsonResponse(ResponseFactory(code=200, message="登录成功", data=users, status='success')) | ||
535 | else: | ||
536 | return JsonResponse(ResponseFactory(code=200, message="用户不存在或用户未绑定微信用户", data=None, status='fail')) | ||
537 | else: | ||
538 | return JsonResponse(ResponseFactory(code=201, message="不正确的vx_code", data=None, status='fail')) | ||
539 | else: | ||
540 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
541 | else: | ||
542 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) |
api/ApiList/my.py
0 → 100644
1 | import re | ||
2 | import json | ||
3 | from django.http import JsonResponse | ||
4 | from api import models | ||
5 | from api.views import AuthPermissionRequired,get_user_info,user_point_record | ||
6 | from django.utils import timezone | ||
7 | from api import serializers | ||
8 | from api.views import ResponseFactory,PageNumberPagination,createMessage,pushSubscribeMessage,JPush,Msg_Push_Server,remove_alias_device,user_permission | ||
9 | from rest_framework.views import APIView | ||
10 | from django.db import transaction | ||
11 | from django.utils.decorators import method_decorator | ||
12 | from api.views import upload_image,WeChatApi,AppWechatApi | ||
13 | import base64 | ||
14 | from api import verification | ||
15 | from api.loggin import logger | ||
16 | from django.core.cache import caches | ||
17 | from HisinApi import settings | ||
18 | from django.db.models import Q | ||
19 | from datetime import timedelta | ||
20 | import requests | ||
21 | |||
22 | |||
23 | def dedupe(activity_ids): | ||
24 | new_activity_ids = [] | ||
25 | for activity_id in activity_ids: | ||
26 | if activity_id not in new_activity_ids: | ||
27 | new_activity_ids.append(activity_id) | ||
28 | return new_activity_ids | ||
29 | |||
30 | |||
31 | @AuthPermissionRequired() | ||
32 | def upload(request): | ||
33 | """ | ||
34 | base64图片上传 | ||
35 | """ | ||
36 | filebase64 = json.loads(request.body).get('file') | ||
37 | temp = base64.b64decode(filebase64) | ||
38 | file_url = upload_image(temp) | ||
39 | data = {"type": "jpg", "name": "", "url": file_url, "size": "", "disk": "oss", "created_at": "", "id": 0} | ||
40 | return JsonResponse(ResponseFactory(code=200, message="上传成功", data=data, status='success')) | ||
41 | |||
42 | |||
43 | @AuthPermissionRequired() | ||
44 | def updateUserAvatar(request): | ||
45 | """ | ||
46 | 修改头像 | ||
47 | """ | ||
48 | if request.method == "PUT": | ||
49 | obj = verification.update_user_verification(json.loads(request.body)) | ||
50 | if obj.is_valid(): | ||
51 | data = obj.clean() | ||
52 | userData = get_user_info(request) | ||
53 | models.Users.objects.filter(id=userData.get('id')).update( avatar = data['avatar']) | ||
54 | # activity_ids = list(models.Activitys.objects.filter(status=1, deleted_at=None).values_list('id', flat=True)) | ||
55 | # all_activity_ids = list(models.Activitys.objects.filter(deleted_at=None).values_list('id', flat=True)) | ||
56 | user = serializers.UserListSerializer(models.Users.objects.filter(id=userData['id']).first(),many=False) | ||
57 | return JsonResponse(ResponseFactory(code=200, message="修改成功", data=user.data, status='success')) | ||
58 | else: | ||
59 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
60 | else: | ||
61 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
62 | |||
63 | class MyActivitys(APIView): | ||
64 | """ | ||
65 | 我参与的活动 | ||
66 | """ | ||
67 | @method_decorator(AuthPermissionRequired()) | ||
68 | def get(self, request): | ||
69 | user_id = get_user_info(request)['id'] | ||
70 | ids = models.ActivityHasUsers.objects.filter(user_id=user_id,deleted_at=None).order_by('-created_at').values_list('activity_id',flat=True).distinct() | ||
71 | activity_id_str = ",".join('%s' % id for id in ids) | ||
72 | queryset = models.Activitys.objects.filter(id__in=ids,deleted_at=None).extra(select={'m':'FIELD(id,{})'.format(activity_id_str)},order_by=['m']) | ||
73 | page_obj = PageNumberPagination() | ||
74 | page_data = page_obj.paginate_queryset(queryset, request) | ||
75 | ser_obj = serializers.MyActivitysSerializer(page_data, many=True,context={"user_id":user_id}) | ||
76 | data = {"activitys":ser_obj.data,"count":queryset.count()} | ||
77 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
78 | |||
79 | @AuthPermissionRequired() | ||
80 | def SaveOrSubmitList(request): | ||
81 | """ | ||
82 | 查看参加活动详情:提交的与保存的demo | ||
83 | """ | ||
84 | if request.method == "GET": | ||
85 | a_id = request.GET['activity_id'] | ||
86 | user_id = get_user_info(request)['id'] | ||
87 | activity =serializers.ActivitysSerializer(models.Activitys.objects.filter(id=a_id,deleted_at=None),many=True,context={'user_id':user_id}) | ||
88 | queryset = models.ActivityHasUsers.objects.filter(user_id=user_id,activity_id=a_id,deleted_at=None).order_by('-created_at') | ||
89 | ser_obj = serializers.ManyActivitysHasUserSerializer(queryset, many=True) | ||
90 | #增加自主报价信息 | ||
91 | price_set = models.ActivityUserHasPrices.objects.filter(user_id=user_id,activity_id=a_id).first() | ||
92 | if price_set:self_price = serializers.ActivitysPriceSerializer(price_set,many=False,context={'activity_id':a_id}).data | ||
93 | else:self_price = None | ||
94 | data = {'data':{'activity':activity.data,'list':ser_obj.data,"self_price":self_price}} | ||
95 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
96 | else: | ||
97 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
98 | |||
99 | |||
100 | @AuthPermissionRequired() | ||
101 | def V2SaveOrSubmitList(request): | ||
102 | """ | ||
103 | 查看参加活动详情:提交的与保存的demo | ||
104 | """ | ||
105 | if request.method == "GET": | ||
106 | a_id = request.GET['activity_id'] | ||
107 | user_id = get_user_info(request)['id'] | ||
108 | activity =serializers.ActivitysSerializer(models.Activitys.objects.filter(id=a_id,deleted_at=None).first(),many=False,context={'user_id':user_id}) | ||
109 | queryset = models.ActivityHasUsers.objects.filter(user_id=user_id,activity_id=a_id,deleted_at=None).order_by('-created_at') | ||
110 | ser_obj = serializers.ManyActivitysHasUserSerializer(queryset, many=True) | ||
111 | # 增加自主报价信息 | ||
112 | price_set = models.ActivityUserHasPrices.objects.filter(user_id=user_id, activity_id=a_id).first() | ||
113 | if price_set:self_price = serializers.ActivitysPriceSerializer(price_set, many=False,context={'activity_id':a_id}).data | ||
114 | else:self_price = None | ||
115 | data = {'activity':activity.data,'list':ser_obj.data,"self_price":self_price} | ||
116 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
117 | else: | ||
118 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
119 | |||
120 | @AuthPermissionRequired() | ||
121 | def UpdateSumbit(request): | ||
122 | """ | ||
123 | 更新提交的版本 | ||
124 | """ | ||
125 | if request.method == "PUT": | ||
126 | userData = get_user_info(request) | ||
127 | try: | ||
128 | # 检查是否有提交权限 | ||
129 | permission = user_permission(userData['id']) | ||
130 | if 2 not in permission: | ||
131 | return JsonResponse(ResponseFactory(code=400, message='用户无此权限', data=None, status='fail')) | ||
132 | put_data = json.loads(request.body) | ||
133 | is_hide = put_data.get('is_hide', None) | ||
134 | obj = verification.update_submit_verification(put_data) | ||
135 | if obj.is_valid(): | ||
136 | data = obj.clean() | ||
137 | self_price = put_data.get('self_price', None) | ||
138 | if is_hide == None: | ||
139 | ahu = models.ActivityHasUsers.objects.filter(type='Submit', user_id=userData.get('id'),activity_id=data.get('activity_id')).last() | ||
140 | is_hide = ahu.is_hide if ahu else 1 | ||
141 | # 校验自主报价参数 | ||
142 | if self_price: | ||
143 | ver = verification.SubmitPriceVerification(data=self_price) | ||
144 | if not ver.is_valid(): | ||
145 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(ver), data=None, status='fail')) | ||
146 | if self_price['value']['amounts']: | ||
147 | if not (0 <= self_price['value']['amounts'] <= 9999999): return JsonResponse( | ||
148 | ResponseFactory(code=201, message="金额在0-9999999之间", data=None, status='fail')) | ||
149 | if self_price['value']['ratio']: | ||
150 | if not (0 <= self_price['value']['ratio'] <= 100): return JsonResponse( | ||
151 | ResponseFactory(code=201, message="分成比列在0%-100%之间", data=None, status='fail')) | ||
152 | |||
153 | #查看活动状态 | ||
154 | activity = models.Activitys.objects.get(id=data.get('activity_id')) | ||
155 | if activity.status != 1: | ||
156 | return JsonResponse(ResponseFactory(code=400, message="活动已完成或下架", data=None, status='fail')) | ||
157 | try: | ||
158 | try: | ||
159 | vx_code = put_data.get("vx_code","") | ||
160 | open_id, unionid = WeChatApi(vx_code) | ||
161 | except: | ||
162 | open_id = '' | ||
163 | with transaction.atomic(): | ||
164 | models.ActivityHasUsers.objects.filter(activity_id=data.get('activity_id'),user_id=userData.get('id')).update(type='Save',updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
165 | updateItem = models.ActivityHasUsers.objects.filter(id=data.get('has_id')) | ||
166 | updateItem.update( | ||
167 | type='Submit', | ||
168 | is_hide = is_hide, | ||
169 | open_id = open_id, | ||
170 | submit_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
171 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
172 | ) | ||
173 | |||
174 | # 存入自主报价 | ||
175 | if self_price: | ||
176 | models.ActivityUserHasPrices.objects.update_or_create( | ||
177 | activity_id = data.get('activity_id'), user_id= userData.get('id'), | ||
178 | defaults={ | ||
179 | "value":self_price['value'], | ||
180 | "is_deduct":self_price['is_deduct'], | ||
181 | "is_talk":self_price['is_talk'], | ||
182 | "address_id":self_price['address_id'], | ||
183 | "is_accept_address":self_price['is_accept_address'], | ||
184 | "created_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
185 | "updated_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"),}, | ||
186 | ) | ||
187 | #更新到动态 | ||
188 | is_tidings = put_data.get("is_tidings", 0) | ||
189 | if is_tidings == 1: | ||
190 | url = updateItem.first().demo_url | ||
191 | if url: | ||
192 | models.UserHasTidings.objects.create(user_id=userData['id'],activity_id=data.get('activity_id'),type=2,url=url, created_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
193 | else: | ||
194 | return JsonResponse(ResponseFactory(code=201, message="保存音频处理中,请5秒后再提交", data=None, status='fail')) | ||
195 | |||
196 | #提交作品计数 1.先检查用户对该作品之前是否有提交且未读的消息 | ||
197 | user_msg = models.UserMessages.objects.filter(is_read=0,sender_id=userData['id'],activity_id=data.get('activity_id'),deleted_at=None,type=3) | ||
198 | if user_msg: | ||
199 | user_msg.update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
200 | # 获取全体管理员和推荐人open_id | ||
201 | project_id = models.Activitys.objects.filter(id=data['activity_id']).first().project_id | ||
202 | project = models.Projects.objects.filter(id=project_id).first() | ||
203 | project_user_ids = [] | ||
204 | if project: | ||
205 | if project.is_public:project_user_ids = list(models.UserHasProjects.objects.filter(project_id=project_id).values_list('user_id',flat=True)) | ||
206 | else:project_user_ids = [models.Activitys.objects.filter(id=data['activity_id']).first().user_id] | ||
207 | project_user_unionid = list(models.Users.objects.filter(id__in=project_user_ids, deleted_at=None, status=1).values_list('unionid', flat=True)) | ||
208 | admin_unionid = list(models.Users.objects.filter(scope=1,deleted_at=None,status=1).values_list('unionid', flat=True)) | ||
209 | push_open_ids = list(models.WechatOfficialUsers.objects.filter(union_id__in=admin_unionid + project_user_unionid,is_subscribe=1).values_list('open_id', flat=True)) | ||
210 | song_name = models.Activitys.objects.filter(id=data['activity_id']).first().song_name | ||
211 | # 再创建消息 | ||
212 | business_id = userData['business_id'] | ||
213 | if business_id: | ||
214 | # 获取推荐人公众号open_id | ||
215 | unionid = models.Users.objects.filter(id=business_id).values_list('unionid', flat=True) | ||
216 | wechat_official = models.WechatOfficialUsers.objects.filter(union_id__in=unionid, is_subscribe=1).last() | ||
217 | if wechat_official: | ||
218 | # 公众号推送 | ||
219 | p_data = {'channel': 'singer_related', 'open_id': [wechat_official.open_id], | ||
220 | 'data': {"title": "您的歌手参加了试唱歌曲", | ||
221 | "name": userData['nick_name'] + "("+userData['real_name']+")", | ||
222 | "intro": "参加了试唱歌曲《{}》".format(song_name), | ||
223 | "remark": "点击前往 >", | ||
224 | "page": "/packageMy/pages/like?tab=2"}} | ||
225 | pushSubscribeMessage(p_data) | ||
226 | # 发给绑定的推荐人 | ||
227 | m_data = {'sender_id': userData['id'], 'receivers': [business_id], | ||
228 | 'activity_id': data['activity_id'], 'type': 3, 'is_bind': 1} | ||
229 | #之前的提交消息设为已读 | ||
230 | models.UserMessages.objects.filter(is_read=0,activity_id=data['activity_id'],type=3,receiver_id=business_id,deleted_at=None,is_bind=1).update(is_read=1) | ||
231 | #创建新的未读消息 | ||
232 | createMessage(m_data) | ||
233 | |||
234 | # 极光推送-提交作品推荐人 | ||
235 | j_title = "您的歌手参加了试唱" | ||
236 | j_content = "您的歌手{}参加了试唱活动《{}》".format(userData['nick_name'], song_name) | ||
237 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
238 | "receiver_value": [business_id], | ||
239 | "extras": {"type": "ToTaSing", "value": ""}} | ||
240 | JPush().jpush_v3(jdata) | ||
241 | |||
242 | # 给全体管理员和项目管理员推服务号消息 | ||
243 | p_data = {'channel': 'activity_join', 'open_id': push_open_ids, | ||
244 | 'data': {"first": "{}({})提交了试唱作品".format(userData['nick_name'], userData['real_name']), | ||
245 | "keyword1": "《"+song_name+"》", | ||
246 | "keyword2": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
247 | "remark": "点击试听 >","page":"/pages/index/index"} | ||
248 | } | ||
249 | pushSubscribeMessage(p_data) | ||
250 | |||
251 | # 外部管理员id | ||
252 | activity_manage_ids = list( | ||
253 | models.UserManageActivitie.objects.filter(activity_id=data['activity_id']).values_list( | ||
254 | 'user_id', flat=True)) | ||
255 | # 发送系统消息(平台管理员+项目管理员+外部管理员) | ||
256 | receivers = list(models.Users.objects.filter(scope=1).values_list('id', flat=True)) | ||
257 | receivers = list(set(receivers + project_user_ids +activity_manage_ids)) | ||
258 | m_data = {'sender_id': userData['id'], 'receivers': receivers, 'activity_id': data['activity_id'], | ||
259 | 'type': 3, 'is_bind': 0} | ||
260 | # 之前的提交消息设为已读 | ||
261 | models.UserMessages.objects.filter(is_read=0, activity_id=data['activity_id'], type=3,receiver_id__in=receivers, deleted_at=None, is_bind=0).update(is_read=1) | ||
262 | # 创建新的未读消息 | ||
263 | createMessage(m_data) | ||
264 | |||
265 | # 极光推送-提交作品全体管理员 | ||
266 | j_title = "有新用户提交试唱" | ||
267 | j_content = "{}参与了试唱《{}》".format(userData['nick_name'], song_name) | ||
268 | jdata = {"title": j_title, "content": j_content, "content_type": "text", | ||
269 | "receiver_value": receivers, | ||
270 | "extras": {"type": "ToPlatfromSing", "value": ""}} | ||
271 | JPush().jpush_v3(jdata) | ||
272 | except Exception as e: | ||
273 | logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(userData['id'], request.body, e)) | ||
274 | return JsonResponse(ResponseFactory(code=201, message="修改失败:{}".format(e), data=None, status='fail')) | ||
275 | #积分逻辑(区分全曲还是片段) | ||
276 | sing_type = updateItem.first().sing_type | ||
277 | if sing_type == 'Part': | ||
278 | # 歌手积分 | ||
279 | user_point_record(user_id=userData['id'], type='SubmitPart', activity_id=data['activity_id']) | ||
280 | # 推荐人积分 | ||
281 | if userData['business_id']: | ||
282 | user_point_record(user_id=userData['business_id'], type='SingerSubmitPart',activity_id=data['activity_id'],singer_id=userData['id']) | ||
283 | else: | ||
284 | # 歌手积分 | ||
285 | user_point_record(user_id=userData['id'], type='SubmitFull', activity_id=data['activity_id']) | ||
286 | # 推荐人积分 | ||
287 | if userData['business_id']: | ||
288 | user_point_record(user_id=userData['business_id'], type='SingerSubmitFull',activity_id=data['activity_id'],singer_id=userData['id']) | ||
289 | return JsonResponse(ResponseFactory(code=200, message="修改成功", data=None, status='success')) | ||
290 | else: | ||
291 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
292 | except Exception as e: | ||
293 | logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(userData['id'], request.body,e)) | ||
294 | return JsonResponse(ResponseFactory(code=201, message="修改失败:{}".format(e), data=None, status='fail')) | ||
295 | else: | ||
296 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
297 | |||
298 | class AdminActivitys(APIView): | ||
299 | @method_decorator(AuthPermissionRequired()) | ||
300 | def get(self,request): | ||
301 | """管理员查看试唱""" | ||
302 | user = get_user_info(request) | ||
303 | user_id = user['id'] | ||
304 | scope = user['scope'] | ||
305 | kwargs = {"status":1,"deleted_at":None} | ||
306 | text = request.GET.get('text','') | ||
307 | if text:kwargs['song_name__icontains'] = text | ||
308 | activity_ids = list(models.ActivityHasUsers.objects.filter(user__deleted_at=None,user__status=1,type='Submit',deleted_at=None).order_by('-created_at').values_list('activity_id',flat=True)) | ||
309 | #去重保序 | ||
310 | activity_ids2 = list(set(activity_ids)) | ||
311 | activity_ids2.sort(key=activity_ids.index) | ||
312 | idList = ",".join('%s' % id for id in activity_ids2) | ||
313 | kwargs['id__in'] = activity_ids2 | ||
314 | if scope == 2: | ||
315 | project_ids = list(models.UserHasProjects.objects.filter(user_id=user_id).values_list('project_id', flat=True)) | ||
316 | kwargs['project_id__in'] = project_ids | ||
317 | #过滤掉不相关的活动,去掉不公开的厂牌下活动不是自己创建的活动 | ||
318 | nopublic_project_id = list(models.Projects.objects.filter(id__in=project_ids,is_public=0,deleted_at=None).values_list('id',flat=True)) | ||
319 | noself_activity_id = list(models.Activitys.objects.filter(project_id__in=nopublic_project_id, status=1,deleted_at=None).exclude(user_id=user_id).values_list('id', flat=True)) | ||
320 | ret = [x for x in activity_ids if x not in noself_activity_id] | ||
321 | kwargs['id__in'] = ret | ||
322 | queryset = models.Activitys.objects.filter(**kwargs).select_related('project').extra(select={'m':'FIELD(activitys.id,{})'.format(idList)},order_by=['m']) | ||
323 | # # #获取所有活动 | ||
324 | page_obj = PageNumberPagination() | ||
325 | page_data = page_obj.paginate_queryset(queryset, request) | ||
326 | for page in page_data: | ||
327 | page.ahus = models.ActivityHasUsers.objects.select_related('user__business').filter(type='Submit',activity_id=page.id,deleted_at=None).order_by('-created_at')\ | ||
328 | .extra(select={'share_user_nick_name':'SELECT users.nick_name FROM activity_share_users LEFT JOIN users ON activity_share_users.share_id=users.id WHERE activity_share_users.activity_id = activity_has_users.activity_id and activity_share_users.user_id=activity_has_users.user_id', | ||
329 | 'share_user_real_name':'SELECT users.real_name FROM activity_share_users LEFT JOIN users ON activity_share_users.share_id=users.id WHERE activity_share_users.activity_id = activity_has_users.activity_id and activity_share_users.user_id=activity_has_users.user_id', | ||
330 | }) | ||
331 | ser_obj = serializers.PlatfromAuditionSerializer(page_data, many=True, context={"user_id": user_id}) | ||
332 | data = {"activitys": ser_obj.data, "count": queryset.count()} | ||
333 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
334 | |||
335 | |||
336 | @AuthPermissionRequired() | ||
337 | def AdminSubmitList(request): | ||
338 | """ | ||
339 | 管理员查看参加活动详情:提交的与demo | ||
340 | """ | ||
341 | if request.method == "GET": | ||
342 | a_id = request.GET['activity_id'] | ||
343 | user_id = get_user_info(request)['id'] | ||
344 | activity =serializers.ActivitysSerializer( models.Activitys.objects.filter(id=a_id,deleted_at=None),many=True,context={'user_id':user_id}) | ||
345 | queryset = models.ActivityHasUsers.objects.filter(activity_id=a_id,type='Submit',deleted_at=None).order_by('-created_at') | ||
346 | ser_obj = serializers.ManyActivitysHasUserSerializer(queryset, many=True) | ||
347 | data = {'data':{'activity':activity.data,'list':ser_obj.data}} | ||
348 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
349 | else: | ||
350 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
351 | |||
352 | @AuthPermissionRequired() | ||
353 | def V2AdminSubmitList(request): | ||
354 | """ | ||
355 | 管理员查看参加活动详情:提交的与demo | ||
356 | """ | ||
357 | if request.method == "GET": | ||
358 | a_id = request.GET['activity_id'] | ||
359 | user_id = get_user_info(request)['id'] | ||
360 | activity =serializers.ActivitysSerializer( models.Activitys.objects.filter(id=a_id,deleted_at=None).first(),many=False,context={'user_id':user_id}) | ||
361 | queryset = models.ActivityHasUsers.objects.filter(activity_id=a_id,type='Submit',deleted_at=None).order_by('-created_at') | ||
362 | ser_obj = serializers.ManyActivitysHasUserSerializer(queryset, many=True) | ||
363 | data = {'activity':activity.data,'list':ser_obj.data} | ||
364 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
365 | else: | ||
366 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
367 | |||
368 | @AuthPermissionRequired() | ||
369 | def SubmitExamine(request): | ||
370 | """ | ||
371 | 再次提交审核 | ||
372 | :param request: | ||
373 | :return: | ||
374 | """ | ||
375 | if request.method == "POST": | ||
376 | user = get_user_info(request) | ||
377 | post_data = json.loads(request.body) | ||
378 | role = user['role'] | ||
379 | if role == "Singer": | ||
380 | obj = verification.singer_submit_examine_verification(post_data) | ||
381 | elif role == "Business": | ||
382 | obj = verification.business_submit_examine_verification(post_data) | ||
383 | if obj.is_valid(): | ||
384 | obj = obj.clean() | ||
385 | #判断该用户是否存在待审核的数据 | ||
386 | is_examines = models.UserExamines.objects.filter(user_id=user.get('id'),status=0,deleted_at=None).exists() | ||
387 | if is_examines: | ||
388 | return JsonResponse(ResponseFactory(code=201, message="已提交审核,请勿重复申请", data=None, status='fail')) | ||
389 | # 获取小程序openid | ||
390 | try: | ||
391 | vx_code = post_data.get("vx_code") | ||
392 | open_id, unionid = WeChatApi(vx_code) | ||
393 | except: | ||
394 | open_id = '' | ||
395 | if role == "Singer": | ||
396 | user_info = {"email": obj.get("email"), "phone": user.get("phone"), | ||
397 | "nick_name": obj.get("nick_name"), | ||
398 | "remarks": post_data.get('remarks', ''), | ||
399 | "business_id": post_data.get("business_id",None), "role": role, | ||
400 | "province": obj.get("province"), "city": obj.get("city"), | ||
401 | "is_referee": obj.get("is_referee"), "real_name": obj.get("real_name"), | ||
402 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
403 | elif role == 'Business': | ||
404 | user_info = {"email": obj.get("email"), "phone": user.get("phone"), | ||
405 | "nick_name": obj.get("nick_name"), "role": role, "real_name": obj.get("real_name"), | ||
406 | "company": obj.get("company"), | ||
407 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
408 | try: | ||
409 | with transaction.atomic(): | ||
410 | # 生成待审核信息 | ||
411 | models.UserExamines.objects.create( | ||
412 | user_id=user.get('id'), | ||
413 | type = role, | ||
414 | admin_id=0, | ||
415 | open_id = open_id, | ||
416 | user_info = user_info, | ||
417 | business_id=obj.get("business_id", 0), | ||
418 | status=0, | ||
419 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
420 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
421 | ) | ||
422 | #修改用户信息 | ||
423 | models.Users.objects.filter(id=user.get('id')).update( | ||
424 | audit_status=0, | ||
425 | nick_name = obj.get("nick_name"), | ||
426 | real_name = obj.get("real_name"), | ||
427 | is_referee = obj.get("is_referee", None), | ||
428 | province = obj.get("province", ""), | ||
429 | city = obj.get("city", ""), | ||
430 | company = obj.get("company", ""), | ||
431 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
432 | ) | ||
433 | return JsonResponse(ResponseFactory(code=200, message="提交成功", data=None, status='success')) | ||
434 | except Exception as e: | ||
435 | return JsonResponse(ResponseFactory(code=400, message="提交失败:{}".format(e), data=None, status='fail')) | ||
436 | else: | ||
437 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
438 | else: | ||
439 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
440 | |||
441 | |||
442 | @AuthPermissionRequired() | ||
443 | def V2SubmitExamine(request): | ||
444 | """ | ||
445 | 再次提交审核 | ||
446 | :param request: | ||
447 | :return: | ||
448 | """ | ||
449 | if request.method == "POST": | ||
450 | user = get_user_info(request) | ||
451 | post_data = json.loads(request.body) | ||
452 | role = user['role'] | ||
453 | if role == "Singer": | ||
454 | obj = verification.v2_singer_submit_examine_verification(post_data) | ||
455 | else: | ||
456 | obj = verification.v2_business_submit_examine_verification(post_data) | ||
457 | if obj.is_valid(): | ||
458 | obj = obj.clean() | ||
459 | #判断该用户是否存在待审核的数据 | ||
460 | is_examines = models.UserExamines.objects.filter(user_id=user.get('id'),status=0,deleted_at=None).exists() | ||
461 | if is_examines: | ||
462 | return JsonResponse(ResponseFactory(code=201, message="已提交审核,请勿重复申请", data=None, status='fail')) | ||
463 | # 判断邮箱格式正确且唯一 | ||
464 | reg = "\w+[@][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+" | ||
465 | valid = re.findall(reg, obj.get("email")) | ||
466 | re_email = models.Users.objects.filter(~Q(id=user['id']),email=obj.get("email"), deleted_at=None).exists() | ||
467 | if re_email or not valid: | ||
468 | return JsonResponse(ResponseFactory(code=400, message="邮箱已被注册或格式不正确", data=None, status='fail')) | ||
469 | # 获取小程序openid | ||
470 | try: | ||
471 | vx_code = post_data.get("vx_code","") | ||
472 | open_id, unionid = WeChatApi(vx_code) | ||
473 | except: | ||
474 | open_id = '' | ||
475 | if role == "Singer": | ||
476 | user_info = {"email": obj.get("email"), "phone": user.get("phone"), | ||
477 | "nick_name": obj.get("nick_name"), | ||
478 | "remarks": post_data.get('remarks', ''), | ||
479 | "sound":post_data.get('sound', ''), | ||
480 | "business_id": post_data.get("business_id",None), "role": role, | ||
481 | "is_referee": post_data.get("is_referee",None), "real_name": obj.get("real_name"), | ||
482 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
483 | else: | ||
484 | user_info = {"email": obj.get("email"), "phone": user.get("phone"), | ||
485 | "nick_name": obj.get("nick_name"), "role": role, "real_name": obj.get("real_name"), | ||
486 | "company": obj.get("company"), | ||
487 | "created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
488 | try: | ||
489 | with transaction.atomic(): | ||
490 | # 生成待审核信息 | ||
491 | models.UserExamines.objects.create( | ||
492 | user_id=user.get('id'), | ||
493 | type = role, | ||
494 | admin_id=0, | ||
495 | open_id = open_id, | ||
496 | user_info = user_info, | ||
497 | business_id=post_data.get("business_id", 0), | ||
498 | status=0, | ||
499 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
500 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
501 | ) | ||
502 | #修改用户信息 | ||
503 | models.Users.objects.filter(id=user.get('id')).update( | ||
504 | audit_status=0, | ||
505 | nick_name = obj.get("nick_name"), | ||
506 | real_name = obj.get("real_name"), | ||
507 | is_referee = obj.get("is_referee", None), | ||
508 | company = obj.get("company", None), | ||
509 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
510 | ) | ||
511 | return JsonResponse(ResponseFactory(code=200, message="提交成功", data=None, status='success')) | ||
512 | except Exception as e: | ||
513 | return JsonResponse(ResponseFactory(code=400, message="提交失败:{}".format(e), data=None, status='fail')) | ||
514 | else: | ||
515 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
516 | else: | ||
517 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
518 | |||
519 | |||
520 | |||
521 | @AuthPermissionRequired() | ||
522 | def SetUserTags(request): | ||
523 | """ | ||
524 | 设置用户标签 | ||
525 | """ | ||
526 | if request.method == "PUT": | ||
527 | obj = verification.user_tags_verification(json.loads(request.body)) | ||
528 | if obj.is_valid(): | ||
529 | tag_ids = json.loads(request.body)['tags'] | ||
530 | user = get_user_info(request) | ||
531 | #删除以前的标签设置 | ||
532 | models.UserHasTags.objects.filter(user_id=user.get('id'),deleted_at=None).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
533 | if len(tag_ids) == 0: | ||
534 | return JsonResponse(ResponseFactory(code=400, message='至少选择一个标签', data=None, status='fail')) | ||
535 | for tag_id in tag_ids: | ||
536 | models.UserHasTags.objects.create( | ||
537 | user_id=user.get('id'), | ||
538 | tag_id = tag_id, | ||
539 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
540 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
541 | ) | ||
542 | return JsonResponse(ResponseFactory(code=200, message="设置成功", data=None, status='success')) | ||
543 | else: | ||
544 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
545 | else: | ||
546 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
547 | |||
548 | def getUserTag(request): | ||
549 | """ | ||
550 | 获取所有标签和用户标签 | ||
551 | """ | ||
552 | if request.method == "GET": | ||
553 | type = request.GET.get('type',1) | ||
554 | orderbyList = ['-weight', '-created_at'] | ||
555 | allTag = serializers.SystemTagsSerializer(models.SystemTags.objects.filter(type=type,deleted_at=None).order_by(*orderbyList),many=True) | ||
556 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=allTag.data, status='success')) | ||
557 | else: | ||
558 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
559 | |||
560 | @AuthPermissionRequired() | ||
561 | def unbind(request): | ||
562 | """ | ||
563 | 解绑微信 | ||
564 | :return: | ||
565 | """ | ||
566 | if request.method == "PUT": | ||
567 | user = get_user_info(request) | ||
568 | models.Users.objects.filter(id=user.get('id')).update(unionid='', open_id='', updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
569 | return JsonResponse(ResponseFactory(code=200, message="解绑成功", data=None, status='success')) | ||
570 | else: | ||
571 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
572 | |||
573 | @AuthPermissionRequired() | ||
574 | def bind(request): | ||
575 | """ | ||
576 | 重新绑定微信 | ||
577 | :return: | ||
578 | """ | ||
579 | if request.method == "POST": | ||
580 | post_data = json.loads(request.body) | ||
581 | obj = verification.bind_verification(post_data) | ||
582 | if obj.is_valid(): | ||
583 | obj = obj.clean() | ||
584 | platform = post_data.get('platform','') | ||
585 | if platform == 'app': | ||
586 | open_id, unionid = AppWechatApi(obj.get("vx_code")) | ||
587 | else: | ||
588 | open_id, unionid = WeChatApi(obj.get("vx_code")) | ||
589 | user = get_user_info(request) | ||
590 | models.Users.objects.filter(id=user.get('id')).update(unionid=unionid, open_id=open_id,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
591 | return JsonResponse(ResponseFactory(code=200, message="换绑成功", data=None, status='success')) | ||
592 | else: | ||
593 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
594 | else: | ||
595 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
596 | |||
597 | |||
598 | class MySinget(APIView): | ||
599 | @method_decorator(AuthPermissionRequired()) | ||
600 | def get(self,request): | ||
601 | user = get_user_info(request) | ||
602 | text = request.GET.get('text', '') | ||
603 | if text : | ||
604 | queset = models.Users.objects.filter(business_id=user.get('id'),nick_name__icontains=text,audit_status=1,status=1,deleted_at=None).order_by('-created_at') | ||
605 | else: | ||
606 | queset = models.Users.objects.filter(business_id=user.get('id'),audit_status=1,status=1,deleted_at=None).order_by('-created_at') | ||
607 | page_obj = PageNumberPagination() | ||
608 | page_data = page_obj.paginate_queryset(queset, request) | ||
609 | serializer = serializers.MySingerSerializer(page_data, many=True,context={"user_id":user['id'] }) | ||
610 | data = {"data":serializer.data,"count":queset.count()} | ||
611 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data= data, status='success')) | ||
612 | |||
613 | |||
614 | class SingerInfo(APIView): | ||
615 | @method_decorator(AuthPermissionRequired()) | ||
616 | def get(self,request): | ||
617 | singer_id = request.GET['singer_id'] | ||
618 | user_id = get_user_info(request)['id'] | ||
619 | data = serializers.MySingerSerializer(models.Users.objects.filter(id=singer_id).first(), many=False,context={"user_id": user_id}).data | ||
620 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
621 | |||
622 | @method_decorator(AuthPermissionRequired()) | ||
623 | def put(self,request): | ||
624 | obj = verification.singer_update(json.loads(request.body)) | ||
625 | logger.info(obj) | ||
626 | if obj.is_valid(): | ||
627 | obj = obj.clean() | ||
628 | singer_id = obj.get('singer_id') | ||
629 | company = obj.get('company') | ||
630 | rate = obj.get('rate') | ||
631 | models.Users.objects.filter(id=singer_id).update(rate=rate,company=company) | ||
632 | return JsonResponse(ResponseFactory(code=200, message="更新成功", data=None, status='success')) | ||
633 | else: | ||
634 | return JsonResponse( | ||
635 | ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
636 | |||
637 | class SingerInfoV2(APIView): | ||
638 | @method_decorator(AuthPermissionRequired()) | ||
639 | def put(self,request): | ||
640 | put_data = json.loads(request.body) | ||
641 | try:obj = verification.singer_updatev2(put_data) | ||
642 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
643 | logger.info(obj) | ||
644 | if not obj.is_valid(): | ||
645 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
646 | obj = obj.clean() | ||
647 | singer_id = obj.get('singer_id') | ||
648 | company = put_data.get('company','') | ||
649 | rate = put_data.get('rate','') | ||
650 | chat_mode = obj.get('chat_mode') | ||
651 | is_all = obj.get('is_all') | ||
652 | user_id = get_user_info(request)['id'] | ||
653 | if chat_mode: | ||
654 | title = '您的私聊模式已改为“队长代理沟通”' | ||
655 | content = '如有疑问,请和队长沟通' | ||
656 | else: | ||
657 | title = '您的私聊模式已改为“成员自主沟通”' | ||
658 | content = '您可以自主进行私聊啦~' | ||
659 | models.Users.objects.filter(id=singer_id).update(rate=rate, company=company) | ||
660 | if not is_all: | ||
661 | models.Users.objects.filter(id=singer_id).update(chat_mode=chat_mode) | ||
662 | # 创建消息 | ||
663 | m_data = {"title": title, "content": content, 'receivers': [singer_id], "activity_id": singer_id, | ||
664 | 'sender_id': user_id, 'type': 11} | ||
665 | else: | ||
666 | models.Users.objects.filter(business_id=user_id,deleted_at=None).update(chat_mode=chat_mode) | ||
667 | all_singer_id = list(models.Users.objects.filter(business_id=user_id,deleted_at=None).values_list('id',flat=True)) | ||
668 | # 创建消息 | ||
669 | m_data = {"title": title, "content": content, 'receivers': all_singer_id, "activity_id": singer_id, | ||
670 | 'sender_id': user_id, 'type': 11} | ||
671 | createMessage(m_data) | ||
672 | return JsonResponse(ResponseFactory(code=200, message="更新成功", data=None, status='success')) | ||
673 | |||
674 | |||
675 | class SingerAvtivity(APIView): | ||
676 | @method_decorator(AuthPermissionRequired()) | ||
677 | def get(self, request): | ||
678 | singer_id = request.GET['singer_id'] | ||
679 | ids = models.ActivityHasUsers.objects.filter(user_id=singer_id,type='Submit',deleted_at=None).values_list('activity_id', flat=True).distinct().order_by('-created_at') | ||
680 | queryset = models.Activitys.objects.filter(id__in=ids) | ||
681 | page_obj = PageNumberPagination() | ||
682 | page_data = page_obj.paginate_queryset(queryset, request) | ||
683 | ser_obj = serializers.MySingerActivitysSerializer(page_data, many=True, context={"user_id": singer_id}) | ||
684 | data = {"activitys": ser_obj.data, "count": queryset.count()} | ||
685 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
686 | |||
687 | class SingerComplete(APIView): | ||
688 | @method_decorator(AuthPermissionRequired()) | ||
689 | def get(self,request): | ||
690 | singer_id = request.GET['singer_id'] | ||
691 | ids = models.ActivityHasUsers.objects.filter(user_id=singer_id, type='Submit',status=1, deleted_at=None).values_list('activity_id', flat=True).distinct().order_by('-updated_at') | ||
692 | activity_id_str = ",".join('%s' % id for id in ids) | ||
693 | queryset = models.Activitys.objects.filter(id__in=ids).extra(select={'m':'FIELD(id,{})'.format(activity_id_str)},order_by=['m']) | ||
694 | page_obj = PageNumberPagination() | ||
695 | page_data = page_obj.paginate_queryset(queryset, request) | ||
696 | ser_obj = serializers.SingerCompleteSerializer(page_data, many=True, context={"user_id": singer_id}) | ||
697 | data = {"activitys": ser_obj.data, "count": queryset.count()} | ||
698 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
699 | |||
700 | class AvtivityDetail(APIView): | ||
701 | @method_decorator(AuthPermissionRequired()) | ||
702 | def get(self,request): | ||
703 | singer_id = request.GET['singer_id'] | ||
704 | activity_id = request.GET['activity_id'] | ||
705 | activity = serializers.SingerActivitysSerializer(models.Activitys.objects.filter(id=activity_id, deleted_at=None).first(), many=False,context={'singer_id': singer_id}) | ||
706 | queryset = models.ActivityHasUsers.objects.filter(user_id=singer_id, activity_id=activity_id,deleted_at=None).order_by('-created_at') | ||
707 | ser_obj = serializers.ManyActivitysHasUserSerializer(queryset, many=True) | ||
708 | data = {'activity': activity.data, 'list': ser_obj.data} | ||
709 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
710 | |||
711 | @AuthPermissionRequired() | ||
712 | def banners(request): | ||
713 | if request.method == 'GET': | ||
714 | user = get_user_info(request) | ||
715 | # sql = """ SELECT * FROM banners where type=2 and status=1 and deleted_at is null and | ||
716 | # json_contains(banners.role,CONCAT('"',"{}",'"')) | ||
717 | # and json_contains(banners.scope,JSON_Array({})) ORDER BY `weight` DESC,`created_at` DESC """.format(user['role'],user['scope']) | ||
718 | |||
719 | sql = """ SELECT * FROM banners where scope=2 and status=1 and deleted_at is null and | ||
720 | json_contains(banners.role,CONCAT('"',"{}",'"')) | ||
721 | ORDER BY `weight` DESC,`created_at` DESC """.format(user['role']) | ||
722 | queset = models.Banners.objects.raw(sql) | ||
723 | ser = serializers.BanneraSerializer(queset,many=True) | ||
724 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=ser.data, status='success')) | ||
725 | else: | ||
726 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
727 | |||
728 | class Listen(APIView): | ||
729 | @method_decorator(AuthPermissionRequired()) | ||
730 | def get(self,request): | ||
731 | user_id = get_user_info(request)['id'] | ||
732 | activity_ids = list(models.UserViewActivity.objects.filter(user_id=user_id, deleted_at=None).values_list('activity_id',flat=True).order_by('-updated_at')) | ||
733 | activity_id_str = ",".join('%s' % id for id in activity_ids) | ||
734 | queset = models.Activitys.objects.filter(id__in=activity_ids,deleted_at=None).extra(select={'m':'FIELD(id,{})'.format(activity_id_str)},order_by=['m']) | ||
735 | page_obj = PageNumberPagination() | ||
736 | page_data = page_obj.paginate_queryset(queset, request) | ||
737 | ser = serializers.ListenActivitysSerializer(page_data,many=True,context={"user_id": user_id}) | ||
738 | data = {"activitys": ser.data, "count":queset.count()} | ||
739 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
740 | |||
741 | class TaCollection(APIView): | ||
742 | @method_decorator(AuthPermissionRequired()) | ||
743 | def get(self,request): | ||
744 | user_id = get_user_info(request)['id'] | ||
745 | #获取关联的歌手id | ||
746 | singer_ids = list(models.Users.objects.filter(business_id=user_id,deleted_at=None).values_list('id',flat=True)) | ||
747 | #获取歌手收藏的活动id | ||
748 | activity_ids = list(models.UserActivityCollections.objects.filter(user_id__in=singer_ids,deleted_at=None).values_list('activity_id',flat=True).order_by('-created_at')) | ||
749 | activity_ids = dedupe(activity_ids) | ||
750 | activity_id_str = ",".join('%s' % id for id in activity_ids) | ||
751 | queset = models.Activitys.objects.filter(id__in=activity_ids ,status=1, deleted_at=None).extra(select={'m': 'FIELD(id,{})'.format(activity_id_str)}, order_by=['m']) | ||
752 | page_obj = PageNumberPagination() | ||
753 | page_data = page_obj.paginate_queryset(queset, request) | ||
754 | ser = serializers.ActivitysCollectionSerializer(page_data, many=True, context={"singer_ids": singer_ids,"user_id":user_id}) | ||
755 | data = {"activitys": ser.data, "count": queset.count()} | ||
756 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
757 | |||
758 | class TaAudition(APIView): | ||
759 | @method_decorator(AuthPermissionRequired()) | ||
760 | def get(self, request): | ||
761 | user_id = get_user_info(request)['id'] | ||
762 | # 获取关联的歌手id | ||
763 | singer_ids = list(models.Users.objects.filter(business_id=user_id, deleted_at=None).values_list('id', flat=True)) | ||
764 | # 获取歌手提交的活动id | ||
765 | activity_ids = list(models.ActivityHasUsers.objects.filter(user_id__in=singer_ids,type='Submit',deleted_at=None).values_list('activity_id', flat=True).order_by('-created_at')) | ||
766 | activity_ids = dedupe(activity_ids) | ||
767 | activity_id_str = ",".join('%s' % id for id in activity_ids) | ||
768 | queset = models.Activitys.objects.filter(id__in=activity_ids, status=1,deleted_at=None).extra(select={'m': 'FIELD(id,{})'.format(activity_id_str)}, order_by=['m']) | ||
769 | page_obj = PageNumberPagination() | ||
770 | page_data = page_obj.paginate_queryset(queset, request) | ||
771 | for page in page_data: | ||
772 | page.ahus = models.ActivityHasUsers.objects.select_related('user__business').filter(user_id__in=singer_ids,type='Submit',activity_id=page.id,deleted_at=None).order_by('-created_at') | ||
773 | ser = serializers.ActivitysSubmitUserSerializer(page_data, many=True, context={"singer_ids": singer_ids,"user_id":user_id}) | ||
774 | data = {"activitys": ser.data, "count": queset.count()} | ||
775 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
776 | |||
777 | class ResumeLike(APIView): | ||
778 | @method_decorator(AuthPermissionRequired()) | ||
779 | def put(self,request): | ||
780 | put_data = json.loads(request.body) | ||
781 | user_id = get_user_info(request)['id'] | ||
782 | activity_id = put_data['activity_id'] | ||
783 | obj = models.UserActivityUnlikes.objects.filter(user_id=user_id,activity_id=activity_id,deleted_at=None) | ||
784 | if obj: | ||
785 | obj.update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
786 | return JsonResponse(ResponseFactory(code=200, message="恢复成功", data=None, status='success')) | ||
787 | else: | ||
788 | return JsonResponse(ResponseFactory(code=201, message="不存在数据", data=None, status='fail')) | ||
789 | |||
790 | @AuthPermissionRequired() | ||
791 | def remove_save(request): | ||
792 | if request.method in ['PUT','DELETE','POST']: | ||
793 | put_data = json.loads(request.body) | ||
794 | models.ActivityHasUsers.objects.filter(id=put_data.get('id')).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
795 | return JsonResponse(ResponseFactory(code=200, message="删除成功", data=None, status='success')) | ||
796 | else: | ||
797 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
798 | |||
799 | |||
800 | @AuthPermissionRequired() | ||
801 | def editor(request): | ||
802 | if request.method == 'PUT': | ||
803 | put_data = json.loads(request.body) | ||
804 | obj = verification.EditorUser(data=put_data) | ||
805 | if not obj.is_valid(): | ||
806 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
807 | user = get_user_info(request) | ||
808 | if user['audit_status'] != 1: | ||
809 | return JsonResponse(ResponseFactory(code=201, message="审核未通过,不允许编辑", data=None, status='fail')) | ||
810 | if put_data == {}: | ||
811 | return JsonResponse(ResponseFactory(code=201, message="参数为空", data=None, status='fail')) | ||
812 | #可更新字段 | ||
813 | field_list = ['nick_name','email','city','avatar','province','company','rate','intro','cover','sex','art_tag','style_tag','wechat_account'] | ||
814 | for key,value in put_data.items(): | ||
815 | # if not value: | ||
816 | # return JsonResponse(ResponseFactory(code=201, message="值不能为空", data=None, status='fail')) | ||
817 | if key in field_list: | ||
818 | if key == 'email':#验证邮箱是否唯一且有效 | ||
819 | reg = "\w+[@][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+" | ||
820 | valid = re.findall(reg, value) | ||
821 | is_exists = models.Users.objects.filter(email=value,deleted_at=None).exclude(id=user['id']).exists() #过滤当前用户,查看邮箱是否重复 | ||
822 | if valid and not is_exists: | ||
823 | pass | ||
824 | else: | ||
825 | return JsonResponse(ResponseFactory(code=201, message="邮箱已注册或格式不正确", data=None, status='fail')) | ||
826 | else: | ||
827 | return JsonResponse(ResponseFactory(code=201, message="不支持字段{}的更新".format(key), data=None, status='fail')) | ||
828 | for key,value in put_data.items(): | ||
829 | if key in ['art_tag','style_tag']: | ||
830 | type = 2 if key == 'art_tag' else 1 | ||
831 | # 删除之前的用户嗓音标签 | ||
832 | models.UserTagRelations.objects.filter(user_id=user['id'], type=type).delete() | ||
833 | # 创建新的用户嗓音标签 | ||
834 | for tag in value: | ||
835 | models.UserTagRelations.objects.create(user_id=user['id'], type=type, tag_id=tag,created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
836 | else: | ||
837 | models.Users.objects.filter(id=user['id'], deleted_at=None).update(**{key: value}) | ||
838 | return JsonResponse(ResponseFactory(code=200, message="更新成功", data=None, status='success')) | ||
839 | else: | ||
840 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
841 | |||
842 | @AuthPermissionRequired() | ||
843 | def ConfirmSinger(request): | ||
844 | """ | ||
845 | 确认合作歌手 | ||
846 | :param request: | ||
847 | :return: | ||
848 | """ | ||
849 | if request.method != 'POST': | ||
850 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
851 | put_data = json.loads(request.body) | ||
852 | obj = verification.ConfirmSingerVerify(put_data) | ||
853 | if obj.is_valid(): | ||
854 | singer_id = obj.clean().get('singer_id') | ||
855 | status = obj.clean().get('status') | ||
856 | activity_id = obj.clean().get('activity_id') | ||
857 | remark = put_data.get('weixin_code',"") | ||
858 | ahu = models.ActivityHasUsers.objects.filter(user_id=singer_id, activity_id=activity_id, type='Submit',status=0, deleted_at=None) | ||
859 | if not ahu: | ||
860 | return JsonResponse(ResponseFactory(code=400, message="不支持的数据,请刷新重试", data=None, status='fail')) | ||
861 | work_id = str(ahu.last().id) | ||
862 | url = "{domain}/app/admin/activity/{work_id}/confirm".format(domain=settings.SERVICE_DOMAOIN,work_id=work_id) | ||
863 | payload = {"status":status,"remark":remark} | ||
864 | headers = { | ||
865 | 'Content-Type': 'application/json', | ||
866 | 'Authorization': request.META.get('HTTP_AUTHORIZATION') | ||
867 | } | ||
868 | resp = requests.request("POST", url, headers=headers, json=payload) | ||
869 | return JsonResponse(ResponseFactory(code=resp.json()['code'], message=resp.json()['message'], data=None, status=resp.json()['status'])) | ||
870 | |||
871 | |||
872 | @AuthPermissionRequired() | ||
873 | def UserDelete(request): | ||
874 | if request.method == 'DELETE': | ||
875 | user_id = get_user_info(request)['id'] | ||
876 | try: | ||
877 | with transaction.atomic(): | ||
878 | #删除用户提交,保存的作品 | ||
879 | # models.ActivityHasUsers.objects.filter(user_id=user_id,deleted_at=None).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
880 | #修改关联歌手聊天设置,解绑歌手 | ||
881 | has_singers = models.Users.objects.filter(business_id=user_id) | ||
882 | if has_singers:has_singers.update(chat_mode=0, business_id=None) | ||
883 | # 删除用户的信息记录 | ||
884 | models.UserMessages.objects.filter(sender_id=user_id,deleted_at=None).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
885 | #解除经纪人关联 | ||
886 | business = models.Users.objects.filter(id=user_id).first() | ||
887 | if business:business_id = business.business_id | ||
888 | else:business_id = 0 | ||
889 | business = models.Users.objects.filter(id=business_id).first() | ||
890 | if business: | ||
891 | models.Users.objects.filter(id=user_id).update(business_id=None) | ||
892 | singer_tag_id = models.SystemConfig.objects.get(identifier='auth_singer_tag').content | ||
893 | business_has_user =list(models.Users.objects.filter(business_id=business_id,status=1,deleted_at=None).exclude(id=user_id).values_list('id',flat=True)) | ||
894 | is_has_singer = models.UserTagRelations.objects.filter(user_id__in=business_has_user,tag_id=singer_tag_id,type=4).exists() | ||
895 | if not is_has_singer: | ||
896 | identity = 1 if business.identity in [1, 3] else 0 | ||
897 | else: | ||
898 | identity = 3 if business.identity in [1, 3] else 2 | ||
899 | models.Users.objects.filter(id=business_id).update(identity=identity) | ||
900 | # 删除待认证信息 | ||
901 | models.UserAuthInfos.objects.filter(user_id=user_id).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
902 | #用户入团申请,邀请信息改为失效 | ||
903 | models.GorupInvites.objects.filter(invite_id=user_id).update(status=4) | ||
904 | models.GorupInvites.objects.filter(user_id=user_id).update(status=4) | ||
905 | |||
906 | #是否存在团 | ||
907 | query = models.GroupHasMembers.objects.filter(member_id=user_id,deleted_at=None).first() | ||
908 | if query: | ||
909 | #是否是团长,团长注销删除团队 | ||
910 | is_master = models.GroupHasMembers.objects.filter(member_id=user_id,role=1, deleted_at=None).exists() | ||
911 | #成员数少于2人,删除团队 | ||
912 | member_count = models.GroupHasMembers.objects.filter(group_id=query.group_id,deleted_at=None).count() | ||
913 | # 删除成员 | ||
914 | models.GroupHasMembers.objects.filter(member_id=user_id, deleted_at=None).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
915 | if (member_count <= 2 or is_master ): | ||
916 | models.Users.objects.filter(business_id=business_id).update(business_id=None) | ||
917 | models.Groups.objects.filter(id=query.group_id).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
918 | models.GroupHasMembers.objects.filter(group_id=query.group_id, deleted_at=None).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
919 | # 删除用户信息 | ||
920 | models.Users.objects.filter(id=user_id).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
921 | return JsonResponse(ResponseFactory(code=200, message="注销完成", data=None, status='success')) | ||
922 | except Exception as e: | ||
923 | return JsonResponse(ResponseFactory(code=201, message='操作失败,请联系管理员', data=None, status='fail')) | ||
924 | else: | ||
925 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
926 | |||
927 | @AuthPermissionRequired() | ||
928 | def change_phone(request): | ||
929 | if request.method == 'PUT': | ||
930 | put_data = json.loads(request.body) | ||
931 | obj = verification.ChangePhoneVrify(put_data) | ||
932 | if obj.is_valid(): | ||
933 | obj = obj.clean() | ||
934 | user = get_user_info(request) | ||
935 | if user['phone'] == obj.get("phone"): | ||
936 | return JsonResponse(ResponseFactory(code=204, message="新手机号码不能与之前手机号码一致", data=None, status='fail')) | ||
937 | check_user = models.Users.objects.filter(phone=int(obj.get("phone")), deleted_at=None).first() | ||
938 | if check_user: | ||
939 | return JsonResponse(ResponseFactory(code=204, message="手机号已被使用", data=None, status='fail')) | ||
940 | mob = caches['default'].get(f'voteapp: polls:valid: {obj.get("phone")}') | ||
941 | is_dev = int(obj.get('sms_code')) == 123456 and settings.ENV == 'dev' | ||
942 | if mob == int(obj.get('sms_code')) or is_dev: | ||
943 | models.Users.objects.filter(id=user['id']).update(phone=obj.get("phone"),area_code=obj.get("area_code")) | ||
944 | caches['default'].delete(f'paopao: polls:valid: {obj.get("phone")}') | ||
945 | return JsonResponse(ResponseFactory(code=200, message="更换成功", data=None, status='success')) | ||
946 | else: | ||
947 | return JsonResponse(ResponseFactory(code=204, message="验证码错误", data=None, status='fail')) | ||
948 | else: | ||
949 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
950 | else: | ||
951 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
952 | |||
953 | |||
954 | class UserPoint(APIView): | ||
955 | @method_decorator(AuthPermissionRequired()) | ||
956 | def put(self,request): | ||
957 | """ | ||
958 | 微信分享积分 | ||
959 | :param request: | ||
960 | :return: | ||
961 | """ | ||
962 | user_id = get_user_info(request)['id'] | ||
963 | user_point_record(user_id,type='ShareSong') | ||
964 | return JsonResponse(ResponseFactory(code=200, message="操作成功", data=None, status='success')) | ||
965 | |||
966 | def sharechildlist(request): | ||
967 | identifier = request.GET['identifier'] | ||
968 | parentobj = models.SystemConfig.objects.filter(identifier=identifier,status=1,deleted_at=None).first() | ||
969 | if parentobj: | ||
970 | data = serializers.SystemConfigSerializer(models.SystemConfig.objects.filter(parent_id=parentobj.id,status=1,deleted_at=None).order_by('-weight'),many=True).data | ||
971 | else: | ||
972 | data = None | ||
973 | if identifier == 'year_limit': | ||
974 | #获取分成年限的时候把较高分成比列也返回 | ||
975 | high_ratio_obj = models.SystemConfig.objects.filter(identifier='high_ratio',status=1,deleted_at=None).first() | ||
976 | high_ratio = serializers.SystemConfigSerializer(high_ratio_obj, many=False).data | ||
977 | data = {"year_limit":data,"high_ratio":high_ratio} | ||
978 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
979 | |||
980 | def sharechild(request): | ||
981 | identifier = request.GET['identifier'] | ||
982 | childobj = models.SystemConfig.objects.filter(identifier=identifier,status=1,deleted_at=None).first() | ||
983 | if childobj: | ||
984 | data = serializers.SystemConfigSerializer(childobj,many=False).data | ||
985 | else: | ||
986 | data = None | ||
987 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
988 | |||
989 | class UserSound(APIView): | ||
990 | @method_decorator(AuthPermissionRequired()) | ||
991 | def put(self,request): | ||
992 | put_data = json.loads(request.body) | ||
993 | obj = verification.UserSound(data=put_data) | ||
994 | if not obj.is_valid(): | ||
995 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
996 | user = get_user_info(request) | ||
997 | user_id = user['id'] | ||
998 | data = obj.data | ||
999 | sound_url = data['sound_url'] | ||
1000 | tags = data['tags'] | ||
1001 | try: | ||
1002 | with transaction.atomic(): | ||
1003 | models.Users.objects.filter(id=user_id).update(sound=sound_url,sound_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
1004 | #删除之前的用户嗓音标签 | ||
1005 | models.UserTagRelations.objects.filter(user_id=user_id, type=3).delete() | ||
1006 | #创建新的用户嗓音标签 | ||
1007 | if tags: | ||
1008 | for tag in tags: | ||
1009 | models.UserTagRelations.objects.create(user_id=user_id,type=3,tag_id=tag, created_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
1010 | return JsonResponse(ResponseFactory(code=200, message="更改完成", data=None, status='success')) | ||
1011 | except Exception as e: | ||
1012 | return JsonResponse(ResponseFactory(code=400, message="编辑失败:{}".format(e), data=None, status='fail')) | ||
1013 | |||
1014 | class UserHome(APIView): | ||
1015 | @method_decorator(AuthPermissionRequired()) | ||
1016 | def get(self,request): | ||
1017 | """ | ||
1018 | 获取用户主页信息 | ||
1019 | :return: | ||
1020 | """ | ||
1021 | try:request_usre_id = get_user_info(request)['id'] | ||
1022 | except:request_usre_id = 0 | ||
1023 | user_id = request.GET['id'] | ||
1024 | if request_usre_id == int(user_id): | ||
1025 | #是否进入主页字段更新 | ||
1026 | models.Users.objects.filter(id=user_id,is_home=0).update(is_home=1) | ||
1027 | else: | ||
1028 | #增加访客记录,不记录游客 | ||
1029 | if request_usre_id != 0: | ||
1030 | models.UserVisitors.objects.create(user_id=user_id, visitor_id=request_usre_id,created_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
1031 | # 获取正在进行的活动id | ||
1032 | activity_ids = list(models.Activitys.objects.filter(status=1, deleted_at=None).values_list('id', flat=True)) | ||
1033 | queryset = models.Users.objects.filter(id=user_id, deleted_at=None).first() | ||
1034 | if queryset:user = serializers.UserHomeSerializer(queryset,many=False,context={"request_usre_id":request_usre_id,"activity_ids":activity_ids}) | ||
1035 | else:return JsonResponse(ResponseFactory(code=400, message='该用户已注销', data=None, status='fail')) | ||
1036 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=user.data, status='success')) | ||
1037 | |||
1038 | class UserTidings(APIView): | ||
1039 | # @method_decorator(AuthPermissionRequired()) | ||
1040 | def get(self,request): | ||
1041 | """ | ||
1042 | 获取用户动态 | ||
1043 | :return: | ||
1044 | """ | ||
1045 | author_id = request.GET['id'] | ||
1046 | try: | ||
1047 | user = get_user_info(request) | ||
1048 | user_id = user['id'] | ||
1049 | scope = user['scope'] | ||
1050 | except: | ||
1051 | user_id = 0 | ||
1052 | scope = 0 | ||
1053 | # if int(author_id) == user_id or scope -=1: | ||
1054 | if int(author_id) == user_id or scope == 1: | ||
1055 | #所有动态 | ||
1056 | queset = models.UserHasTidings.objects.filter(user_id=author_id,deleted_at=None).order_by('-created_at') | ||
1057 | else: | ||
1058 | # 未被限流动态 | ||
1059 | queset = models.UserHasTidings.objects.filter(user_id=author_id,status=0,deleted_at=None).order_by('-created_at') | ||
1060 | page_obj = PageNumberPagination() | ||
1061 | page_data = page_obj.paginate_queryset(queset, request) | ||
1062 | tidings = serializers.CommunityTidingsSerializer(page_data,many=True,context={'user_id':user_id}) | ||
1063 | data = {"data":tidings.data,"count":queset.count()} | ||
1064 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
1065 | |||
1066 | @method_decorator(AuthPermissionRequired()) | ||
1067 | def post(self,request): | ||
1068 | try: | ||
1069 | post_data = json.loads(request.body) | ||
1070 | except: | ||
1071 | return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
1072 | obj = verification.TidingsDeleteVerify(data=post_data) | ||
1073 | if not obj.is_valid(): | ||
1074 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1075 | tidings_id = obj.data.get('tidings_id') | ||
1076 | tidings = models.UserHasTidings.objects.filter(id=tidings_id,deleted_at=None).first() | ||
1077 | auther = models.Users.objects.filter(id=tidings.user_id).first() | ||
1078 | if not tidings: | ||
1079 | return JsonResponse(ResponseFactory(code=400, message="不存在此动态", data=None, status='fail')) | ||
1080 | user_id = get_user_info(request)['id'] | ||
1081 | if tidings.user_id != user_id: | ||
1082 | return JsonResponse(ResponseFactory(code=400, message="只能删除自己的动态", data=None, status='fail')) | ||
1083 | #删除动态 | ||
1084 | models.UserHasTidings.objects.filter(id=tidings_id).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
1085 | if auther.id != user_id: | ||
1086 | # 极光推送 | ||
1087 | j_title = "您发布的动态被平台删除" | ||
1088 | if tidings.type == 2: | ||
1089 | activity = models.Activitys.objects.filter(id=tidings.activity_id).first() | ||
1090 | content = "《{}》{}".format(activity.song_name, auther.nick_name) | ||
1091 | elif tidings.type == 3: | ||
1092 | tidings_has_content = serializers.SystemMsgTidingsSerializer(tidings, many=False).data | ||
1093 | content = "{}".format(tidings.title) | ||
1094 | for recommend_activity in tidings_has_content['recommend_activitys']: | ||
1095 | content = content + "[试唱活动《{}》]".format(recommend_activity['song_name']) | ||
1096 | for recommend_singer in tidings_has_content['recommend_singers']: | ||
1097 | content = content + "[{}的名片]".format(recommend_singer['nick_name']) | ||
1098 | if tidings_has_content['photos']: | ||
1099 | content = content + "[图片]" | ||
1100 | if tidings_has_content['sounds']: | ||
1101 | content = content + "[音频]" | ||
1102 | jdata = {"title": j_title, "content": content, "content_type": "text", | ||
1103 | "receiver_value": [tidings.user_id], | ||
1104 | "extras": {"type": "ToSystemMsg", "value": ""}} | ||
1105 | JPush().jpush_v3(jdata) | ||
1106 | # 服务号推送 | ||
1107 | wechat_data = models.WechatOfficialUsers.objects.filter(union_id=auther.unionid).first() | ||
1108 | if wechat_data: | ||
1109 | p_data = {'channel': 'square_result', 'open_id': [wechat_data.open_id], | ||
1110 | 'data': {"first": j_title, "keyword1": content, | ||
1111 | "keyword2": str(tidings.created_at), 'keyword3': auther.nick_name} | ||
1112 | } | ||
1113 | pushSubscribeMessage(p_data) | ||
1114 | return JsonResponse(ResponseFactory(code=200, message="删除成功", data=None, status='success')) | ||
1115 | |||
1116 | |||
1117 | class UserFollow(APIView): | ||
1118 | @method_decorator(AuthPermissionRequired()) | ||
1119 | def get(self,request): | ||
1120 | """ | ||
1121 | 获取用户粉丝列表 | ||
1122 | :return: | ||
1123 | """ | ||
1124 | user_id = request.GET['id'] | ||
1125 | text = request.GET.get('text', '') | ||
1126 | follower_ids = models.UserFollowRelations.objects.filter(following_id=user_id,deleted_at=None).order_by('-created_at').values_list('follower_id',flat=True) | ||
1127 | follower_ids_str = ",".join('%s' % id for id in follower_ids) | ||
1128 | kwargs = {"id__in":follower_ids,"status":1,"deleted_at":None} | ||
1129 | if text: | ||
1130 | kwargs['nick_name__icontains'] = text | ||
1131 | queset = models.Users.objects.filter(**kwargs).extra(select={'m': 'FIELD(id,{})'.format(follower_ids_str)}, order_by=['m']) | ||
1132 | page_obj = PageNumberPagination() | ||
1133 | page_data = page_obj.paginate_queryset(queset, request) | ||
1134 | data = serializers.UserFollowSerializer(page_data,many=True,context={"user_id":user_id}).data | ||
1135 | #关注全部已读 | ||
1136 | models.UserFollowRelations.objects.filter(following_id=user_id, is_read=0).update(is_read=1) | ||
1137 | data = {"follows":data,"count":queset.count()} | ||
1138 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
1139 | |||
1140 | @method_decorator(AuthPermissionRequired()) | ||
1141 | def post(self,request): | ||
1142 | """ | ||
1143 | 关注 | ||
1144 | :param request: | ||
1145 | :return: | ||
1146 | """ | ||
1147 | post_data = json.loads(request.body) | ||
1148 | obj = verification.CreataFollow(data=post_data) | ||
1149 | if not obj.is_valid(): | ||
1150 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1151 | user_id = get_user_info(request)['id'] | ||
1152 | following_id = obj.data.get('following_id') | ||
1153 | if user_id == following_id: | ||
1154 | return JsonResponse(ResponseFactory(code=400, message="关注失败,您无法关注自己~", data=None, status='fail')) | ||
1155 | models.UserFollowRelations.objects.update_or_create(follower_id=user_id,following_id=following_id,deleted_at=None,defaults={"created_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"),"updated_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S")}) | ||
1156 | return JsonResponse(ResponseFactory(code=200, message="已关注", data=None, status='success')) | ||
1157 | |||
1158 | @method_decorator(AuthPermissionRequired()) | ||
1159 | def put(self,request): | ||
1160 | """ | ||
1161 | 取消关注 | ||
1162 | :param request: | ||
1163 | :return: | ||
1164 | """ | ||
1165 | post_data = json.loads(request.body) | ||
1166 | obj = verification.CreataFollow(data = post_data) | ||
1167 | if not obj.is_valid(): | ||
1168 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1169 | user_id = get_user_info(request)['id'] | ||
1170 | following_id = obj.data.get('following_id') | ||
1171 | models.UserFollowRelations.objects.filter(follower_id=user_id,following_id=following_id,deleted_at=None).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
1172 | return JsonResponse(ResponseFactory(code=200, message="已取消关注", data=None, status='success')) | ||
1173 | |||
1174 | |||
1175 | class UserFollowing(APIView): | ||
1176 | @method_decorator(AuthPermissionRequired()) | ||
1177 | def get(self,request): | ||
1178 | """ | ||
1179 | 获取关注列表 | ||
1180 | :return: | ||
1181 | """ | ||
1182 | user_id = request.GET['id'] | ||
1183 | text = request.GET.get('text', '') | ||
1184 | following_ids = models.UserFollowRelations.objects.filter(follower_id=user_id,deleted_at=None).order_by('-created_at').values_list('following_id',flat=True) | ||
1185 | following_ids_str = ",".join('%s' % id for id in following_ids) | ||
1186 | if text: | ||
1187 | queset = models.Users.objects.filter(id__in=following_ids, nick_name__icontains=text,status=1, deleted_at=None).extra(select={'m': 'FIELD(id,{})'.format(following_ids_str)}, order_by=['m']) | ||
1188 | else: | ||
1189 | queset = models.Users.objects.filter(id__in=following_ids,status=1,deleted_at=None).extra(select={'m': 'FIELD(id,{})'.format(following_ids_str)}, order_by=['m']) | ||
1190 | page_obj = PageNumberPagination() | ||
1191 | page_data = page_obj.paginate_queryset(queset, request) | ||
1192 | following = serializers.UserFollowingSerializer(page_data,many=True,context={"user_id":user_id}) | ||
1193 | data = {"following":following.data,"count":queset.count()} | ||
1194 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
1195 | |||
1196 | |||
1197 | class FindSinger(APIView): | ||
1198 | @method_decorator(AuthPermissionRequired()) | ||
1199 | def get(self,request): | ||
1200 | kwargs = {'role':'Singer','status':1,'audit_status':1,'deleted_at':None} | ||
1201 | orderbyList = ['-sound_at'] | ||
1202 | text = request.GET.get('text','') | ||
1203 | sound_tags_id = eval(request.GET.get('sound_tags_id','[]')) | ||
1204 | style_tags_id = eval(request.GET.get('style_tags_id','[]')) | ||
1205 | submit_sound_tag_user = models.UserTagRelations.objects.filter(type=3).values_list('user_id', flat=True) | ||
1206 | if text: | ||
1207 | kwargs['id__in'] = submit_sound_tag_user | ||
1208 | queryset = models.Users.objects.filter(~Q(sound=''),Q(nick_name__icontains=text)|Q(real_name__icontains=text),**kwargs).order_by(*orderbyList) | ||
1209 | else: | ||
1210 | sound_user = models.UserTagRelations.objects.filter(type=3,tag_id__in=sound_tags_id).values_list('user_id', flat=True) | ||
1211 | style_user = models.UserTagRelations.objects.filter( type=1,tag_id__in=style_tags_id).values_list('user_id', flat=True) | ||
1212 | #取交集 | ||
1213 | if len(sound_tags_id) > 0 and len(style_tags_id) > 0:user_ids = [v for v in style_user if v in sound_user] | ||
1214 | elif len(sound_tags_id) == 0 and len(style_tags_id) > 0:user_ids = [v for v in style_user if v in submit_sound_tag_user] | ||
1215 | elif len(sound_tags_id) > 0 and len(style_tags_id) == 0:user_ids = sound_user | ||
1216 | else:user_ids = submit_sound_tag_user | ||
1217 | kwargs['id__in'] = user_ids | ||
1218 | queryset = models.Users.objects.filter(~Q(sound=''), **kwargs).order_by(*orderbyList) | ||
1219 | page_obj = PageNumberPagination() | ||
1220 | page_data = page_obj.paginate_queryset(queryset, request) | ||
1221 | ser_obj = serializers.FindSingerSerializer(page_data, many=True) | ||
1222 | data = {"singers":ser_obj.data,"count":queryset.count()} | ||
1223 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
1224 | |||
1225 | |||
1226 | class CustomerService(APIView): | ||
1227 | @method_decorator(AuthPermissionRequired()) | ||
1228 | def get(self,request): | ||
1229 | obj = models.SystemConfig.objects.filter(identifier='customer_service', status=1, deleted_at=None).first() | ||
1230 | id = obj.remark | ||
1231 | queryset = models.Users.objects.filter(id=id).first() | ||
1232 | ser_obj = serializers.CustomerUserSerializer(queryset, many=False) | ||
1233 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=ser_obj.data, status='success')) | ||
1234 | |||
1235 | class Visitors(APIView): | ||
1236 | @method_decorator(AuthPermissionRequired()) | ||
1237 | def get(self,request): | ||
1238 | user_id = get_user_info(request)['id'] | ||
1239 | # 获取当前日期和时间 | ||
1240 | now = timezone.now() | ||
1241 | # 计算 30 天前的日期和时间 | ||
1242 | thirty_days_ago = now - timedelta(days=30) | ||
1243 | visitor_ids = list(models.UserVisitors.objects.filter(user_id=user_id,created_at__gte=thirty_days_ago).order_by('-created_at').values_list('visitor_id',flat=True)) | ||
1244 | visitor_ids = sorted(set(visitor_ids), key=visitor_ids.index) | ||
1245 | visitor_ids_str = ",".join('%s' % id for id in visitor_ids) | ||
1246 | queryset = models.Users.objects.filter(id__in=visitor_ids).extra(select={'m':'FIELD(id,{})'.format(visitor_ids_str)},order_by=['m']) | ||
1247 | page_obj = PageNumberPagination() | ||
1248 | page_data = page_obj.paginate_queryset(queryset, request) | ||
1249 | ser_obj = serializers.VisitorUserSerializer(page_data, many=True,context={'user_id':user_id}) | ||
1250 | data = {"visitors": ser_obj.data,"count":len(visitor_ids)} | ||
1251 | # 访客都已读 | ||
1252 | models.UserVisitors.objects.filter(user_id=user_id, is_read=0).update(is_read=1) | ||
1253 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
1254 | |||
1255 | class RemoveDevice(APIView): | ||
1256 | @method_decorator(AuthPermissionRequired()) | ||
1257 | def get(self,request): | ||
1258 | user_id = get_user_info(request)['id'] | ||
1259 | remove_alias_device(user_id) | ||
1260 | return JsonResponse(ResponseFactory(code=200, message="处理成功", data=None, status='success')) | ||
1261 | |||
1262 | class AvtivitysPrice(APIView): | ||
1263 | @method_decorator(AuthPermissionRequired()) | ||
1264 | def put(self,request): | ||
1265 | try:post_data = json.loads(request.body) | ||
1266 | except:return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail')) | ||
1267 | obj = verification.AvtivitysPriceVerification(data=post_data) | ||
1268 | if not obj.is_valid(): | ||
1269 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
1270 | if obj.data.get('value')['amounts']: | ||
1271 | if not (0 <= obj.data.get('value')['amounts'] <= 9999999): return JsonResponse( | ||
1272 | ResponseFactory(code=201, message="金额在0-9999999之间", data=None, status='fail')) | ||
1273 | if obj.data.get('value')['ratio']: | ||
1274 | if not (0 <= obj.data.get('value')['ratio'] <= 100): return JsonResponse( | ||
1275 | ResponseFactory(code=201, message="分成比列在0%-100%之间", data=None, status='fail')) | ||
1276 | user_id = get_user_info(request)['id'] | ||
1277 | activity_id = obj.data.get('activity_id') | ||
1278 | models.ActivityUserHasPrices.objects.update_or_create( | ||
1279 | activity_id = activity_id, | ||
1280 | user_id = user_id, | ||
1281 | defaults = { | ||
1282 | "value" :obj.data.get('value'), | ||
1283 | "is_deduct" :obj.data.get('is_deduct'), | ||
1284 | "is_talk" :obj.data.get('is_talk'), | ||
1285 | "address_id" :obj.data.get('address_id'), | ||
1286 | "is_accept_address" :obj.data.get('is_accept_address'), | ||
1287 | "created_at" :timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
1288 | "updated_at" :timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
1289 | ) | ||
1290 | return JsonResponse(ResponseFactory(code=200, message="修改成功", data=None, status='success')) | ||
1291 | |||
1292 | |||
1293 | |||
1294 | |||
1295 | class AvtivitysPriceInfo(APIView): | ||
1296 | @method_decorator(AuthPermissionRequired()) | ||
1297 | def get(self, request): | ||
1298 | activity_id = request.GET.get('activity_id') | ||
1299 | user_id = get_user_info(request)['id'] | ||
1300 | queryset = models.ActivityUserHasPrices.objects.filter(activity_id=activity_id,user_id=user_id).first() | ||
1301 | if queryset:data = serializers.ActivitysPriceSerializer(queryset, many=False,context={'activity_id':activity_id}).data | ||
1302 | else: | ||
1303 | queryset = models.ActivityUserHasPrices.objects.filter(user_id=user_id).order_by('updated_at').last() | ||
1304 | if queryset:data = serializers.ActivitysPriceSerializer(queryset, many=False,context={'activity_id':activity_id}).data | ||
1305 | else: data = None | ||
1306 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data={"price_info":data}, status='success')) | ||
1307 | |||
1308 |
api/ApiList/notifications.py
0 → 100644
1 | from api.views import AuthPermissionRequired,get_user_info | ||
2 | from django.http import JsonResponse | ||
3 | from api.views import ResponseFactory,PageNumberPagination,GetWxToken,pushSubscribeMessage,WeChatApi,JPush | ||
4 | from rest_framework.decorators import api_view | ||
5 | from api import models,verification,serializers | ||
6 | import json | ||
7 | from django.utils.decorators import method_decorator | ||
8 | from rest_framework.views import APIView | ||
9 | |||
10 | |||
11 | def push_notifications(request): | ||
12 | if request.method != "POST": | ||
13 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
14 | post_data = json.loads(request.body) | ||
15 | obj = verification.PushNotifications(post_data) | ||
16 | if not obj.is_valid(): | ||
17 | return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail')) | ||
18 | obj = obj.clean() | ||
19 | jdata = {"title": obj.get('title'), "content": obj.get('content'), "content_type": "text", | ||
20 | "receiver_value": obj.get('receivers'), | ||
21 | "extras": {"type": post_data.get('type',""), "value": post_data.get('value',"")}} | ||
22 | result = JPush().jpush_v3(jdata) | ||
23 | return JsonResponse(result) | ||
24 | |||
25 | @AuthPermissionRequired() | ||
26 | def read(request): | ||
27 | put_data = json.loads(request.body) | ||
28 | user_id = get_user_info(request)['id'] | ||
29 | if request.method == "PUT": | ||
30 | type = put_data.get('type') | ||
31 | #我的歌手审核消息已读 | ||
32 | if type == 1: | ||
33 | models.UserMessages.objects.filter(type=type,receiver_id=user_id,sender_id=put_data['sender_id'],deleted_at=None).update(is_read=1) | ||
34 | return JsonResponse(ResponseFactory(code=200, message="已阅读", data=None, status='success')) | ||
35 | # 我的歌手收藏消息已读 | ||
36 | elif type == 2: | ||
37 | models.UserMessages.objects.filter(type=type,receiver_id=user_id,deleted_at=None).update(is_read=1) | ||
38 | return JsonResponse(ResponseFactory(code=200, message="已阅读", data=None, status='success')) | ||
39 | # 我的歌手或平台用户试唱消息已读(注意区分是绑定用户,还是平台用户) | ||
40 | elif type == 3: | ||
41 | models.UserMessages.objects.filter(type=type,sender_id=put_data['sender_id'],receiver_id=user_id,activity_id=put_data['activity_id'],is_bind=put_data['is_bind'],deleted_at=None).update(is_read=1) | ||
42 | return JsonResponse(ResponseFactory(code=200, message="已阅读", data=None, status='success')) | ||
43 | #系统消息已读 | ||
44 | elif type == 4: | ||
45 | models.UserMessages.objects.filter(type__in=[4,5,6,7,8,9,10,11,12,13,14], receiver_id=user_id, deleted_at=None).update(is_read=1) | ||
46 | return JsonResponse(ResponseFactory(code=200, message="已阅读", data=None, status='success')) | ||
47 | else: | ||
48 | return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail')) | ||
49 | |||
50 | |||
51 | class SystemMessage(APIView): | ||
52 | @method_decorator(AuthPermissionRequired()) | ||
53 | def get(self,request): | ||
54 | user_id = get_user_info(request)['id'] | ||
55 | queryset = models.UserMessages.objects.filter(type__in=[4,5,6,7,8,9,10,11,12,13,14],receiver_id=user_id,deleted_at=None).order_by('-created_at') | ||
56 | page_obj = PageNumberPagination() | ||
57 | page_data = page_obj.paginate_queryset(queryset, request) | ||
58 | ser_obj = serializers.SystemMessageSerializer(page_data, many=True) | ||
59 | data = {"message": ser_obj.data, "count": queryset.count()} | ||
60 | return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success')) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/TLSSigAPIv2.py
0 → 100644
1 | #! /usr/bin/python | ||
2 | # coding:utf-8 | ||
3 | |||
4 | |||
5 | import hmac | ||
6 | import hashlib | ||
7 | import base64 | ||
8 | import zlib | ||
9 | import json | ||
10 | import time | ||
11 | |||
12 | |||
13 | def base64_encode_url(data): | ||
14 | """ base url encode 实现""" | ||
15 | base64_data = base64.b64encode(data) | ||
16 | base64_data_str = bytes.decode(base64_data) | ||
17 | base64_data_str = base64_data_str.replace('+', '*') | ||
18 | base64_data_str = base64_data_str.replace('/', '-') | ||
19 | base64_data_str = base64_data_str.replace('=', '_') | ||
20 | return base64_data_str | ||
21 | |||
22 | |||
23 | def base64_decode_url(base64_data): | ||
24 | """ base url decode 实现""" | ||
25 | base64_data_str = bytes.decode(base64_data) | ||
26 | base64_data_str = base64_data_str.replace('*', '+') | ||
27 | base64_data_str = base64_data_str.replace('-', '/') | ||
28 | base64_data_str = base64_data_str.replace('_', '=') | ||
29 | raw_data = base64.b64decode(base64_data_str) | ||
30 | return raw_data | ||
31 | |||
32 | |||
33 | class TLSSigAPIv2: | ||
34 | __sdkappid = 0 | ||
35 | __version = '2.0' | ||
36 | __key = "" | ||
37 | |||
38 | def __init__(self, sdkappid, key): | ||
39 | self.__sdkappid = sdkappid | ||
40 | self.__key = key | ||
41 | |||
42 | ##用于生成实时音视频(TRTC)业务进房权限加密串,具体用途用法参考TRTC文档:https://cloud.tencent.com/document/product/647/32240 | ||
43 | # TRTC业务进房权限加密串需使用用户定义的userbuf | ||
44 | # @brief 生成 userbuf | ||
45 | # @param account 用户名 | ||
46 | # @param dwSdkappid sdkappid | ||
47 | # @param dwAuthID 数字房间号 | ||
48 | # @param dwExpTime 过期时间:该权限加密串的过期时间,实际过期时间:当前时间+dwExpTime | ||
49 | # @param dwPrivilegeMap 用户权限,255表示所有权限 | ||
50 | # @param dwAccountType 用户类型,默认为0 | ||
51 | # @param roomStr 字符串房间号,数字房间号非0时存在 | ||
52 | # @return userbuf {string} 返回的userbuf | ||
53 | # / | ||
54 | |||
55 | ##It is used to generate real-time audio and video (TRTC) business access rights encryption string. For specific usage, please refer to the TRTC document:https://cloud.tencent.com/document/product/647/32240 | ||
56 | # User-defined userbuf is used for the encrypted string of TRTC service entry permission | ||
57 | # @brief generate userbuf | ||
58 | # @param account username | ||
59 | # @param dwSdkappid sdkappid | ||
60 | # @param dwAuthID digital room number | ||
61 | # @param dwExpTime Expiration time: The expiration time of the encrypted string of this permission. Expiration time = now+dwExpTime | ||
62 | # @param dwPrivilegeMap User permissions, 255 means all permissions | ||
63 | # @param dwAccountType User type, default is 0 | ||
64 | # @param roomStr String room number | ||
65 | # @return userbuf string returned userbuf | ||
66 | # / | ||
67 | |||
68 | def _gen_userbuf(self, account, dwAuthID, dwExpTime, | ||
69 | dwPrivilegeMap, dwAccountType, roomStr): | ||
70 | userBuf = b'' | ||
71 | |||
72 | if len(roomStr) > 0: | ||
73 | userBuf += bytearray([1]) | ||
74 | else: | ||
75 | userBuf += bytearray([0]) | ||
76 | |||
77 | userBuf += bytearray([ | ||
78 | ((len(account) & 0xFF00) >> 8), | ||
79 | (len(account) & 0x00FF), | ||
80 | ]) | ||
81 | userBuf += bytearray(map(ord, account)) | ||
82 | |||
83 | # dwSdkAppid | ||
84 | userBuf += bytearray([ | ||
85 | ((self.__sdkappid & 0xFF000000) >> 24), | ||
86 | ((self.__sdkappid & 0x00FF0000) >> 16), | ||
87 | ((self.__sdkappid & 0x0000FF00) >> 8), | ||
88 | (self.__sdkappid & 0x000000FF), | ||
89 | ]) | ||
90 | |||
91 | # dwAuthId | ||
92 | userBuf += bytearray([ | ||
93 | ((dwAuthID & 0xFF000000) >> 24), | ||
94 | ((dwAuthID & 0x00FF0000) >> 16), | ||
95 | ((dwAuthID & 0x0000FF00) >> 8), | ||
96 | (dwAuthID & 0x000000FF), | ||
97 | ]) | ||
98 | |||
99 | # dwExpTime = now + 300; | ||
100 | expire = dwExpTime + int(time.time()) | ||
101 | userBuf += bytearray([ | ||
102 | ((expire & 0xFF000000) >> 24), | ||
103 | ((expire & 0x00FF0000) >> 16), | ||
104 | ((expire & 0x0000FF00) >> 8), | ||
105 | (expire & 0x000000FF), | ||
106 | ]) | ||
107 | |||
108 | # dwPrivilegeMap | ||
109 | userBuf += bytearray([ | ||
110 | ((dwPrivilegeMap & 0xFF000000) >> 24), | ||
111 | ((dwPrivilegeMap & 0x00FF0000) >> 16), | ||
112 | ((dwPrivilegeMap & 0x0000FF00) >> 8), | ||
113 | (dwPrivilegeMap & 0x000000FF), | ||
114 | ]) | ||
115 | |||
116 | # dwAccountType | ||
117 | userBuf += bytearray([ | ||
118 | ((dwAccountType & 0xFF000000) >> 24), | ||
119 | ((dwAccountType & 0x00FF0000) >> 16), | ||
120 | ((dwAccountType & 0x0000FF00) >> 8), | ||
121 | (dwAccountType & 0x000000FF), | ||
122 | ]) | ||
123 | if len(roomStr) > 0: | ||
124 | userBuf += bytearray([ | ||
125 | ((len(roomStr) & 0xFF00) >> 8), | ||
126 | (len(roomStr) & 0x00FF), | ||
127 | ]) | ||
128 | userBuf += bytearray(map(ord, roomStr)) | ||
129 | return userBuf | ||
130 | |||
131 | def __hmacsha256(self, identifier, curr_time, expire, base64_userbuf=None): | ||
132 | """ 通过固定串进行 hmac 然后 base64 得的 sig 字段的值""" | ||
133 | raw_content_to_be_signed = "TLS.identifier:" + str(identifier) + "\n" \ | ||
134 | + "TLS.sdkappid:" + str(self.__sdkappid) + "\n" \ | ||
135 | + "TLS.time:" + str(curr_time) + "\n" \ | ||
136 | + "TLS.expire:" + str(expire) + "\n" | ||
137 | if None != base64_userbuf: | ||
138 | raw_content_to_be_signed += "TLS.userbuf:" + base64_userbuf + "\n" | ||
139 | return base64.b64encode(hmac.new(self.__key.encode('utf-8'), | ||
140 | raw_content_to_be_signed.encode('utf-8'), | ||
141 | hashlib.sha256).digest()) | ||
142 | |||
143 | def __gen_sig(self, identifier, expire=180 * 86400, userbuf=None): | ||
144 | """ 用户可以采用默认的有效期生成 sig """ | ||
145 | curr_time = int(time.time()) | ||
146 | m = dict() | ||
147 | m["TLS.ver"] = self.__version | ||
148 | m["TLS.identifier"] = str(identifier) | ||
149 | m["TLS.sdkappid"] = int(self.__sdkappid) | ||
150 | m["TLS.expire"] = int(expire) | ||
151 | m["TLS.time"] = int(curr_time) | ||
152 | base64_userbuf = None | ||
153 | if None != userbuf: | ||
154 | base64_userbuf = bytes.decode(base64.b64encode(userbuf)) | ||
155 | m["TLS.userbuf"] = base64_userbuf | ||
156 | |||
157 | m["TLS.sig"] = bytes.decode(self.__hmacsha256( | ||
158 | identifier, curr_time, expire, base64_userbuf)) | ||
159 | |||
160 | raw_sig = json.dumps(m) | ||
161 | sig_cmpressed = zlib.compress(raw_sig.encode('utf-8')) | ||
162 | base64_sig = base64_encode_url(sig_cmpressed) | ||
163 | return base64_sig | ||
164 | |||
165 | ## | ||
166 | # 【功能说明】用于签发 TRTC 和 IM 服务中必须要使用的 UserSig 鉴权票据 | ||
167 | # | ||
168 | # 【参数说明】 | ||
169 | # userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。 | ||
170 | # expire - UserSig 票据的过期时间,单位是秒,比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了。 | ||
171 | # / | ||
172 | |||
173 | # Function: Used to issue UserSig that is required by the TRTC and IM services. | ||
174 | |||
175 | # Parameter description: | ||
176 | # userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-). | ||
177 | # expire - UserSig expiration time, in seconds. For example, 86400 indicates that the generated UserSig will expire one day after being generated. | ||
178 | |||
179 | def genUserSig(self, userid, expire=180 * 86400): | ||
180 | """ 用户可以采用默认的有效期生成 sig """ | ||
181 | return self.__gen_sig(userid, expire, None) | ||
182 | |||
183 | ## | ||
184 | # 【功能说明】 | ||
185 | # 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。 | ||
186 | # PrivateMapKey 需要跟 UserSig 一起使用,但比 UserSig 有更强的权限控制能力: | ||
187 | # - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。 | ||
188 | # - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。 | ||
189 | # 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中“启动权限密钥”。 | ||
190 | # | ||
191 | # 【参数说明】 | ||
192 | # userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。 | ||
193 | # expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。 | ||
194 | # roomid - 房间号,用于指定该 userid 可以进入的房间号 | ||
195 | # privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限: | ||
196 | # - 第 1 位:0000 0001 = 1,创建房间的权限 | ||
197 | # - 第 2 位:0000 0010 = 2,加入房间的权限 | ||
198 | # - 第 3 位:0000 0100 = 4,发送语音的权限 | ||
199 | # - 第 4 位:0000 1000 = 8,接收语音的权限 | ||
200 | # - 第 5 位:0001 0000 = 16,发送视频的权限 | ||
201 | # - 第 6 位:0010 0000 = 32,接收视频的权限 | ||
202 | # - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限 | ||
203 | # - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限 | ||
204 | # - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。 | ||
205 | # - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。 | ||
206 | # / | ||
207 | |||
208 | # Function: | ||
209 | # Used to issue PrivateMapKey that is optional for room entry. | ||
210 | # PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities. | ||
211 | # - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room. | ||
212 | # - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room. | ||
213 | # To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info. | ||
214 | # * | ||
215 | # Parameter description: | ||
216 | # userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-). | ||
217 | # roomid - ID of the room to which the specified UserID can enter. | ||
218 | # expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated. | ||
219 | # privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features: | ||
220 | # - Bit 1: 0000 0001 = 1, permission for room creation | ||
221 | # - Bit 2: 0000 0010 = 2, permission for room entry | ||
222 | # - Bit 3: 0000 0100 = 4, permission for audio sending | ||
223 | # - Bit 4: 0000 1000 = 8, permission for audio receiving | ||
224 | # - Bit 5: 0001 0000 = 16, permission for video sending | ||
225 | # - Bit 6: 0010 0000 = 32, permission for video receiving | ||
226 | # - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing) | ||
227 | # - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing) | ||
228 | # - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid. | ||
229 | # - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data. | ||
230 | |||
231 | def genPrivateMapKey(self, userid, expire, roomid, privilegeMap): | ||
232 | """ 带 userbuf 生成签名 """ | ||
233 | userbuf = self._gen_userbuf(userid, roomid, expire, privilegeMap, 0, "") | ||
234 | print(userbuf) | ||
235 | return self.__gen_sig(userid, expire, userbuf) | ||
236 | |||
237 | ## | ||
238 | # 【功能说明】 | ||
239 | # 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。 | ||
240 | # PrivateMapKey 需要跟 UserSig 一起使用,但比 UserSig 有更强的权限控制能力: | ||
241 | # - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。 | ||
242 | # - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。 | ||
243 | # 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中“启动权限密钥”。 | ||
244 | # | ||
245 | # 【参数说明】 | ||
246 | # userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。 | ||
247 | # expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。 | ||
248 | # roomstr - 字符串房间号,用于指定该 userid 可以进入的房间号 | ||
249 | # privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限: | ||
250 | # - 第 1 位:0000 0001 = 1,创建房间的权限 | ||
251 | # - 第 2 位:0000 0010 = 2,加入房间的权限 | ||
252 | # - 第 3 位:0000 0100 = 4,发送语音的权限 | ||
253 | # - 第 4 位:0000 1000 = 8,接收语音的权限 | ||
254 | # - 第 5 位:0001 0000 = 16,发送视频的权限 | ||
255 | # - 第 6 位:0010 0000 = 32,接收视频的权限 | ||
256 | # - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限 | ||
257 | # - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限 | ||
258 | # - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。 | ||
259 | # - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。 | ||
260 | # / | ||
261 | |||
262 | # Function: | ||
263 | # Used to issue PrivateMapKey that is optional for room entry. | ||
264 | # PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities. | ||
265 | # - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room. | ||
266 | # - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room. | ||
267 | # To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info. | ||
268 | # * | ||
269 | # Parameter description: | ||
270 | # @param userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-). | ||
271 | # @param roomstr - ID of the room to which the specified UserID can enter. | ||
272 | # @param expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated. | ||
273 | # @param privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features: | ||
274 | # - Bit 1: 0000 0001 = 1, permission for room creation | ||
275 | # - Bit 2: 0000 0010 = 2, permission for room entry | ||
276 | # - Bit 3: 0000 0100 = 4, permission for audio sending | ||
277 | # - Bit 4: 0000 1000 = 8, permission for audio receiving | ||
278 | # - Bit 5: 0001 0000 = 16, permission for video sending | ||
279 | # - Bit 6: 0010 0000 = 32, permission for video receiving | ||
280 | # - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing) | ||
281 | # - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing) | ||
282 | # - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid. | ||
283 | # - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data. | ||
284 | def genPrivateMapKeyWithStringRoomID(self, userid, expire, roomstr, privilegeMap): | ||
285 | """ 带 userbuf 生成签名 """ | ||
286 | userbuf = self._gen_userbuf(userid, 0, expire, privilegeMap, 0, roomstr) | ||
287 | print(userbuf) | ||
288 | return self.__gen_sig(userid, expire, userbuf) | ||
289 | |||
290 | |||
291 | def main(): | ||
292 | api = TLSSigAPIv2(1400752528, "a68603354e10d70dc0e8b834da884f383ebc21180a382dac79efd1194b77f1b7") | ||
293 | sig = api.genUserSig("administrator") | ||
294 | print(sig) | ||
295 | sig = api.genPrivateMapKey("xiaojun", 86400 * 180, 10000, 255) | ||
296 | print(sig) | ||
297 | # sig = api.genPrivateMapKeyWithStringRoomID("xiaojun", 86400*180,"adbjkl",255) | ||
298 | # print(sig) | ||
299 | |||
300 | |||
301 | if __name__ == "__main__": | ||
302 | main() | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/__init__.py
0 → 100644
File mode changed
api/admin.py
0 → 100644
1 | from django.contrib import admin |
api/apps.py
0 → 100644
api/jobs/__init__.py
0 → 100644
File mode changed
api/jobs/job.py
0 → 100644
File mode changed
api/loggin.py
0 → 100644
api/middleware/ApiLoggingMiddleware.py
0 → 100644
1 | import jwt | ||
2 | import json | ||
3 | from HisinApi import settings | ||
4 | from api.models import SystemHttpLogs | ||
5 | from django.utils import timezone | ||
6 | from api.views import object_to_json | ||
7 | import time | ||
8 | from api.loggin import logger | ||
9 | |||
10 | |||
11 | |||
12 | class ApiLogs(object): | ||
13 | |||
14 | def __init__(self, get_response): | ||
15 | self.get_response = get_response | ||
16 | |||
17 | def __call__(self, request): | ||
18 | response = self.get_response(request) | ||
19 | try: | ||
20 | body = json.loads(request.body.decode('utf-8')) | ||
21 | except: | ||
22 | body = {} | ||
23 | header = object_to_json(request.headers)['_store'] | ||
24 | if request.method == 'GET': | ||
25 | query = request.GET | ||
26 | else: | ||
27 | query = request.POST | ||
28 | request_data = {"body":body,"header":header,"query":query} | ||
29 | try:body = json.loads( response._container[0].decode('utf-8')) | ||
30 | except: body = None | ||
31 | response_data = {"body":body, "header": object_to_json(response.headers)['_store'],"code":response.status_code} | ||
32 | try: | ||
33 | try: | ||
34 | auth = request.META.get('HTTP_AUTHORIZATION').split() | ||
35 | dict = jwt.decode(auth[1], settings.SECRET_KEY, algorithms=['HS256']) | ||
36 | user_id = dict.get('data').get('id') | ||
37 | except: | ||
38 | user_id = 0 | ||
39 | SystemHttpLogs( | ||
40 | guard='App', | ||
41 | user_id=user_id, | ||
42 | method=request.method, | ||
43 | uri=request.path, | ||
44 | ip=request.META['REMOTE_ADDR'], | ||
45 | request=request_data, | ||
46 | response=response_data, | ||
47 | consume =response.headers['time'], | ||
48 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")).save() | ||
49 | except Exception as e: | ||
50 | logger.info('API Log Error:{}'.format(e)) | ||
51 | return response | ||
52 | |||
53 | |||
54 | class ResponseTime: | ||
55 | def __init__(self, get_response): | ||
56 | self.get_response = get_response | ||
57 | |||
58 | def __call__(self, request): | ||
59 | start_time = time.time() | ||
60 | response = self.get_response(request) | ||
61 | duration = time.time() - start_time | ||
62 | response["time"] = int(duration * 1000) | ||
63 | return response | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/models.py
0 → 100644
1 | # This is an auto-generated Django model module. | ||
2 | # You'll have to do the following manually to clean this up: | ||
3 | # * Rearrange models' order | ||
4 | # * Make sure each model has one field with primary_key=True | ||
5 | # * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior | ||
6 | # * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table | ||
7 | # Feel free to rename the models, but don't rename db_table values or field names. | ||
8 | from django.db import models | ||
9 | from django.contrib.auth.models import AbstractBaseUser | ||
10 | from datetime import datetime,timedelta | ||
11 | import jwt | ||
12 | from HisinApi import settings | ||
13 | |||
14 | class UserDynamics(models.Model): | ||
15 | user_id = models.IntegerField(default=0) | ||
16 | type = models.CharField(max_length=255) | ||
17 | intro = models.CharField(max_length=255) | ||
18 | properties = models.JSONField() | ||
19 | is_top = models.IntegerField(default=0) | ||
20 | created_at = models.DateTimeField(blank=True, null=True) | ||
21 | updated_at = models.DateTimeField(blank=True, null=True) | ||
22 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
23 | |||
24 | class Meta: | ||
25 | managed = False | ||
26 | db_table = 'user_dynamics' | ||
27 | |||
28 | class BrokerUserConfigs(models.Model): | ||
29 | title = models.CharField(default='',max_length=255) | ||
30 | begin_at = models.DateTimeField(blank=True, null=True) | ||
31 | end_at = models.DateTimeField(blank=True, null=True) | ||
32 | user_id = models.IntegerField(default=0) | ||
33 | push_type = models.IntegerField(default=0) | ||
34 | push_at = models.DateTimeField(blank=True, null=True) | ||
35 | created_at = models.DateTimeField(blank=True, null=True) | ||
36 | updated_at = models.DateTimeField(blank=True, null=True) | ||
37 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
38 | |||
39 | class Meta: | ||
40 | managed = False | ||
41 | db_table = 'broker_user_configs' | ||
42 | |||
43 | |||
44 | class BrokerUserConfigItems(models.Model): | ||
45 | user_id = models.IntegerField(default=0) | ||
46 | config = models.ForeignKey(BrokerUserConfigs, on_delete=models.CASCADE) | ||
47 | identifier = models.CharField(default='',max_length=255) | ||
48 | singer_num = models.IntegerField(default=0) | ||
49 | status = models.IntegerField(default=0) | ||
50 | created_at = models.DateTimeField(blank=True, null=True) | ||
51 | updated_at = models.DateTimeField(blank=True, null=True) | ||
52 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
53 | |||
54 | class Meta: | ||
55 | managed = False | ||
56 | db_table = 'broker_user_config_items' | ||
57 | |||
58 | |||
59 | class ProjectHasMembers(models.Model): | ||
60 | invite_id = models.IntegerField(default=0) | ||
61 | user_id = models.IntegerField(default=0) | ||
62 | project_id = models.IntegerField(default=0) | ||
63 | status = models.IntegerField(default=0) | ||
64 | is_top = models.IntegerField(default=0) | ||
65 | created_at = models.DateTimeField(blank=True, null=True) | ||
66 | updated_at = models.DateTimeField(blank=True, null=True) | ||
67 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
68 | |||
69 | class Meta: | ||
70 | managed = False | ||
71 | db_table = 'project_has_members' | ||
72 | |||
73 | class ProjectVisitors(models.Model): | ||
74 | project_id = models.IntegerField(default=0) | ||
75 | user_id = models.IntegerField(default=0) | ||
76 | created_at = models.DateTimeField(blank=True, null=True) | ||
77 | updated_at = models.DateTimeField(blank=True, null=True) | ||
78 | class Meta: | ||
79 | managed = False | ||
80 | db_table = 'project_visitors' | ||
81 | |||
82 | |||
83 | class UserManageActivitie(models.Model): | ||
84 | user_id = models.IntegerField(default=0) | ||
85 | activity_id = models.IntegerField(default=0) | ||
86 | project_id = models.IntegerField(default=0) | ||
87 | activity_publish_at = models.DateTimeField(blank=True, null=True) | ||
88 | activity_status = models.IntegerField(default=0) | ||
89 | permission = models.JSONField() | ||
90 | |||
91 | class Meta: | ||
92 | managed = False | ||
93 | db_table = 'user_manage_activities' | ||
94 | |||
95 | |||
96 | class GorupInvites(models.Model): | ||
97 | group_id = models.IntegerField(default=0) | ||
98 | invite_id = models.IntegerField(default=0) | ||
99 | user_id = models.IntegerField(default=0) | ||
100 | type = models.IntegerField(default=1) | ||
101 | status = models.IntegerField(default=0) | ||
102 | created_at = models.DateTimeField(blank=True, null=True) | ||
103 | updated_at = models.DateTimeField(blank=True, null=True) | ||
104 | |||
105 | class Meta: | ||
106 | managed = False | ||
107 | db_table = 'group_invites' | ||
108 | |||
109 | |||
110 | class GroupHasMembers(models.Model): | ||
111 | group_id = models.IntegerField(default=0) | ||
112 | member_id = models.IntegerField(default=0) | ||
113 | is_top = models.IntegerField(default=0) | ||
114 | role = models.IntegerField(default=3) | ||
115 | status = models.IntegerField(default=1) | ||
116 | created_at = models.DateTimeField(blank=True, null=True) | ||
117 | updated_at = models.DateTimeField(blank=True, null=True) | ||
118 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
119 | |||
120 | class Meta: | ||
121 | managed = False | ||
122 | db_table = 'group_has_members' | ||
123 | |||
124 | |||
125 | class Groups(models.Model): | ||
126 | user_id = models.IntegerField(default=0) | ||
127 | created_at = models.DateTimeField(blank=True, null=True) | ||
128 | updated_at = models.DateTimeField(blank=True, null=True) | ||
129 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
130 | |||
131 | class Meta: | ||
132 | managed = False | ||
133 | db_table = 'groups' | ||
134 | |||
135 | class SystemSmsLogs(models.Model): | ||
136 | gateway = models.CharField(max_length=80) | ||
137 | phone = models.CharField(max_length=255) | ||
138 | content = models.JSONField() | ||
139 | result = models.JSONField() | ||
140 | status = models.CharField(max_length=80) | ||
141 | created_at = models.DateTimeField(blank=True, null=True) | ||
142 | updated_at = models.DateTimeField(blank=True, null=True) | ||
143 | class Meta: | ||
144 | managed = False | ||
145 | db_table = 'system_sms_logs' | ||
146 | |||
147 | class UserAuthInfos(models.Model): | ||
148 | user_id = models.IntegerField(default=0) | ||
149 | nick_name = models.CharField(max_length=80) | ||
150 | platform = models.JSONField() | ||
151 | works = models.CharField(max_length=255) | ||
152 | img = models.JSONField() | ||
153 | tags = models.JSONField() | ||
154 | audio_info = models.JSONField() | ||
155 | reason = models.TextField() | ||
156 | status = models.IntegerField(default=0) | ||
157 | created_at = models.DateTimeField(blank=True, null=True) | ||
158 | updated_at = models.DateTimeField(blank=True, null=True) | ||
159 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
160 | class Meta: | ||
161 | managed = False | ||
162 | db_table = 'user_auth_infos' | ||
163 | |||
164 | class ActivityLinks(models.Model): | ||
165 | activity_id = models.IntegerField(default=0) | ||
166 | type = models.CharField(max_length=80) | ||
167 | link_type = models.CharField(max_length=255) | ||
168 | link_id = models.CharField(max_length=32) | ||
169 | class Meta: | ||
170 | managed = False | ||
171 | db_table = 'activity_links' | ||
172 | |||
173 | class ProjectConfirmationTime(models.Model): | ||
174 | """厂牌确认合作时间""" | ||
175 | project_id = models.IntegerField(default=0) | ||
176 | average_day = models.FloatField() | ||
177 | created_at = models.DateTimeField(blank=True, null=True) | ||
178 | updated_at = models.DateTimeField(blank=True, null=True) | ||
179 | class Meta: | ||
180 | managed = False | ||
181 | db_table = 'project_confirmation_times' | ||
182 | |||
183 | class CountryRegions(models.Model): | ||
184 | """地区信息""" | ||
185 | parent_id = models.IntegerField(default=0) | ||
186 | country_id = models.IntegerField(default=0) | ||
187 | identifier = models.CharField(max_length=255) | ||
188 | name = models.CharField(max_length=255) | ||
189 | code = models.CharField(max_length=255) | ||
190 | weight = models.IntegerField(default=1) | ||
191 | status = models.IntegerField(max_length=255) | ||
192 | created_at = models.DateTimeField(blank=True, null=True) | ||
193 | updated_at = models.DateTimeField(blank=True, null=True) | ||
194 | |||
195 | class Meta: | ||
196 | managed = False | ||
197 | db_table = 'country_regions' | ||
198 | |||
199 | |||
200 | class ActivityUserHasPrices(models.Model): | ||
201 | """自主报价""" | ||
202 | user_id = models.IntegerField(default=0) | ||
203 | activity_id = models.IntegerField(default=0) | ||
204 | value = models.JSONField() | ||
205 | is_deduct = models.IntegerField(default=0) | ||
206 | is_talk = models.IntegerField(default=0) | ||
207 | address_id = models.CharField(max_length=255) | ||
208 | is_accept_address = models.IntegerField(default=0) | ||
209 | created_at = models.DateTimeField(blank=True, null=True) | ||
210 | updated_at = models.DateTimeField(blank=True, null=True) | ||
211 | |||
212 | class Meta: | ||
213 | managed = False | ||
214 | db_table = 'activity_user_has_prices' | ||
215 | |||
216 | |||
217 | class SystemHttpLogs(models.Model): | ||
218 | """接口日志""" | ||
219 | guard = models.CharField(default='Other',max_length=255) | ||
220 | user_id = models.IntegerField(default=0) | ||
221 | method = models.CharField(default='GET',max_length=255) | ||
222 | uri = models.CharField(max_length=500) | ||
223 | ip = models.CharField(max_length=255) | ||
224 | request = models.JSONField() | ||
225 | response = models.JSONField() | ||
226 | consume = models.FloatField() | ||
227 | created_at = models.DateTimeField(blank=True, null=True) | ||
228 | class Meta: | ||
229 | managed = False | ||
230 | db_table = 'system_http_logs' | ||
231 | |||
232 | class TidingsHasComments(models.Model): | ||
233 | """动态评论""" | ||
234 | tidings_id = models.IntegerField(default=0) | ||
235 | parent_id = models.IntegerField(default=0) | ||
236 | user_id = models.IntegerField(default=0) | ||
237 | content = models.TextField() | ||
238 | created_at = models.DateTimeField(blank=True, null=True) | ||
239 | updated_at = models.DateTimeField(blank=True, null=True) | ||
240 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
241 | class Meta: | ||
242 | managed = False | ||
243 | db_table = 'tidings_has_comments' | ||
244 | |||
245 | |||
246 | class UserChatAgentRecords(models.Model): | ||
247 | """设置私聊代理,聊天关系""" | ||
248 | user_id = models.IntegerField(default=0) | ||
249 | send_id = models.IntegerField(default=0) | ||
250 | business_id = models.IntegerField(default=0) | ||
251 | created_at = models.DateTimeField(blank=True, null=True) | ||
252 | updated_at = models.DateTimeField(blank=True, null=True) | ||
253 | class Meta: | ||
254 | managed = False | ||
255 | db_table = 'user_chatagent_records' | ||
256 | |||
257 | |||
258 | class UserUnlikeTidings(models.Model): | ||
259 | """用户不感兴趣的动态""" | ||
260 | user_id = models.IntegerField(default=0) | ||
261 | tidings_id = models.IntegerField(default=0) | ||
262 | created_at = models.DateTimeField(blank=True, null=True) | ||
263 | updated_at = models.DateTimeField(blank=True, null=True) | ||
264 | class Meta: | ||
265 | managed = False | ||
266 | db_table = 'user_unlike_tidings' | ||
267 | |||
268 | class ActivityHasRecommends(models.Model): | ||
269 | """活动确定分享人""" | ||
270 | activity_id = models.IntegerField(default=0) | ||
271 | type = models.IntegerField(default=0) | ||
272 | content = models.TextField() | ||
273 | created_at = models.DateTimeField(blank=True, null=True) | ||
274 | updated_at = models.DateTimeField(blank=True, null=True) | ||
275 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
276 | class Meta: | ||
277 | managed = False | ||
278 | db_table = 'activity_has_recommends' | ||
279 | |||
280 | |||
281 | class UserVisitors(models.Model): | ||
282 | """活动确定分享人""" | ||
283 | user_id = models.IntegerField(default=0) | ||
284 | visitor_id = models.IntegerField(default=0) | ||
285 | is_read = models.IntegerField(default=0) | ||
286 | created_at = models.DateTimeField(blank=True, null=True) | ||
287 | updated_at = models.DateTimeField(blank=True, null=True) | ||
288 | class Meta: | ||
289 | managed = False | ||
290 | db_table = 'user_visitors' | ||
291 | |||
292 | class ActivityShareUsers(models.Model): | ||
293 | """活动确定分享人""" | ||
294 | activity_id = models.IntegerField(default=0) | ||
295 | user_id = models.IntegerField(default=0) | ||
296 | share_id = models.IntegerField(default=0) | ||
297 | created_at = models.DateTimeField(blank=True, null=True) | ||
298 | updated_at = models.DateTimeField(blank=True, null=True) | ||
299 | class Meta: | ||
300 | managed = False | ||
301 | db_table = 'activity_share_users' | ||
302 | |||
303 | class TidingsHasChat(models.Model): | ||
304 | tidings_id = models.IntegerField(default=0) | ||
305 | user_id = models.IntegerField(default=0) | ||
306 | created_at = models.DateTimeField(blank=True, null=True) | ||
307 | updated_at = models.DateTimeField(blank=True, null=True) | ||
308 | class Meta: | ||
309 | managed = False | ||
310 | db_table = 'tidings_has_chat' | ||
311 | |||
312 | |||
313 | class UserViewTidings(models.Model): | ||
314 | """动态活动""" | ||
315 | tidings_id = models.IntegerField(default=0) | ||
316 | user_id = models.IntegerField(default=0) | ||
317 | created_at = models.DateTimeField(blank=True, null=True) | ||
318 | updated_at = models.DateTimeField(blank=True, null=True) | ||
319 | class Meta: | ||
320 | managed = False | ||
321 | db_table = 'user_view_tidings' | ||
322 | |||
323 | |||
324 | class TidingsHasReports(models.Model): | ||
325 | """举报""" | ||
326 | tidings_id = models.IntegerField(default=0) | ||
327 | comment_id = models.IntegerField(default=0) | ||
328 | person_id = models.IntegerField(default=0) | ||
329 | user_id = models.IntegerField(default=0) | ||
330 | reason = models.TextField() | ||
331 | desc = models.TextField(default=None) | ||
332 | type = models.IntegerField(default=1) | ||
333 | status = models.IntegerField(default=0) | ||
334 | created_at = models.DateTimeField(blank=True, null=True) | ||
335 | updated_at = models.DateTimeField(blank=True, null=True) | ||
336 | class Meta: | ||
337 | managed = False | ||
338 | db_table = 'tidings_has_reports' | ||
339 | |||
340 | class TidingsHasInteracts(models.Model): | ||
341 | """动态活动""" | ||
342 | type_id = models.IntegerField(default=0) | ||
343 | type = models.IntegerField(default=1) | ||
344 | user_id = models.IntegerField(default=0) | ||
345 | status = models.IntegerField(default=1) | ||
346 | created_at = models.DateTimeField(blank=True, null=True) | ||
347 | updated_at = models.DateTimeField(blank=True, null=True) | ||
348 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
349 | class Meta: | ||
350 | managed = False | ||
351 | db_table = 'tidings_has_interacts' | ||
352 | |||
353 | class TidingsHasContents(models.Model): | ||
354 | """动态关联的内容""" | ||
355 | tidings_id = models.IntegerField(default=0) | ||
356 | type = models.IntegerField(default=1) | ||
357 | value = models.CharField(max_length=400,default='') | ||
358 | created_at = models.DateTimeField(blank=True, null=True) | ||
359 | updated_at = models.DateTimeField(blank=True, null=True) | ||
360 | class Meta: | ||
361 | managed = False | ||
362 | db_table = 'tidings_has_contents' | ||
363 | |||
364 | class UserHasTidings(models.Model): | ||
365 | # user_id = models.IntegerField(default=0) | ||
366 | user = models.OneToOneField('Users',on_delete=models.DO_NOTHING) | ||
367 | title = models.TextField() | ||
368 | activity_id = models.IntegerField(default=0) | ||
369 | type = models.IntegerField(default=0) | ||
370 | url = models.CharField(max_length=400,default='') | ||
371 | status = models.IntegerField(default=0) | ||
372 | is_top = models.IntegerField(default=0) | ||
373 | created_at = models.DateTimeField(blank=True, null=True) | ||
374 | updated_at = models.DateTimeField(blank=True, null=True) | ||
375 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
376 | class Meta: | ||
377 | managed = False | ||
378 | db_table = 'user_has_tidings' | ||
379 | |||
380 | |||
381 | class UserFollowRelations(models.Model): | ||
382 | follower_id = models.IntegerField(default=0) | ||
383 | following_id = models.IntegerField(default=0) | ||
384 | is_read = models.IntegerField(default=0) | ||
385 | created_at = models.DateTimeField(blank=True, null=True) | ||
386 | updated_at = models.DateTimeField(blank=True, null=True) | ||
387 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
388 | class Meta: | ||
389 | managed = False | ||
390 | db_table = 'user_follow_relations' | ||
391 | |||
392 | |||
393 | class UserTagRelations(models.Model): | ||
394 | user_id = models.IntegerField(default=0) | ||
395 | tag_id = models.IntegerField(default=0) | ||
396 | type = models.IntegerField(max_length=255) | ||
397 | created_at = models.DateTimeField(blank=True, null=True) | ||
398 | updated_at = models.DateTimeField(blank=True, null=True) | ||
399 | class Meta: | ||
400 | managed = False | ||
401 | db_table = 'user_tag_relations' | ||
402 | |||
403 | class SystemConfig(models.Model): | ||
404 | creator_id = models.IntegerField(default=0) | ||
405 | parent_id = models.IntegerField(default=0) | ||
406 | name = models.CharField(max_length=255) | ||
407 | identifier = models.CharField(max_length=255) | ||
408 | content = models.TextField() | ||
409 | expand = models.JSONField() | ||
410 | status = models.CharField(max_length=255) | ||
411 | weight = models.IntegerField(max_length=255) | ||
412 | remark = models.TextField() | ||
413 | created_at = models.DateTimeField(blank=True, null=True) | ||
414 | updated_at = models.DateTimeField(blank=True, null=True) | ||
415 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
416 | class Meta: | ||
417 | managed = False | ||
418 | db_table = 'system_config' | ||
419 | |||
420 | class AppVersion(models.Model): | ||
421 | app_ver = models.CharField(default=None,max_length=255) | ||
422 | app_no = models.CharField(default=None,max_length=255) | ||
423 | os = models.CharField(default=None,max_length=255) | ||
424 | url = models.CharField(default=None,max_length=512) | ||
425 | remark = models.CharField(default=None,max_length=1024) | ||
426 | is_force = models.IntegerField(default=None) | ||
427 | user_id = models.IntegerField(default=None) | ||
428 | created_at = models.DateTimeField(blank=True, null=True) | ||
429 | updated_at = models.DateTimeField(blank=True, null=True) | ||
430 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
431 | class Meta: | ||
432 | managed = False | ||
433 | db_table = 'app_version' | ||
434 | |||
435 | |||
436 | class UserHasProjects(models.Model): | ||
437 | user_id = models.IntegerField(default=0) | ||
438 | project_id = models.IntegerField(default=0) | ||
439 | class Meta: | ||
440 | managed = False | ||
441 | db_table = 'user_has_projects' | ||
442 | |||
443 | |||
444 | class UserPoints(models.Model): | ||
445 | type = models.CharField(max_length=50,default=None) | ||
446 | point = models.IntegerField(default=0) | ||
447 | user_id = models.IntegerField(default=0) | ||
448 | singer_id = models.IntegerField(default=0) | ||
449 | activity_id = models.IntegerField(default=0) | ||
450 | created_at = models.DateTimeField(blank=True, null=True) | ||
451 | updated_at = models.DateTimeField(blank=True, null=True) | ||
452 | class Meta: | ||
453 | managed = False | ||
454 | db_table = 'user_points' | ||
455 | |||
456 | class UserMessages(models.Model): | ||
457 | title = models.CharField(max_length=255,default="") | ||
458 | content = models.TextField() | ||
459 | sender_id = models.IntegerField(default=0) | ||
460 | receiver_id = models.IntegerField(default=0) | ||
461 | activity_id = models.IntegerField(default=0) | ||
462 | type = models.IntegerField(default=0) | ||
463 | is_read = models.IntegerField(default=0) | ||
464 | is_bind = models.IntegerField(default=0) | ||
465 | created_at = models.DateTimeField(blank=True, null=True) | ||
466 | updated_at = models.DateTimeField(blank=True, null=True) | ||
467 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
468 | class Meta: | ||
469 | managed = False | ||
470 | db_table = 'user_messages' | ||
471 | |||
472 | |||
473 | |||
474 | class Actions(models.Model): | ||
475 | event_name = models.CharField(max_length=255) | ||
476 | open_id = models.CharField(max_length=255) | ||
477 | user_id = models.IntegerField(default=0) | ||
478 | activity_id = models.IntegerField(default=0) | ||
479 | start_at = models.DateTimeField(blank=True, null=True) | ||
480 | end_at = models.DateTimeField(blank=True, null=True) | ||
481 | # time = models.IntegerField(default=None) | ||
482 | created_at = models.DateTimeField(blank=True, null=True) | ||
483 | updated_at = models.DateTimeField(blank=True, null=True) | ||
484 | class Meta: | ||
485 | managed = False | ||
486 | db_table = 'actions' | ||
487 | |||
488 | class Events(models.Model): | ||
489 | event_name = models.CharField(max_length=255,primary_key='event_name') | ||
490 | event_title = models.CharField(max_length=255) | ||
491 | event_intro = models.CharField(max_length=255) | ||
492 | event_path = models.CharField(max_length=255) | ||
493 | |||
494 | class Meta: | ||
495 | managed = False | ||
496 | db_table = 'events' | ||
497 | |||
498 | class UserActivityUnlikes(models.Model): | ||
499 | user_id = models.IntegerField(default=0) | ||
500 | activity_id = models.IntegerField(default=0) | ||
501 | created_at = models.DateTimeField(blank=True, null=True) | ||
502 | updated_at = models.DateTimeField(blank=True, null=True) | ||
503 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
504 | class Meta: | ||
505 | managed = False | ||
506 | db_table = 'user_activity_unlikes' | ||
507 | |||
508 | class UserActivityCollections(models.Model): | ||
509 | user_id = models.IntegerField(default=0) | ||
510 | activity_id = models.IntegerField(default=0) | ||
511 | created_at = models.DateTimeField(blank=True, null=True) | ||
512 | updated_at = models.DateTimeField(blank=True, null=True) | ||
513 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
514 | class Meta: | ||
515 | managed = False | ||
516 | db_table = 'user_activity_collections' | ||
517 | |||
518 | class WechatOfficialUsers(models.Model): | ||
519 | open_id = models.CharField(max_length=255) | ||
520 | union_id = models.CharField(max_length=255) | ||
521 | is_subscribe = models.IntegerField() | ||
522 | created_at = models.DateTimeField(blank=True, null=True) | ||
523 | updated_at = models.DateTimeField(blank=True, null=True) | ||
524 | |||
525 | class Meta: | ||
526 | managed = False | ||
527 | db_table = 'wechat_official_users' | ||
528 | |||
529 | |||
530 | class MixinPreviews(models.Model): | ||
531 | user_id = models.IntegerField() | ||
532 | activity_id = models.IntegerField() | ||
533 | url = models.CharField(max_length=255) | ||
534 | syn_status = models.IntegerField(default=0) | ||
535 | created_at = models.DateTimeField(blank=True, null=True) | ||
536 | updated_at = models.DateTimeField(blank=True, null=True) | ||
537 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
538 | |||
539 | class Meta: | ||
540 | managed = False | ||
541 | db_table = 'mixin_previews' | ||
542 | |||
543 | |||
544 | class ActivityHasUsers(models.Model): | ||
545 | # activity_id = models.IntegerField() | ||
546 | activity = models.ForeignKey('Activitys',related_name="activityhasusers",on_delete=models.DO_NOTHING) | ||
547 | # user_id = models.IntegerField() | ||
548 | user = models.OneToOneField('Users',related_name="has_user",on_delete=models.DO_NOTHING) | ||
549 | broker_id = models.IntegerField(default=0) | ||
550 | broker_level = models.CharField(max_length=255,default='') | ||
551 | demo_url = models.CharField(max_length=255) | ||
552 | wav_url = models.CharField(max_length=255,default='',blank=True, null=True) | ||
553 | wav_durations = models.FloatField(default=0,blank=True, null=True) | ||
554 | durations = models.FloatField(default=0) | ||
555 | type = models.CharField(max_length=6, blank=True, null=True) | ||
556 | status = models.IntegerField(blank=True, null=True) | ||
557 | syn_status = models.IntegerField() | ||
558 | syn_data = models.JSONField() | ||
559 | is_checked = models.IntegerField(default=0) | ||
560 | mode = models.IntegerField(blank=True, null=True) | ||
561 | open_id = models.CharField(max_length=255) | ||
562 | submit_at = models.DateTimeField(blank=True, null=True) | ||
563 | is_hide = models.IntegerField(default=1) | ||
564 | version = models.IntegerField() | ||
565 | sing_type = models.CharField(default=None,max_length=50) | ||
566 | created_at = models.DateTimeField(blank=True, null=True) | ||
567 | updated_at = models.DateTimeField(blank=True, null=True) | ||
568 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
569 | |||
570 | class Meta: | ||
571 | managed = False | ||
572 | db_table = 'activity_has_users' | ||
573 | |||
574 | |||
575 | class ActivityMaterials(models.Model): | ||
576 | activity_id = models.IntegerField() | ||
577 | type = models.CharField(max_length=12) | ||
578 | url = models.CharField(max_length=255) | ||
579 | tone = models.CharField(max_length=255) | ||
580 | created_at = models.DateTimeField(blank=True, null=True) | ||
581 | updated_at = models.DateTimeField(blank=True, null=True) | ||
582 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
583 | |||
584 | class Meta: | ||
585 | managed = False | ||
586 | db_table = 'activity_materials' | ||
587 | |||
588 | |||
589 | class Activitys(models.Model): | ||
590 | song_type = models.IntegerField(blank=True, null=True) | ||
591 | sub_title = models.CharField(max_length=255) | ||
592 | song_name = models.CharField(max_length=255) | ||
593 | cover = models.CharField(max_length=255) | ||
594 | user_id = models.IntegerField(blank=True, null=True) | ||
595 | project = models.OneToOneField("Projects", null=True,related_name="has_project",on_delete=models.DO_NOTHING) | ||
596 | lyric = models.TextField(blank=True, null=True) | ||
597 | clip_lyric = models.TextField() | ||
598 | guide = models.CharField(max_length=400) | ||
599 | guide_duration = models.IntegerField() | ||
600 | guide_clip = models.CharField(max_length=400) | ||
601 | guide_clip_duration = models.IntegerField() | ||
602 | karaoke = models.CharField(max_length=400) | ||
603 | karaoke_clip = models.CharField(max_length=400) | ||
604 | send_url = models.JSONField() | ||
605 | weight = models.IntegerField(blank=True, null=True) | ||
606 | r_weight = models.IntegerField(blank=True, null=True) | ||
607 | r_status=models.IntegerField(blank=True, null=True) | ||
608 | status = models.IntegerField(blank=True, null=True) | ||
609 | is_official = models.IntegerField(default=0) | ||
610 | is_recommend = models.IntegerField(default=0) | ||
611 | sex = models.CharField(max_length=255) | ||
612 | mark = models.CharField(max_length=255) | ||
613 | speed = models.CharField(max_length=255) | ||
614 | lang = models.JSONField() | ||
615 | expand = models.JSONField() | ||
616 | audit_status = models.IntegerField(blank=True, null=True) | ||
617 | estimate_release_at = models.DateField() | ||
618 | publish_at = models.DateTimeField(blank=True, null=True) | ||
619 | p_is_top = models.IntegerField(default=0) | ||
620 | created_at = models.DateTimeField(blank=True, null=True) | ||
621 | updated_at = models.DateTimeField(blank=True, null=True) | ||
622 | match_at = models.DateTimeField(blank=True, null=True) | ||
623 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
624 | |||
625 | class Meta: | ||
626 | managed = False | ||
627 | db_table = 'activitys' | ||
628 | |||
629 | class Banners(models.Model): | ||
630 | name = models.CharField(max_length=255) | ||
631 | cover = models.CharField(max_length=255) | ||
632 | content_picture = models.CharField(max_length=255) | ||
633 | role = models.JSONField() | ||
634 | weight = models.CharField(max_length=255) | ||
635 | status = models.IntegerField(blank=True, null=True) | ||
636 | type = models.IntegerField(blank=True, null=True) | ||
637 | scope = models.IntegerField() | ||
638 | content = models.JSONField() | ||
639 | created_at = models.DateTimeField(blank=True, null=True) | ||
640 | updated_at = models.DateTimeField(blank=True, null=True) | ||
641 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
642 | |||
643 | class Meta: | ||
644 | managed = False | ||
645 | db_table = 'banners' | ||
646 | |||
647 | |||
648 | class Projects(models.Model): | ||
649 | name = models.CharField(max_length=255) | ||
650 | cover = models.CharField(max_length=400) | ||
651 | intro = models.CharField(max_length=255) | ||
652 | user_id = models.IntegerField() | ||
653 | master_id = models.IntegerField() | ||
654 | status = models.IntegerField(blank=True, null=True) | ||
655 | is_promote = models.IntegerField(default=0) | ||
656 | weight = models.IntegerField(default=0) | ||
657 | r_status = models.IntegerField(default=0) | ||
658 | r_weight = models.IntegerField(default=0) | ||
659 | is_public = models.IntegerField() | ||
660 | created_at = models.DateTimeField(blank=True, null=True) | ||
661 | updated_at = models.DateTimeField(blank=True, null=True) | ||
662 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
663 | |||
664 | class Meta: | ||
665 | managed = False | ||
666 | db_table = 'projects' | ||
667 | |||
668 | |||
669 | class SystemBusiness(models.Model): | ||
670 | nick_name = models.CharField(max_length=255) | ||
671 | real_name = models.CharField(max_length=255) | ||
672 | user_id = models.IntegerField() | ||
673 | created_at = models.DateTimeField(blank=True, null=True) | ||
674 | updated_at = models.DateTimeField(blank=True, null=True) | ||
675 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
676 | |||
677 | class Meta: | ||
678 | managed = False | ||
679 | db_table = 'system_business' | ||
680 | |||
681 | |||
682 | class SystemLogs(models.Model): | ||
683 | id = models.IntegerField(primary_key=True) | ||
684 | user_id = models.IntegerField() | ||
685 | model = models.CharField(max_length=255) | ||
686 | type = models.CharField(max_length=255) | ||
687 | text = models.CharField(max_length=255, blank=True, null=True) | ||
688 | created_at = models.DateTimeField(blank=True, null=True) | ||
689 | updated_at = models.DateTimeField(blank=True, null=True) | ||
690 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
691 | |||
692 | class Meta: | ||
693 | managed = False | ||
694 | db_table = 'system_logs' | ||
695 | |||
696 | |||
697 | class SystemTags(models.Model): | ||
698 | name = models.CharField(max_length=255) | ||
699 | user_id = models.IntegerField() | ||
700 | type = models.IntegerField() | ||
701 | weight = models.IntegerField(default=0) | ||
702 | expand = models.JSONField() | ||
703 | is_show = models.IntegerField(default=1) | ||
704 | created_at = models.DateTimeField(blank=True, null=True) | ||
705 | updated_at = models.DateTimeField(blank=True, null=True) | ||
706 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
707 | |||
708 | class Meta: | ||
709 | managed = False | ||
710 | db_table = 'system_tags' | ||
711 | |||
712 | |||
713 | class UserExamines(models.Model): | ||
714 | user_id = models.IntegerField() | ||
715 | admin_id = models.IntegerField() | ||
716 | business_id = models.IntegerField() | ||
717 | open_id = models.CharField(max_length=255,blank=True, null=True) | ||
718 | type = models.CharField(max_length=255, blank=True, null=True) | ||
719 | examine_info = models.CharField(max_length=255, blank=True, null=True) | ||
720 | user_info = models.JSONField() | ||
721 | status = models.IntegerField() | ||
722 | created_at = models.DateTimeField(blank=True, null=True) | ||
723 | updated_at = models.DateTimeField(blank=True, null=True) | ||
724 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
725 | |||
726 | class Meta: | ||
727 | managed = False | ||
728 | db_table = 'user_examines' | ||
729 | |||
730 | |||
731 | class UserLoginLogs(models.Model): | ||
732 | user_id = models.PositiveBigIntegerField() | ||
733 | client_ip = models.CharField(max_length=50) | ||
734 | client_agent = models.CharField(max_length=400) | ||
735 | created_at = models.DateTimeField(blank=True, null=True) | ||
736 | updated_at = models.DateTimeField(blank=True, null=True) | ||
737 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
738 | |||
739 | class Meta: | ||
740 | managed = False | ||
741 | db_table = 'user_login_logs' | ||
742 | |||
743 | class ActivityHasTags(models.Model): | ||
744 | activity = models.ForeignKey('Activitys',related_name='has_activity',on_delete=models.DO_NOTHING) | ||
745 | tag = models.ForeignKey('SystemTags',related_name='has_tag',on_delete=models.DO_NOTHING) | ||
746 | created_at = models.DateTimeField(blank=True, null=True) | ||
747 | updated_at = models.DateTimeField(blank=True, null=True) | ||
748 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
749 | |||
750 | class Meta: | ||
751 | managed = False | ||
752 | db_table = 'activity_has_tags' | ||
753 | |||
754 | class UserHasTags(models.Model): | ||
755 | user_id = models.IntegerField() | ||
756 | tag_id = models.IntegerField() | ||
757 | created_at = models.DateTimeField(blank=True, null=True) | ||
758 | updated_at = models.DateTimeField(blank=True, null=True) | ||
759 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
760 | |||
761 | class Meta: | ||
762 | managed = False | ||
763 | db_table = 'user_has_tags' | ||
764 | |||
765 | class UserViewActivity(models.Model): | ||
766 | activity_id = models.IntegerField() | ||
767 | user_id = models.IntegerField() | ||
768 | created_at = models.DateTimeField(blank=True, null=True) | ||
769 | updated_at = models.DateTimeField(blank=True, null=True) | ||
770 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
771 | class Meta: | ||
772 | managed = False | ||
773 | db_table = 'user_view_activitys' | ||
774 | |||
775 | |||
776 | class Users(AbstractBaseUser): | ||
777 | nick_name = models.CharField(max_length=255,unique=True) | ||
778 | real_name = models.CharField(max_length=255) | ||
779 | sex = models.IntegerField(default=0) | ||
780 | intro = models.CharField(max_length=400,default='') | ||
781 | cover = models.CharField(max_length=400,default='https://hi-sing-cdn.hikoon.com/file/20231116/vbhr3e6yk4l1700102812011wg18xstw9m.jpg') | ||
782 | avatar = models.CharField(max_length=400, blank=True, null=True,default='https://hi-sing-cdn.hikoon.com/image/20230925/heqk7stlm31695620862622v3gdnlhzars.png') | ||
783 | area_code = models.CharField(max_length=255,default='86') | ||
784 | phone = models.IntegerField(max_length=255) | ||
785 | email = models.CharField(max_length=255) | ||
786 | # origin_type = models.CharField(max_length=8) | ||
787 | # remarks = models.CharField(max_length=255) | ||
788 | # business_id = models.IntegerField(blank=True, null=True) | ||
789 | business = models.ForeignKey('self',null=True,related_name='has_business',on_delete=models.DO_NOTHING) | ||
790 | business_singer_limit = models.IntegerField(default=0) | ||
791 | password = models.CharField(max_length=255) | ||
792 | open_id = models.CharField(max_length=255, blank=True, null=True) | ||
793 | unionid = models.CharField(max_length=255, blank=True, null=True) | ||
794 | role = models.CharField(max_length=255,default=None) | ||
795 | scope = models.IntegerField(default=0) | ||
796 | sound = models.CharField(max_length=400,default='') | ||
797 | sound_at = models.DateTimeField(blank=True, null=True) | ||
798 | province = models.CharField(max_length=255, blank=True, null=True) | ||
799 | city = models.CharField(max_length=255, blank=True, null=True) | ||
800 | is_referee = models.IntegerField() | ||
801 | rate = models.CharField(max_length=255) | ||
802 | company = models.CharField(max_length=255, blank=True, null=True) | ||
803 | status = models.IntegerField() | ||
804 | audit_status = models.IntegerField(blank=True, null=True) | ||
805 | last_login = models.DateTimeField(blank=True, null=True) | ||
806 | is_home = models.IntegerField(default=1) | ||
807 | chat_mode = models.IntegerField(default=0) | ||
808 | wechat_account = models.CharField(max_length=255,default=None) | ||
809 | identity = models.IntegerField(default=0) | ||
810 | created_at = models.DateTimeField(blank=True, null=True) | ||
811 | updated_at = models.DateTimeField(blank=True, null=True) | ||
812 | deleted_at = models.DateTimeField(blank=True, null=True) | ||
813 | |||
814 | USERNAME_FIELD = 'nick_name' | ||
815 | REQUIRED_FIELDS = [] | ||
816 | |||
817 | def __str__(self): | ||
818 | return self.nick_name | ||
819 | |||
820 | @property | ||
821 | def token(self): | ||
822 | return self._generate_jwt_token() | ||
823 | |||
824 | def _generate_jwt_token(self): | ||
825 | token = jwt.encode({ | ||
826 | 'exp': datetime.utcnow() + timedelta(days=90), | ||
827 | 'iat': datetime.utcnow(), | ||
828 | 'data': { | ||
829 | 'id':self.id, | ||
830 | 'env':settings.ENV | ||
831 | } | ||
832 | }, | ||
833 | settings.SECRET_KEY, algorithm='HS256') | ||
834 | return token | ||
835 | |||
836 | |||
837 | class Meta: | ||
838 | managed = False | ||
839 | db_table = 'users' | ||
840 | default_permissions = () |
api/schedules.py
0 → 100644
1 | |||
2 | import time | ||
3 | import schedule | ||
4 | import threading | ||
5 | from api import models | ||
6 | from django.utils import timezone | ||
7 | from django.db.models import F, Func | ||
8 | from django.db.models.functions import Now | ||
9 | |||
10 | def project_confirmation_times(): | ||
11 | projects = models.Projects.objects.filter(status=1,deleted_at=None) | ||
12 | for project in projects: | ||
13 | #匹配的活动均值 | ||
14 | l1 = list() | ||
15 | days_diff = Func(F('match_at') - F('publish_at'), function='ABS') | ||
16 | results = models.Activitys.objects.filter(status__in=[3,5],project_id=project.id).annotate(days_diff=days_diff) | ||
17 | for result in results: | ||
18 | try:l1.append(result.days_diff.days) | ||
19 | except:l1.append(0) | ||
20 | # 未匹配的活动均值 | ||
21 | days_diff = Func(Now() - F('publish_at'),function='ABS') | ||
22 | deltas = models.Activitys.objects.filter(status=1,project_id=project.id).annotate(days_diff=days_diff) | ||
23 | for delta in deltas: | ||
24 | try:l1.append(delta.days_diff.days) | ||
25 | except:pass | ||
26 | try:mean = sum(l1) / len(l1) | ||
27 | except: mean = 0 | ||
28 | models.ProjectConfirmationTime.objects.update_or_create( | ||
29 | project_id=project.id, | ||
30 | defaults={'average_day': mean,'created_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S"),'updated_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S")} | ||
31 | ) | ||
32 | |||
33 | def job1(): | ||
34 | threading.Thread(target=project_confirmation_times).start() | ||
35 | |||
36 | schedule.every().day.at("02:00").do(job1) | ||
37 | # schedule.every(1).minutes.do(job1) | ||
38 | |||
39 | def run(): | ||
40 | while True: | ||
41 | schedule.run_pending() | ||
42 | time.sleep(1) | ||
43 | |||
44 | |||
45 |
api/serializers.py
0 → 100644
1 | # -*- coding: utf-8 -*- | ||
2 | import logging | ||
3 | |||
4 | from rest_framework import serializers | ||
5 | from api import models,TLSSigAPIv2 | ||
6 | import datetime | ||
7 | from HisinApi import settings | ||
8 | from datetime import timedelta | ||
9 | from django.utils import timezone | ||
10 | |||
11 | |||
12 | class BanneraSerializer(serializers.ModelSerializer): | ||
13 | def __init__(self, *args, **kwargs): | ||
14 | # 获取传递进来的 fields 参数,如果没有默认为 None | ||
15 | fields = kwargs.pop('fields', None) | ||
16 | super().__init__(*args, **kwargs) | ||
17 | |||
18 | if fields is not None: | ||
19 | allowed_fields = set(fields) | ||
20 | existing_fields = set(self.fields.keys()) | ||
21 | |||
22 | # 找出需要删除的字段 | ||
23 | for field_name in existing_fields - allowed_fields: | ||
24 | self.fields.pop(field_name) | ||
25 | |||
26 | class Meta: | ||
27 | model = models.Banners | ||
28 | fields = "__all__" | ||
29 | |||
30 | class ProjectsSerializer(serializers.ModelSerializer): | ||
31 | intro = serializers.SerializerMethodField() | ||
32 | master = serializers.SerializerMethodField() | ||
33 | visitor_count = serializers.SerializerMethodField() | ||
34 | |||
35 | class Meta: | ||
36 | model = models.Projects | ||
37 | fields = "__all__" | ||
38 | def get_intro(self,obj): | ||
39 | if obj.intro:intro = obj.intro | ||
40 | else:intro = '海星试唱入驻厂牌' | ||
41 | return intro | ||
42 | |||
43 | def get_master(self,obj): | ||
44 | queryset = models.Users.objects.filter(id=obj.master_id,deleted_at=None).first() | ||
45 | if queryset :data = BusinessSerializer(queryset,many=False).data | ||
46 | else:data=None | ||
47 | return data | ||
48 | |||
49 | def get_visitor_count(self, obj): | ||
50 | # 取当前日期和时间 | ||
51 | now = timezone.now() | ||
52 | # 计算 30 天前的日期和时间 | ||
53 | thirty_days_ago = now - timedelta(days=30) | ||
54 | return models.ProjectVisitors.objects.filter(project_id=obj.id, created_at__gte=thirty_days_ago).values('user_id').distinct().count() | ||
55 | |||
56 | class ProjectSimplesSerializer(serializers.ModelSerializer): | ||
57 | class Meta: | ||
58 | model = models.Projects | ||
59 | fields = ('id','name','cover') | ||
60 | |||
61 | |||
62 | class SystemTagsSerializer(serializers.ModelSerializer): | ||
63 | def __init__(self, *args, **kwargs): | ||
64 | # 获取传递进来的 fields 参数,如果没有默认为 None | ||
65 | fields = kwargs.pop('fields', None) | ||
66 | super().__init__(*args, **kwargs) | ||
67 | |||
68 | if fields is not None: | ||
69 | allowed_fields = set(fields) | ||
70 | existing_fields = set(self.fields.keys()) | ||
71 | |||
72 | # 找出需要删除的字段 | ||
73 | for field_name in existing_fields - allowed_fields: | ||
74 | self.fields.pop(field_name) | ||
75 | class Meta: | ||
76 | model = models.SystemTags | ||
77 | fields = "__all__" | ||
78 | |||
79 | |||
80 | |||
81 | class UsersSerializer(serializers.ModelSerializer): | ||
82 | has_tags = serializers.SerializerMethodField() | ||
83 | examine_info = serializers.SerializerMethodField() | ||
84 | is_band = serializers.SerializerMethodField() | ||
85 | is_subscribe = serializers.SerializerMethodField() | ||
86 | singer_count = serializers.SerializerMethodField() | ||
87 | collection_count = serializers.SerializerMethodField() | ||
88 | my_collection = serializers.SerializerMethodField() | ||
89 | my_audition_count = serializers.SerializerMethodField() | ||
90 | my_audition = serializers.SerializerMethodField() | ||
91 | total_audition_count = serializers.SerializerMethodField() | ||
92 | listen_count = serializers.SerializerMethodField() | ||
93 | my_listen = serializers.SerializerMethodField() | ||
94 | singer_collection_count = serializers.SerializerMethodField() | ||
95 | singer_audition_count = serializers.SerializerMethodField() | ||
96 | new_singer_count = serializers.SerializerMethodField() | ||
97 | new_collection_count = serializers.SerializerMethodField() | ||
98 | new_audition_count = serializers.SerializerMethodField() | ||
99 | new_platform_audition_count = serializers.SerializerMethodField() | ||
100 | is_reject = serializers.SerializerMethodField() | ||
101 | follower_count = serializers.SerializerMethodField() | ||
102 | following_count = serializers.SerializerMethodField() | ||
103 | home_red_dot = serializers.SerializerMethodField() | ||
104 | system_message_count = serializers.SerializerMethodField() | ||
105 | im_usersig = serializers.SerializerMethodField() | ||
106 | art_tag = serializers.SerializerMethodField() | ||
107 | business = serializers.SerializerMethodField() | ||
108 | auth_count = serializers.SerializerMethodField() | ||
109 | auth_tags = serializers.SerializerMethodField() | ||
110 | auth_status = serializers.SerializerMethodField() | ||
111 | group_status = serializers.SerializerMethodField() | ||
112 | project_status = serializers.SerializerMethodField() | ||
113 | project_name = serializers.SerializerMethodField() | ||
114 | member_count = serializers.SerializerMethodField() | ||
115 | whitelist_permission = serializers.SerializerMethodField() | ||
116 | is_activity_manage = serializers.SerializerMethodField() | ||
117 | is_project_master = serializers.SerializerMethodField() | ||
118 | is_intercept_auth = serializers.SerializerMethodField() | ||
119 | examine_count = serializers.SerializerMethodField() | ||
120 | |||
121 | class Meta: | ||
122 | model = models.Users | ||
123 | fields = ( | ||
124 | 'id','nick_name','rate','real_name','intro','member_count','auth_count','auth_tags','whitelist_permission', | ||
125 | 'auth_status','is_activity_manage','identity','group_status','project_status','project_name','is_project_master','art_tag', | ||
126 | 'im_usersig','my_listen','my_audition','my_collection','system_message_count','singer_count','is_reject', | ||
127 | 'examine_info','follower_count','following_count','home_red_dot','listen_count','new_singer_count', | ||
128 | 'new_collection_count','new_audition_count','new_platform_audition_count','singer_collection_count', | ||
129 | 'singer_audition_count','collection_count','my_audition_count','total_audition_count','avatar','phone','email', | ||
130 | 'business_id','open_id','unionid','is_band','is_subscribe','role','scope','status','audit_status','has_tags', | ||
131 | 'is_intercept_auth','examine_count','province','city','is_referee','company','chat_mode','business','last_login','created_at') | ||
132 | |||
133 | def get_examine_count(self,obj): | ||
134 | user_ids = list(models.Users.objects.filter(audit_status=0, role__in=['Singer','Business'],deleted_at=None).values_list('id', flat=True)) | ||
135 | examine_count = models.UserExamines.objects.filter(user_id__in=user_ids, status=0, deleted_at=None).count() | ||
136 | if obj.scope != 1: | ||
137 | examine_count = 0 | ||
138 | return examine_count | ||
139 | |||
140 | def get_is_intercept_auth(self,obj): | ||
141 | source = 0 | ||
142 | #有无风格标签 | ||
143 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=1).values_list('tag_id', flat=True)) | ||
144 | is_style_tag = models.SystemTags.objects.filter(id__in=tags, deleted_at=None).exists() | ||
145 | #打分项配置 | ||
146 | parentobj = models.SystemConfig.objects.filter(identifier='TeZnnaB-Pfwyz8IADs0SM', status=1, deleted_at=None).first() | ||
147 | if parentobj: | ||
148 | data = SystemConfigSerializer(models.SystemConfig.objects.filter(parent_id=parentobj.id, status=1, deleted_at=None), many=True).data | ||
149 | for item in data: | ||
150 | if item['identifier'] == 'nick_name' and obj.nick_name: | ||
151 | source = source + int(item['content']) | ||
152 | if item['identifier'] == 'sex' and obj.sex: | ||
153 | source = source + int(item['content']) | ||
154 | if item['identifier'] == 'city' and obj.city: | ||
155 | source = source + int(item['content']) | ||
156 | if item['identifier'] == 'wechat_account' and obj.wechat_account: | ||
157 | source = source + int(item['content']) | ||
158 | if item['identifier'] == 'cover' and obj.cover: | ||
159 | source = source + int(item['content']) | ||
160 | if item['identifier'] == 'company' and obj.company: | ||
161 | source = source + int(item['content']) | ||
162 | if item['identifier'] == 'intro' and obj.intro: | ||
163 | source = source + int(item['content']) | ||
164 | if item['identifier'] == 'email' and obj.email: | ||
165 | source = source + int(item['content']) | ||
166 | if item['identifier'] == 'style' and is_style_tag: | ||
167 | source = source + int(item['content']) | ||
168 | if item['identifier'] == 'video' and models.UserDynamics.objects.filter(user_id=obj.id,type='video',deleted_at=None).exists(): | ||
169 | source = source + int(item['content']) | ||
170 | if item['identifier'] == 'audio' and models.UserDynamics.objects.filter(user_id=obj.id,type='audio',deleted_at=None).exists(): | ||
171 | source = source + int(item['content']) | ||
172 | if item['identifier'] == 'image' and models.UserDynamics.objects.filter(user_id=obj.id,type='image',deleted_at=None).exists(): | ||
173 | source = source + int(item['content']) | ||
174 | #阈值 | ||
175 | content = int(models.SystemConfig.objects.get(identifier='iymo-wZcV2F0UWFUKJR5m', status=1, deleted_at=None).content) | ||
176 | return False if source >= content else True | ||
177 | |||
178 | def get_art_tag(self,obj): | ||
179 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id,type=2).values_list('tag_id',flat=True)) | ||
180 | if len(tags) > 0:return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True).data | ||
181 | else: | ||
182 | if obj.role == 'Singer':name = "歌手" | ||
183 | elif obj.role == 'Business':name = "商务" | ||
184 | else:name = "策划" | ||
185 | return [{"name":name}] | ||
186 | |||
187 | def get_im_usersig(self,obj): | ||
188 | api = TLSSigAPIv2.TLSSigAPIv2(settings.SDK_APPID, settings.PRI_KEY) | ||
189 | if settings.ENV == 'dev':user_id = 'test'+str(obj.id) | ||
190 | else:user_id = obj.id | ||
191 | usersig = api.genUserSig(user_id) | ||
192 | return usersig | ||
193 | |||
194 | def get_system_message_count(self,obj): | ||
195 | return models.UserMessages.objects.filter(type__in=[4,5,6,7,8,9,10,11,12,13,14],receiver_id=obj.id,is_read=0,deleted_at=None).count() | ||
196 | |||
197 | def get_is_reject(self,obj): | ||
198 | return models.UserExamines.objects.filter(user_id=obj.id,status=2,deleted_at=None).exists() | ||
199 | |||
200 | def get_new_platform_audition_count(self,obj): | ||
201 | if obj.scope == 0:return 0 | ||
202 | if obj.scope != 2:activity_ids = self.context['activity_ids'] | ||
203 | else: | ||
204 | # 获取项目用户关联项目id | ||
205 | project_ids = list( models.UserHasProjects.objects.filter(user_id=obj.id).values_list('project_id', flat=True)) | ||
206 | activity_ids = list(models.Activitys.objects.filter(project_id__in=project_ids,status=1,deleted_at=None).values_list('id', flat=True)) | ||
207 | # 过滤掉不相关的活动,去掉不公开的厂牌下活动不是自己创建的活动 | ||
208 | nopublic_project_id = list(models.Projects.objects.filter(id__in=project_ids, is_public=0, deleted_at=None).values_list('id',flat=True)) | ||
209 | noself_activity_id = list(models.Activitys.objects.filter(project_id__in=nopublic_project_id, status=1, deleted_at=None).exclude(user_id=obj.id).values_list('id', flat=True)) | ||
210 | activity_ids = [x for x in activity_ids if x not in noself_activity_id] | ||
211 | return models.UserMessages.objects.filter(is_read=0, activity_id__in=activity_ids, type=3,receiver_id=obj.id, deleted_at=None, is_bind=0).count() | ||
212 | |||
213 | def get_new_audition_count(self,obj): | ||
214 | """ | ||
215 | 我的歌手新增试唱数 | ||
216 | :param obj: | ||
217 | :return: | ||
218 | """ | ||
219 | member_count = self.get_member_count(obj) | ||
220 | new_audition_count = models.UserMessages.objects.filter(is_read=0, activity_id__in=self.context['activity_ids'], type=3, | ||
221 | receiver_id=obj.id, deleted_at=None, is_bind=1).count() | ||
222 | if member_count == 0:new_audition_count = 0 | ||
223 | return new_audition_count | ||
224 | |||
225 | def get_new_collection_count(self,obj): | ||
226 | """ | ||
227 | 我的歌手新增收藏数 | ||
228 | :param obj: | ||
229 | :return: | ||
230 | """ | ||
231 | return models.UserMessages.objects.filter(is_read=0,activity_id__in=self.context['activity_ids'],type=2,receiver_id=obj.id,deleted_at=None).count() | ||
232 | |||
233 | def get_new_singer_count(self,obj): | ||
234 | """ | ||
235 | 新增歌手数 | ||
236 | :param obj: | ||
237 | :return: | ||
238 | """ | ||
239 | return models.UserMessages.objects.filter(is_read=0,type=1,receiver_id=obj.id,deleted_at=None).count() | ||
240 | |||
241 | def get_singer_audition_count(self,obj): | ||
242 | #获取我关联的歌手 | ||
243 | singer_ids = list(models.Users.objects.filter(business_id=obj.id,deleted_at=None).values_list('id',flat=True)) | ||
244 | #获取我关联歌手的提交数量 | ||
245 | return models.ActivityHasUsers.objects.filter(user_id__in=singer_ids,activity_id__in=self.context['activity_ids'],type='Submit',deleted_at=None).count() | ||
246 | |||
247 | |||
248 | def get_singer_collection_count(self,obj): | ||
249 | #获取我关联的歌手 | ||
250 | singer_ids = list(models.Users.objects.filter(business_id=obj.id,deleted_at=None).values_list('id',flat=True)) | ||
251 | #获取我关联歌手的收藏数量 | ||
252 | return models.UserActivityCollections.objects.filter(user_id__in=singer_ids,activity_id__in=self.context['activity_ids'],deleted_at=None).count() | ||
253 | |||
254 | def get_listen_count(self,obj): | ||
255 | return models.UserViewActivity.objects.filter(user_id=obj.id,activity_id__in=self.context['all_activity_ids'],deleted_at=None).values('activity_id').distinct().count() | ||
256 | |||
257 | def get_my_listen(self,obj): | ||
258 | activity_ids = list(models.UserViewActivity.objects.filter(user_id=obj.id, deleted_at=None).values_list('activity_id',flat=True).order_by('-updated_at')) | ||
259 | if not activity_ids:return {"count": 0,"cover":None} | ||
260 | activity_id_str = ",".join('%s' % id for id in activity_ids) | ||
261 | ids = list(models.Activitys.objects.filter(id__in=activity_ids, deleted_at=None).extra(select={'m': 'FIELD(id,{})'.format(activity_id_str)}, order_by=['m']).values_list('id',flat=True)) | ||
262 | if ids:url = models.Activitys.objects.filter(id=ids[0]).first().cover | ||
263 | else:url=None | ||
264 | return {"count":self.get_listen_count(obj),"cover":url} | ||
265 | |||
266 | def get_singer_count(self,obj): | ||
267 | return models.Users.objects.filter(business_id=obj.id,deleted_at=None,audit_status=1,status=1).count() | ||
268 | |||
269 | def get_collection_count(self, obj): | ||
270 | """首页收藏数:正在进行的活动""" | ||
271 | ids = list(models.UserActivityCollections.objects.filter(user_id=obj.id, deleted_at=None).order_by('-created_at').values_list('activity_id', flat=True)) | ||
272 | return models.Activitys.objects.filter(id__in=ids,status=1,deleted_at=None).count() | ||
273 | |||
274 | def get_my_collection(self,obj): | ||
275 | ids = list(models.UserActivityCollections.objects.filter(user_id=obj.id,deleted_at=None).order_by('-created_at').values_list('activity_id',flat=True)) | ||
276 | if not ids:return {"count": 0,"cover":None} | ||
277 | activity_id_str = ",".join('%s' % id for id in ids) | ||
278 | ids = list(models.Activitys.objects.filter(id__in=ids, deleted_at=None).extra(select={'m': 'FIELD(id,{})'.format(activity_id_str)}, order_by=['m']).values_list('id',flat=True)) | ||
279 | if ids:url = models.Activitys.objects.filter(id=ids[0]).first().cover | ||
280 | else:url = None | ||
281 | ids = list(models.UserActivityCollections.objects.filter(user_id=obj.id, deleted_at=None).order_by( | ||
282 | '-created_at').values_list('activity_id', flat=True)) | ||
283 | count = models.Activitys.objects.filter(id__in=ids, deleted_at=None).count() | ||
284 | return {"count":count,"cover":url} | ||
285 | |||
286 | def get_my_audition_count(self, obj): | ||
287 | return models.ActivityHasUsers.objects.filter(user_id=obj.id,activity_id__in=self.context['all_activity_ids'],deleted_at=None).all().values('activity_id').distinct().count() | ||
288 | |||
289 | def get_my_audition(self,obj): | ||
290 | ids = models.ActivityHasUsers.objects.filter(user_id=obj.id, deleted_at=None).order_by('-created_at').values_list('activity_id', flat=True).distinct() | ||
291 | if not ids:return {"count": 0,"cover":None} | ||
292 | activity_id_str = ",".join('%s' % id for id in ids) | ||
293 | ids = list(models.Activitys.objects.filter(id__in=ids, deleted_at=None).extra(select={'m': 'FIELD(id,{})'.format(activity_id_str)}, order_by=['m']).values_list('id',flat=True)) | ||
294 | if ids:url = models.Activitys.objects.filter(id=ids[0]).first().cover | ||
295 | else:url = None | ||
296 | return {"count": self.get_my_audition_count(obj),"cover":url} | ||
297 | |||
298 | def get_total_audition_count(self,obj): | ||
299 | return models.ActivityHasUsers.objects.filter(type='Submit',deleted_at=None).all().values('user_id').distinct().count() | ||
300 | |||
301 | def get_has_tags(self,obj): | ||
302 | return UserHasTagsSerializer(models.UserHasTags.objects.filter(user_id=obj.id,deleted_at=None),many=True).data | ||
303 | |||
304 | def get_examine_info(self,obj): | ||
305 | return UserExaminesSerializer(models.UserExamines.objects.filter(user_id=obj.id).order_by('-created_at').first(),many=False).data | ||
306 | |||
307 | def get_is_band(self,obj): | ||
308 | if obj.open_id and obj.unionid :return True | ||
309 | else:return False | ||
310 | |||
311 | def get_is_subscribe(self,obj): | ||
312 | return models.WechatOfficialUsers.objects.filter(union_id=obj.unionid,is_subscribe=1).exists() | ||
313 | |||
314 | |||
315 | def get_follower_count(self,obj): | ||
316 | user_ids = list(models.UserFollowRelations.objects.filter(following_id=obj.id,deleted_at=None).values_list('follower_id',flat=True)) | ||
317 | return models.Users.objects.filter(id__in =user_ids,status=1,deleted_at=None).count() | ||
318 | |||
319 | def get_following_count(self,obj): | ||
320 | user_ids = list(models.UserFollowRelations.objects.filter(follower_id=obj.id,deleted_at=None).values_list('following_id',flat=True)) | ||
321 | return models.Users.objects.filter(id__in =user_ids,status=1,deleted_at=None).count() | ||
322 | |||
323 | def get_home_red_dot(self,obj): | ||
324 | """ | ||
325 | 主页红点:新访客,新粉丝,有新试唱数且是推荐人身份,且审核通过 | ||
326 | :param obj: | ||
327 | :return: | ||
328 | """ | ||
329 | new_visitor = models.UserVisitors.objects.filter(user_id=obj.id,is_read=0).exists() | ||
330 | new_fans = models.UserFollowRelations.objects.filter(following_id=obj.id,deleted_at=None,is_read=0).exists() | ||
331 | #平台/项目试唱数 | ||
332 | new_platform_audition = self.get_new_platform_audition_count(obj) | ||
333 | # 团队管理-ta们新试唱 | ||
334 | new_ta_audition = self.get_new_audition_count(obj) | ||
335 | # # 团队管理-ta们新收藏 删除于2023-12-8 | ||
336 | # new_ta_collection = self.get_new_collection_count(obj) | ||
337 | # 待审核数 | ||
338 | examine_count = self.get_examine_count(obj) | ||
339 | if ( | ||
340 | new_visitor or | ||
341 | new_fans or | ||
342 | new_ta_audition or | ||
343 | # new_ta_collection or | ||
344 | examine_count or | ||
345 | (new_platform_audition and obj.role=='Business') and obj.audit_status==1):return True | ||
346 | else:return False | ||
347 | |||
348 | def get_business(self,obj): | ||
349 | if obj.business_id:return SingerBusinessSerializer(models.Users.objects.filter(id=obj.business_id).first(),many=False).data | ||
350 | else:return None | ||
351 | |||
352 | def get_auth_count(self,obj): | ||
353 | if obj.scope != 1:auth_count = 0 | ||
354 | else:auth_count = models.UserAuthInfos.objects.filter(status=0,deleted_at=None).values('user_id').distinct().count() | ||
355 | return auth_count | ||
356 | |||
357 | def get_auth_tags(self,obj): | ||
358 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=4).values_list('tag_id', flat=True)) | ||
359 | if len(tags) == 0:return None | ||
360 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None), many=True,fields=['id','name','expand']).data | ||
361 | |||
362 | def get_auth_status(self,obj): | ||
363 | auth_info = models.UserAuthInfos.objects.filter(user_id=obj.id,deleted_at=None).last() | ||
364 | if auth_info:status = auth_info.status | ||
365 | else:status=3 | ||
366 | return status | ||
367 | |||
368 | def get_group_status(self,obj): | ||
369 | query = models.GroupHasMembers.objects.filter(member_id=obj.id,deleted_at=None).last() | ||
370 | status = query.status if query else 0 | ||
371 | return status | ||
372 | |||
373 | def get_project_status(self,obj): | ||
374 | query = models.ProjectHasMembers.objects.filter(user_id=obj.id, status__in= [1,3],deleted_at=None).last() | ||
375 | status = query.status if query else 0 | ||
376 | return status | ||
377 | |||
378 | def get_project_name(self,obj): | ||
379 | projecthasmember = models.ProjectHasMembers.objects.filter(user_id=obj.id, status__in= [1,3],deleted_at=None).last() | ||
380 | project_id = projecthasmember.project_id if projecthasmember else 0 | ||
381 | project = models.Projects.objects.filter(id=project_id,status=1, deleted_at=None).first() | ||
382 | return project.name if project else '' | ||
383 | |||
384 | def get_is_project_master(self,obj): | ||
385 | query = models.ProjectHasMembers.objects.filter(user_id=obj.id, status__in= [1,3],deleted_at=None).last() | ||
386 | if not query: | ||
387 | return False | ||
388 | return models.UserHasProjects.objects.filter(project_id=query.project_id,user_id=obj.id).exists() | ||
389 | |||
390 | |||
391 | def get_member_count(self, obj): | ||
392 | return models.Users.objects.filter(business_id=obj.id, status=1, audit_status=1, deleted_at=None).count() | ||
393 | |||
394 | def get_whitelist_permission(self,obj): | ||
395 | #唱权限检测 | ||
396 | singobj = models.SystemConfig.objects.filter(identifier='Jy-zgPbcSXSGnvHIx8moq',status=1, deleted_at=None).first() | ||
397 | if singobj: | ||
398 | if str(obj.id) in singobj.content.split(','):return {"sing": True, "listen": True} | ||
399 | else:sing = False | ||
400 | else: sing = False | ||
401 | #听权限检测 | ||
402 | listenobj = models.SystemConfig.objects.filter(identifier='-BIGBAR9rPOMwCrw4hIuQ', status=1,deleted_at=None).first() | ||
403 | if listenobj:listen = True if str(obj.id) in listenobj.content.split(',') else False | ||
404 | else:listen = False | ||
405 | return {"sing":sing,"listen":listen} | ||
406 | |||
407 | def get_is_activity_manage(self,obj): | ||
408 | '''是否外部管理员''' | ||
409 | return models.UserManageActivitie.objects.filter(user_id=obj.id).exists() | ||
410 | |||
411 | class UserHomeSerializer(serializers.ModelSerializer): | ||
412 | business_id = serializers.SerializerMethodField() | ||
413 | business = serializers.SerializerMethodField() | ||
414 | art_tag = serializers.SerializerMethodField() | ||
415 | style_tag = serializers.SerializerMethodField() | ||
416 | follower_count = serializers.SerializerMethodField() | ||
417 | new_follower_count = serializers.SerializerMethodField() | ||
418 | following_count = serializers.SerializerMethodField() | ||
419 | sound_tag = serializers.SerializerMethodField() | ||
420 | is_follow = serializers.SerializerMethodField() | ||
421 | sound_like_count = serializers.SerializerMethodField() | ||
422 | is_sound_like = serializers.SerializerMethodField() | ||
423 | visitor_count = serializers.SerializerMethodField() | ||
424 | new_visitor_count = serializers.SerializerMethodField() | ||
425 | new_platform_audition_count = serializers.SerializerMethodField() | ||
426 | auth_status = serializers.SerializerMethodField() | ||
427 | auth_tags = serializers.SerializerMethodField() | ||
428 | broker = serializers.SerializerMethodField() | ||
429 | member_count = serializers.SerializerMethodField() | ||
430 | source = serializers.SerializerMethodField() | ||
431 | dynamics_count = serializers.SerializerMethodField() | ||
432 | |||
433 | class Meta: | ||
434 | model = models.Users | ||
435 | exclude = ['password','phone','deleted_at'] | ||
436 | |||
437 | def get_dynamics_count(self,obj): | ||
438 | image_count = models.UserDynamics.objects.filter(user_id=obj.id,type='image',deleted_at=None).count() | ||
439 | audio_count = models.UserDynamics.objects.filter(user_id=obj.id,type='audio',deleted_at=None).count() | ||
440 | video_count = models.UserDynamics.objects.filter(user_id=obj.id,type='video',deleted_at=None).count() | ||
441 | return {"image_count":image_count,"audio_count":audio_count,"video_count":video_count} | ||
442 | |||
443 | def get_source(self,obj): | ||
444 | source = 0 | ||
445 | parentobj = models.SystemConfig.objects.filter(identifier='TeZnnaB-Pfwyz8IADs0SM', status=1, deleted_at=None).first() | ||
446 | if parentobj: | ||
447 | data = SystemConfigSerializer(models.SystemConfig.objects.filter(parent_id=parentobj.id, status=1, deleted_at=None), many=True).data | ||
448 | for item in data: | ||
449 | if item['identifier'] == 'nick_name' and obj.nick_name: | ||
450 | source = source + int(item['content']) | ||
451 | if item['identifier'] == 'sex' and obj.sex: | ||
452 | source = source + int(item['content']) | ||
453 | if item['identifier'] == 'city' and obj.city: | ||
454 | source = source + int(item['content']) | ||
455 | if item['identifier'] == 'wechat_account' and obj.wechat_account: | ||
456 | source = source + int(item['content']) | ||
457 | if item['identifier'] == 'cover' and obj.cover: | ||
458 | source = source + int(item['content']) | ||
459 | if item['identifier'] == 'company' and obj.company: | ||
460 | source = source + int(item['content']) | ||
461 | if item['identifier'] == 'intro' and obj.intro: | ||
462 | source = source + int(item['content']) | ||
463 | if item['identifier'] == 'email' and obj.email: | ||
464 | source = source + int(item['content']) | ||
465 | if item['identifier'] == 'style' and self.get_style_tag(obj): | ||
466 | source = source + int(item['content']) | ||
467 | if item['identifier'] == 'video' and models.UserDynamics.objects.filter(user_id=obj.id,type='video',deleted_at=None).exists(): | ||
468 | source = source + int(item['content']) | ||
469 | if item['identifier'] == 'audio' and models.UserDynamics.objects.filter(user_id=obj.id,type='audio',deleted_at=None).exists(): | ||
470 | source = source + int(item['content']) | ||
471 | if item['identifier'] == 'image' and models.UserDynamics.objects.filter(user_id=obj.id,type='image',deleted_at=None).exists(): | ||
472 | source = source + int(item['content']) | ||
473 | #阈值推荐语 | ||
474 | content_list = eval(models.SystemConfig.objects.get(identifier='YmSNBXwMB6cUo-zRT26s-', status=1, deleted_at=None).content) | ||
475 | text = '' | ||
476 | for content in content_list: | ||
477 | if content['min'] <= source < content['max']:text = content['content'] | ||
478 | return {"number":source,"text":text} | ||
479 | |||
480 | def get_new_platform_audition_count(self,obj): | ||
481 | #是否外部管理员 | ||
482 | is_activity_manage = models.UserManageActivitie.objects.filter(user_id=obj.id).exists() | ||
483 | #1.普通用户 | ||
484 | if obj.scope == 0 and not is_activity_manage: | ||
485 | return 0 | ||
486 | #2.平台管理员 | ||
487 | if obj.scope == 1: | ||
488 | activity_ids = self.context['activity_ids'] | ||
489 | #项目管理员和外部管理员 | ||
490 | else: | ||
491 | # 获取项目用户关联项目id | ||
492 | project_ids = list( models.UserHasProjects.objects.filter(user_id=obj.id).values_list('project_id', flat=True)) | ||
493 | activity_ids = list(models.Activitys.objects.filter(project_id__in=project_ids,status=1,deleted_at=None).values_list('id', flat=True)) | ||
494 | # 过滤掉不相关的活动,去掉不公开的厂牌下活动不是自己创建的活动 | ||
495 | nopublic_project_id = list(models.Projects.objects.filter(id__in=project_ids, is_public=0, deleted_at=None).values_list('id',flat=True)) | ||
496 | noself_activity_id = list(models.Activitys.objects.filter(project_id__in=nopublic_project_id, status=1, deleted_at=None).exclude(user_id=obj.id).values_list('id', flat=True)) | ||
497 | activity_ids = [x for x in activity_ids if x not in noself_activity_id] | ||
498 | #外部管理员 | ||
499 | if is_activity_manage: | ||
500 | manage_activity_ids = list(models.UserManageActivitie.objects.filter(user_id=obj.id,activity_status=1).values_list('activity_id',flat=True)) | ||
501 | activity_ids = set(sorted(activity_ids+manage_activity_ids)) | ||
502 | return models.UserMessages.objects.filter(is_read=0, activity_id__in=activity_ids, type=3,receiver_id=obj.id, deleted_at=None, is_bind=0).count() | ||
503 | |||
504 | |||
505 | def get_visitor_count(self,obj): | ||
506 | #取当前日期和时间 | ||
507 | now = timezone.now() | ||
508 | # 计算 30 天前的日期和时间 | ||
509 | thirty_days_ago = now - timedelta(days=30) | ||
510 | return models.UserVisitors.objects.filter(user_id=obj.id,created_at__gte=thirty_days_ago).values('visitor_id').distinct().count() | ||
511 | |||
512 | def get_new_visitor_count(self, obj): | ||
513 | # 取当前日期和时间 | ||
514 | now = timezone.now() | ||
515 | # 计算 30 天前的日期和时间 | ||
516 | thirty_days_ago = now - timedelta(days=30) | ||
517 | return models.UserVisitors.objects.filter(user_id=obj.id,is_read=0,created_at__gte=thirty_days_ago).count() | ||
518 | |||
519 | def get_business_id(self,obj): | ||
520 | return obj.business_id | ||
521 | |||
522 | def get_business(self,obj): | ||
523 | return SystemBusinessSerializer(models.Users.objects.filter(id=obj.business_id,status=1,audit_status=1,deleted_at=None).first(),many=False).data | ||
524 | |||
525 | def get_art_tag(self,obj): | ||
526 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id,type=2).values_list('tag_id',flat=True)) | ||
527 | if len(tags) > 0: | ||
528 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True,fields=['id','name']).data | ||
529 | else: | ||
530 | if obj.role == 'Singer': | ||
531 | name = "歌手" | ||
532 | elif obj.role == 'Business': | ||
533 | name = "商务" | ||
534 | else: | ||
535 | name = "策划" | ||
536 | return [{"name":name}] | ||
537 | |||
538 | def get_style_tag(self,obj): | ||
539 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=1).values_list('tag_id', flat=True)) | ||
540 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True,fields=['id','name']).data | ||
541 | |||
542 | def get_sound_tag(self,obj): | ||
543 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=3).values_list('tag_id', flat=True)) | ||
544 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True,fields=['id','name']).data | ||
545 | |||
546 | def get_follower_count(self,obj): | ||
547 | user_ids = list(models.UserFollowRelations.objects.filter(following_id=obj.id,deleted_at=None).values_list('follower_id',flat=True)) | ||
548 | return models.Users.objects.filter(id__in =user_ids,status=1,deleted_at=None).count() | ||
549 | |||
550 | def get_new_follower_count(self,obj): | ||
551 | return models.UserFollowRelations.objects.filter(following_id=obj.id,deleted_at=None,is_read=0).count() | ||
552 | |||
553 | def get_following_count(self,obj): | ||
554 | user_ids = list(models.UserFollowRelations.objects.filter(follower_id=obj.id,deleted_at=None).values_list('following_id',flat=True)) | ||
555 | return models.Users.objects.filter(id__in =user_ids,status=1,deleted_at=None).count() | ||
556 | |||
557 | def get_is_follow(self,obj): | ||
558 | request_usre_id = self.context['request_usre_id'] | ||
559 | return models.UserFollowRelations.objects.filter(follower_id=request_usre_id,following_id=obj.id, deleted_at=None).exists() | ||
560 | |||
561 | def get_sound_like_count(self,obj): | ||
562 | if obj.sound: | ||
563 | return models.TidingsHasInteracts.objects.filter(type=3,type_id=obj.id,status=1,deleted_at=None).count() | ||
564 | else: | ||
565 | return 0 | ||
566 | |||
567 | def get_is_sound_like(self,obj): | ||
568 | if obj.sound: | ||
569 | request_usre_id = self.context['request_usre_id'] | ||
570 | return models.TidingsHasInteracts.objects.filter(type=3,user_id=request_usre_id,status=1,type_id=obj.id,deleted_at=None).exists() | ||
571 | else: | ||
572 | return False | ||
573 | |||
574 | def get_auth_status(self,obj): | ||
575 | auth_info = models.UserAuthInfos.objects.filter(user_id=obj.id,deleted_at=None).last() | ||
576 | if auth_info: | ||
577 | status = auth_info.status | ||
578 | reason=auth_info.reason | ||
579 | else: | ||
580 | status=3 | ||
581 | reason=None | ||
582 | return {"status":status,"reason":reason} | ||
583 | |||
584 | def get_auth_tags(self,obj): | ||
585 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=4).values_list('tag_id', flat=True)) | ||
586 | if len(tags) == 0:return None | ||
587 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None), many=True,fields=['id','name']).data | ||
588 | |||
589 | def get_broker(self,obj): | ||
590 | singer_tag_id = models.SystemConfig.objects.filter(identifier='auth_singer_tag').values_list('content',flat=True).get() | ||
591 | has_singer_tag = models.UserTagRelations.objects.filter(user_id=obj.id, type=4,tag_id=singer_tag_id).exists() | ||
592 | queryset = models.Users.objects.filter(id=obj.business_id,status=1,audit_status=1,deleted_at=None).first() | ||
593 | if not has_singer_tag:return None | ||
594 | elif not queryset: return None | ||
595 | else:return SystemBusinessSerializer(queryset,many=False).data | ||
596 | |||
597 | def get_member_count(self,obj): | ||
598 | return models.Users.objects.filter(business_id=obj.id,status=1,audit_status=1,deleted_at=None).count() | ||
599 | |||
600 | class UserTidingSerializer(serializers.ModelSerializer): | ||
601 | activity = serializers.SerializerMethodField() | ||
602 | user = serializers.SerializerMethodField() | ||
603 | class Meta: | ||
604 | model = models.UserHasTidings | ||
605 | exclude = ['deleted_at'] | ||
606 | |||
607 | def get_user(self,obj): | ||
608 | return UserListSerializer(models.Users.objects.filter(id=obj.user_id).first(),many=False).data | ||
609 | |||
610 | def get_activity(self,obj): | ||
611 | return TidingsActivity(models.Activitys.objects.filter(id=obj.activity_id).first(),many=False).data | ||
612 | |||
613 | class UserFollowSerializer(serializers.ModelSerializer): | ||
614 | is_follow = serializers.SerializerMethodField() | ||
615 | is_read = serializers.SerializerMethodField() | ||
616 | follow_time = serializers.SerializerMethodField() | ||
617 | auth_tags = serializers.SerializerMethodField() | ||
618 | |||
619 | class Meta: | ||
620 | model = models.Users | ||
621 | fields = ('id','avatar','nick_name','real_name','intro','is_follow','is_read','follow_time','role','identity','auth_tags') | ||
622 | |||
623 | def get_is_follow(self,obj): | ||
624 | user_id = self.context['user_id'] | ||
625 | return models.UserFollowRelations.objects.filter(following_id=obj.id,follower_id=user_id,deleted_at=None).exists() | ||
626 | |||
627 | def get_is_read(self,obj): | ||
628 | user_id = self.context['user_id'] | ||
629 | return not models.UserFollowRelations.objects.filter(following_id=user_id,follower_id=obj.id,deleted_at=None,is_read=0).exists() | ||
630 | |||
631 | def get_follow_time(self, obj): | ||
632 | user_id = self.context['user_id'] | ||
633 | return models.UserFollowRelations.objects.filter(following_id=user_id, follower_id=obj.id,deleted_at=None).first().created_at.strftime("%Y-%m-%d %H:%M:%S") | ||
634 | |||
635 | |||
636 | def get_auth_tags(self,obj): | ||
637 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=4).values_list('tag_id', flat=True)) | ||
638 | if len(tags) == 0:return None | ||
639 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None), many=True,fields=['id','name','expand']).data | ||
640 | |||
641 | |||
642 | class UserFollowingSerializer(serializers.ModelSerializer): | ||
643 | is_follow_me = serializers.SerializerMethodField() | ||
644 | art_tag = serializers.SerializerMethodField() | ||
645 | follow_time = serializers.SerializerMethodField() | ||
646 | is_read = serializers.SerializerMethodField() | ||
647 | auth_tags = serializers.SerializerMethodField() | ||
648 | |||
649 | class Meta: | ||
650 | model = models.Users | ||
651 | fields = ('id','avatar','nick_name','art_tag','real_name','intro','is_follow_me','identity','follow_time','is_read','auth_tags') | ||
652 | |||
653 | def get_is_follow_me(self,obj): | ||
654 | user_id = self.context['user_id'] | ||
655 | return models.UserFollowRelations.objects.filter(following_id=user_id,follower_id=obj.id,deleted_at=None).exists() | ||
656 | |||
657 | def get_art_tag(self,obj): | ||
658 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id,type=2).values_list('tag_id',flat=True)) | ||
659 | if len(tags) > 0: | ||
660 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True).data | ||
661 | else: | ||
662 | if obj.role == 'Singer': | ||
663 | name = "歌手" | ||
664 | elif obj.role == 'Business': | ||
665 | name = "商务" | ||
666 | else: | ||
667 | name = "策划" | ||
668 | return [{"name":name}] | ||
669 | |||
670 | def get_follow_time(self,obj): | ||
671 | user_id = self.context['user_id'] | ||
672 | return models.UserFollowRelations.objects.filter(following_id=obj.id, follower_id=user_id,deleted_at=None).first().created_at.strftime("%Y-%m-%d %H:%M:%S") | ||
673 | |||
674 | def get_is_read(self,obj): | ||
675 | user_id = self.context['user_id'] | ||
676 | return not models.UserFollowRelations.objects.filter(following_id=obj.id,follower_id=user_id,deleted_at=None,is_read=0).exists() | ||
677 | |||
678 | def get_auth_tags(self,obj): | ||
679 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=4).values_list('tag_id', flat=True)) | ||
680 | if len(tags) == 0:return None | ||
681 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None), many=True,fields=['id','name','expand']).data | ||
682 | |||
683 | class ActivitysPriceSerializer(serializers.ModelSerializer): | ||
684 | class Meta: | ||
685 | model = models.ActivityUserHasPrices | ||
686 | fields = "__all__" | ||
687 | address = serializers.SerializerMethodField() | ||
688 | is_hide = serializers.SerializerMethodField() | ||
689 | def get_address(self,obj): | ||
690 | city = models.CountryRegions.objects.filter(id=obj.address_id).first() | ||
691 | if city:province = models.CountryRegions.objects.filter(id=city.parent_id).first() | ||
692 | else:return None | ||
693 | return {"province":province.name,"city":city.name} | ||
694 | |||
695 | def get_is_hide(self,obj): | ||
696 | """获取音频公开属性""" | ||
697 | ahu = models.ActivityHasUsers.objects.filter(type='Submit', user_id=obj.user_id, activity_id=self.context['activity_id']).last() | ||
698 | return ahu.is_hide if ahu else 1 | ||
699 | |||
700 | class ActivitysSerializer(serializers.ModelSerializer): | ||
701 | tags = serializers.SerializerMethodField() | ||
702 | attend_user = serializers.SerializerMethodField() | ||
703 | project = serializers.SerializerMethodField() | ||
704 | attend_count = serializers.SerializerMethodField() | ||
705 | is_take = serializers.SerializerMethodField() | ||
706 | comfire_share_user = serializers.SerializerMethodField() | ||
707 | is_promote = serializers.SerializerMethodField() | ||
708 | class Meta: | ||
709 | model = models.Activitys | ||
710 | fields = ("id","cover","comfire_share_user","is_promote","song_name","status","created_at","sub_title","guide","lyric","clip_lyric","tags","attend_user","project","is_take","attend_count") | ||
711 | |||
712 | def get_is_promote(self,obj): | ||
713 | project = models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).first() | ||
714 | if not project:is_promote = 0 | ||
715 | else:is_promote = project.is_promote | ||
716 | return is_promote | ||
717 | |||
718 | def get_comfire_share_user(self, obj): | ||
719 | user_id = self.context['user_id'] | ||
720 | share_obj = models.ActivityShareUsers.objects.filter(activity_id=obj.id, user_id=user_id).first() | ||
721 | if share_obj: | ||
722 | if share_obj.share_id:return BusinessSerializer(models.Users.objects.filter(id=share_obj.share_id).first(), many=False).data | ||
723 | else:return None | ||
724 | else: | ||
725 | return None | ||
726 | |||
727 | def get_tags(self,obj): | ||
728 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
729 | flat=True) | ||
730 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
731 | fields=['id', 'name']).data | ||
732 | def get_attend_user(self,obj): | ||
733 | attend_user_ids = models.ActivityHasUsers.objects.filter(type='Submit',activity_id=obj.id,deleted_at=None).all().values_list('user_id',flat=True).distinct()[:6] #最多取前6个 | ||
734 | return UserListSerializer (models.Users.objects.in_bulk(attend_user_ids).values(),many=True).data | ||
735 | |||
736 | def get_project(self,obj): | ||
737 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(),many=True).data | ||
738 | |||
739 | def get_attend_count(self,obj): | ||
740 | return models.ActivityHasUsers.objects.filter(type='Submit',activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
741 | |||
742 | def get_is_take(self,obj): | ||
743 | user_id = self.context['user_id'] | ||
744 | return models.ActivityHasUsers.objects.filter(user_id=user_id,activity_id=obj.id,status=1).exists() | ||
745 | |||
746 | class PlatfromAuditionSerializer(serializers.ModelSerializer): | ||
747 | tags = serializers.SerializerMethodField() | ||
748 | project = serializers.SerializerMethodField() | ||
749 | submit = serializers.SerializerMethodField() | ||
750 | is_promote = serializers.SerializerMethodField() | ||
751 | |||
752 | class Meta: | ||
753 | model = models.Activitys | ||
754 | fields = ("id","cover","song_name","status","is_promote","is_official","created_at","sub_title","guide","lyric","clip_lyric","tags","submit","project") | ||
755 | |||
756 | def get_is_promote(self,obj): | ||
757 | try: | ||
758 | if obj.project.is_promote==1 and obj.project.deleted_at == None and obj.project.status==1:is_promote = 1 | ||
759 | else:is_promote =0 | ||
760 | except: | ||
761 | is_promote = 0 | ||
762 | return is_promote | ||
763 | |||
764 | def get_tags(self,obj): | ||
765 | query_set_list = models.ActivityHasTags.objects.select_related('tag').filter(activity_id=obj.id,deleted_at=None) | ||
766 | tag_list = [] | ||
767 | for query_set in query_set_list: | ||
768 | tag_list.append(query_set.tag) | ||
769 | data = SystemTagsSerializer(tag_list, many=True).data | ||
770 | return data | ||
771 | |||
772 | def get_project(self,obj): | ||
773 | try: | ||
774 | if obj.project.deleted_at == None and obj.project.status==1:return [{"id":obj.project.id,"name":obj.project.name}] | ||
775 | else:return [] | ||
776 | except: return [] | ||
777 | |||
778 | def get_submit(self,obj): | ||
779 | user_id = self.context['user_id'] | ||
780 | query_set = obj.ahus | ||
781 | messageobj_list = models.UserMessages.objects.none() | ||
782 | sender_id_list = [] | ||
783 | for q in query_set: | ||
784 | messageobj = models.UserMessages.objects.filter(type=3, activity_id=obj.id, sender_id=q.user_id,receiver_id=user_id, is_read=0, is_bind=0, deleted_at=None) | ||
785 | messageobj_list = messageobj_list | messageobj | ||
786 | |||
787 | for message in messageobj_list: | ||
788 | sender_id_list.append(message.sender_id) | ||
789 | for q in query_set: | ||
790 | if q.user_id in sender_id_list:q.is_new = True | ||
791 | else:q.is_new = False | ||
792 | query_set = list(query_set) | ||
793 | query_set.sort(key=lambda x: x.is_new,reverse=True) | ||
794 | query_set.sort(key=lambda x: x.status) | ||
795 | return PlatfromAuditionHasUserSerializer(query_set,many=True,context={"user_id":user_id}).data | ||
796 | |||
797 | |||
798 | class ListenActivitysSerializer(serializers.ModelSerializer): | ||
799 | tags = serializers.SerializerMethodField() | ||
800 | project = serializers.SerializerMethodField() | ||
801 | listen_at = serializers.SerializerMethodField() | ||
802 | is_unlike = serializers.SerializerMethodField() | ||
803 | |||
804 | class Meta: | ||
805 | model = models.Activitys | ||
806 | fields = ("id","cover","song_name","status","is_official","created_at","sub_title","guide","lyric","clip_lyric","tags","project","listen_at","is_unlike") | ||
807 | |||
808 | def get_listen_at(self,obj): | ||
809 | user_id = self.context['user_id'] | ||
810 | return models.UserViewActivity.objects.filter(user_id=user_id,activity_id=obj.id,deleted_at=None).first().updated_at.strftime("%Y-%m-%d %H:%M:%S") | ||
811 | |||
812 | def get_tags(self,obj): | ||
813 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
814 | flat=True) | ||
815 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
816 | fields=['id', 'name']).data | ||
817 | def get_project(self,obj): | ||
818 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(),many=True).data | ||
819 | |||
820 | def get_is_unlike(self, obj): | ||
821 | user_id = self.context['user_id'] | ||
822 | return models.UserActivityUnlikes.objects.filter(user_id=user_id, activity_id=obj.id, deleted_at=None).exists() | ||
823 | |||
824 | |||
825 | class CollectionActivitysSerializer(serializers.ModelSerializer): | ||
826 | tags = serializers.SerializerMethodField() | ||
827 | project = serializers.SerializerMethodField() | ||
828 | collection_at = serializers.SerializerMethodField() | ||
829 | attend_count = serializers.SerializerMethodField() | ||
830 | attend_user = serializers.SerializerMethodField() | ||
831 | view_count = serializers.SerializerMethodField() | ||
832 | |||
833 | class Meta: | ||
834 | model = models.Activitys | ||
835 | fields = ("id","cover","song_name","status","is_official","attend_count","view_count","attend_user","created_at","sub_title","guide","guide_clip","lyric","clip_lyric","tags","project","collection_at",'sex','mark','speed','lang',) | ||
836 | |||
837 | def get_collection_at(self,obj): | ||
838 | user_id = self.context['user_id'] | ||
839 | return models.UserActivityCollections.objects.filter(user_id=user_id,activity_id=obj.id,deleted_at=None).first().created_at.strftime("%Y-%m-%d %H:%M:%S") | ||
840 | |||
841 | def get_view_count(self,obj): | ||
842 | return models.UserViewActivity.objects.filter(activity_id=obj.id,deleted_at=None).count() | ||
843 | |||
844 | def get_tags(self,obj): | ||
845 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
846 | flat=True) | ||
847 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
848 | fields=['id', 'name']).data | ||
849 | def get_project(self,obj): | ||
850 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(),many=True).data | ||
851 | |||
852 | def get_attend_count(self, obj): | ||
853 | return models.ActivityHasUsers.objects.filter(type='Submit', activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
854 | |||
855 | def get_attend_user(self,obj): | ||
856 | attend_user_ids = models.ActivityHasUsers.objects.filter(type='Submit',activity_id=obj.id,deleted_at=None).values_list('user_id',flat=True).distinct()[:6] #最多取前6个 | ||
857 | return UserListSerializer (models.Users.objects.in_bulk(attend_user_ids).values(),many=True).data | ||
858 | |||
859 | |||
860 | class MyActivitysSerializer(serializers.ModelSerializer): | ||
861 | tags = serializers.SerializerMethodField() | ||
862 | project = serializers.SerializerMethodField() | ||
863 | is_take = serializers.SerializerMethodField() | ||
864 | save_count = serializers.SerializerMethodField() | ||
865 | submit_count = serializers.SerializerMethodField() | ||
866 | attend_count = serializers.SerializerMethodField() | ||
867 | attend_user = serializers.SerializerMethodField() | ||
868 | sound_url = serializers.SerializerMethodField() | ||
869 | class Meta: | ||
870 | model = models.Activitys | ||
871 | # fields = "__all__" | ||
872 | fields = ( | ||
873 | "id", "status","is_official","cover", "song_name","attend_count","attend_user", "created_at", "sub_title", "guide", "lyric", "clip_lyric", "tags", | ||
874 | "project", "is_take", "save_count","submit_count","sound_url") | ||
875 | |||
876 | def get_save_count(self,obj): | ||
877 | user_id = self.context['user_id'] | ||
878 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,user_id=user_id,type="Save",deleted_at=None).count() | ||
879 | |||
880 | def get_submit_count(self,obj): | ||
881 | user_id = self.context['user_id'] | ||
882 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,user_id=user_id,type="Submit",deleted_at=None).count() | ||
883 | |||
884 | def get_tags(self, obj): | ||
885 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
886 | flat=True) | ||
887 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
888 | fields=['id', 'name']).data | ||
889 | def get_project(self, obj): | ||
890 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(), many=True).data | ||
891 | |||
892 | def get_is_take(self, obj): | ||
893 | user_id = self.context['user_id'] | ||
894 | return models.ActivityHasUsers.objects.filter(user_id=user_id, activity_id=obj.id, status=1).exists() | ||
895 | |||
896 | def get_attend_count(self, obj): | ||
897 | return models.ActivityHasUsers.objects.filter(type='Submit', activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
898 | |||
899 | def get_attend_user(self, obj): | ||
900 | attend_user_ids = models.ActivityHasUsers.objects.filter(type='Submit', activity_id=obj.id,deleted_at=None).values_list( | ||
901 | 'user_id', flat=True).distinct()[:6] # 最多取前6个 | ||
902 | return UserListSerializer(models.Users.objects.in_bulk(attend_user_ids).values(), many=True).data | ||
903 | |||
904 | def get_sound_url(self,obj): | ||
905 | user_id = self.context['user_id'] | ||
906 | ahu = models.ActivityHasUsers.objects.filter(activity_id=obj.id, user_id=user_id, type='Submit').first() | ||
907 | if ahu: | ||
908 | sound_url = ahu.demo_url | ||
909 | else: | ||
910 | sound_url = models.ActivityHasUsers.objects.filter(activity_id=obj.id, user_id=user_id,deleted_at=None).last().demo_url | ||
911 | return sound_url | ||
912 | |||
913 | class MySingerActivitysSerializer(serializers.ModelSerializer): | ||
914 | tags = serializers.SerializerMethodField() | ||
915 | project = serializers.SerializerMethodField() | ||
916 | save_count = serializers.SerializerMethodField() | ||
917 | submit_count = serializers.SerializerMethodField() | ||
918 | submit_info = serializers.SerializerMethodField() | ||
919 | attend_count = serializers.SerializerMethodField() | ||
920 | is_take = serializers.SerializerMethodField() | ||
921 | |||
922 | |||
923 | class Meta: | ||
924 | model = models.Activitys | ||
925 | fields = ( | ||
926 | "id", "status","is_official","cover", "song_name", "created_at", "sub_title", "guide", "lyric", "clip_lyric", "tags", | ||
927 | "project", "save_count","submit_count","submit_info","attend_count","is_take") | ||
928 | |||
929 | def get_save_count(self,obj): | ||
930 | user_id = self.context['user_id'] | ||
931 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,user_id=user_id,type="Save",deleted_at=None).count() | ||
932 | |||
933 | def get_submit_count(self,obj): | ||
934 | user_id = self.context['user_id'] | ||
935 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,user_id=user_id,type="Submit",deleted_at=None).count() | ||
936 | |||
937 | def get_tags(self, obj): | ||
938 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
939 | flat=True) | ||
940 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
941 | fields=['id', 'name']).data | ||
942 | def get_project(self, obj): | ||
943 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(), many=True).data | ||
944 | |||
945 | def get_submit_info(self,obj): | ||
946 | user_id = self.context['user_id'] | ||
947 | return ActivitysHasUserSerializer(models.ActivityHasUsers.objects.filter(activity_id=obj.id,user_id=user_id,type="Submit",deleted_at=None).first(),many=False).data | ||
948 | |||
949 | def get_attend_count(self, obj): | ||
950 | return models.ActivityHasUsers.objects.filter(type='Submit', activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
951 | |||
952 | def get_is_take(self, obj): | ||
953 | user_id = self.context['user_id'] | ||
954 | return models.ActivityHasUsers.objects.filter(user_id=user_id, activity_id=obj.id, status=1).exists() | ||
955 | |||
956 | class V2ActivitysSerializer(serializers.ModelSerializer): | ||
957 | tags = serializers.SerializerMethodField() | ||
958 | attend_user = serializers.SerializerMethodField() | ||
959 | project = serializers.SerializerMethodField() | ||
960 | attend_count = serializers.SerializerMethodField() | ||
961 | is_take = serializers.SerializerMethodField() | ||
962 | is_collection = serializers.SerializerMethodField() | ||
963 | view_count = serializers.SerializerMethodField() | ||
964 | #status_tag状态标签 | ||
965 | status_tag = serializers.SerializerMethodField() | ||
966 | is_listen = serializers.SerializerMethodField() | ||
967 | is_submit = serializers.SerializerMethodField() | ||
968 | |||
969 | class Meta: | ||
970 | model = models.Activitys | ||
971 | # fields = "__all__" | ||
972 | fields = ("id","cover","song_name","status","is_official","created_at","is_listen","is_submit","is_collection","sub_title","guide","guide_clip","guide_clip_duration","lyric","clip_lyric","tags","attend_user","project","attend_count","is_take","is_collection","view_count","status_tag") | ||
973 | |||
974 | def get_is_listen(self, obj): | ||
975 | return obj.is_listen | ||
976 | |||
977 | def get_is_submit(self, obj): | ||
978 | return obj.is_submit | ||
979 | |||
980 | def get_is_collection(self, obj): | ||
981 | return obj.is_collection | ||
982 | |||
983 | def get_attend_count(self,obj): | ||
984 | return obj.attend_count | ||
985 | |||
986 | def get_is_take(self, obj): | ||
987 | return obj.is_take | ||
988 | |||
989 | def get_view_count(self,obj): | ||
990 | return obj.view_count | ||
991 | |||
992 | def get_status_tag(self,obj): | ||
993 | if obj.is_listen:return 'listened' | ||
994 | else:return 'new' | ||
995 | |||
996 | def get_is_new(self,obj): | ||
997 | new_day = (datetime.datetime.now() - datetime.timedelta(days=7)).strftime("%Y-%m-%d %H:%M:%S") | ||
998 | is_within = models.Activitys.objects.filter(id=obj.id,created_at__gte =new_day).exists() | ||
999 | return not obj.is_listen and is_within | ||
1000 | |||
1001 | def get_tags(self,obj): | ||
1002 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1003 | flat=True) | ||
1004 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1005 | fields=['id', 'name']).data | ||
1006 | def get_attend_user(self,obj): | ||
1007 | attend_user_ids = models.ActivityHasUsers.objects.filter(type='Submit',activity_id=obj.id,deleted_at=None).values_list('user_id',flat=True).distinct()[:6] #最多取前6个 | ||
1008 | return UserListSerializer (models.Users.objects.in_bulk(attend_user_ids).values(),many=True).data | ||
1009 | |||
1010 | def get_project(self,obj): | ||
1011 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(),many=True).data | ||
1012 | |||
1013 | |||
1014 | |||
1015 | class ActivitysCollectionSerializer(serializers.ModelSerializer): | ||
1016 | tags = serializers.SerializerMethodField() | ||
1017 | project = serializers.SerializerMethodField() | ||
1018 | attend_count = serializers.SerializerMethodField() | ||
1019 | collection = serializers.SerializerMethodField() | ||
1020 | |||
1021 | class Meta: | ||
1022 | model = models.Activitys | ||
1023 | fields = "__all__" | ||
1024 | |||
1025 | def get_tags(self,obj): | ||
1026 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1027 | flat=True) | ||
1028 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1029 | fields=['id', 'name']).data | ||
1030 | def get_project(self,obj): | ||
1031 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(),many=True).data | ||
1032 | |||
1033 | def get_attend_count(self,obj): | ||
1034 | return models.ActivityHasUsers.objects.filter(type='Submit',activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
1035 | |||
1036 | def get_collection(self,obj): | ||
1037 | singer_ids = self.context['singer_ids'] | ||
1038 | user_id = self.context['user_id'] | ||
1039 | queset = models.UserActivityCollections.objects.filter(user_id__in=singer_ids,activity_id=obj.id,deleted_at=None).order_by('-created_at') | ||
1040 | return CollectionsHasUserSerializer(queset,many=True,context={"user_id":user_id}).data | ||
1041 | |||
1042 | |||
1043 | |||
1044 | class ActivitysSubmitUserSerializer(serializers.ModelSerializer): | ||
1045 | tags = serializers.SerializerMethodField() | ||
1046 | project = serializers.SerializerMethodField() | ||
1047 | submit = serializers.SerializerMethodField() | ||
1048 | is_promote = serializers.SerializerMethodField() | ||
1049 | class Meta: | ||
1050 | model = models.Activitys | ||
1051 | fields = "__all__" | ||
1052 | |||
1053 | def get_is_promote(self,obj): | ||
1054 | project = models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).first() | ||
1055 | if not project:is_promote = 0 | ||
1056 | else:is_promote = project.is_promote | ||
1057 | return is_promote | ||
1058 | |||
1059 | def get_tags(self,obj): | ||
1060 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1061 | flat=True) | ||
1062 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1063 | fields=['id', 'name']).data | ||
1064 | def get_project(self,obj): | ||
1065 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(),many=True).data | ||
1066 | |||
1067 | def get_submit(self,obj): | ||
1068 | user_id = self.context['user_id'] | ||
1069 | query_set = obj.ahus | ||
1070 | messageobj_list = models.UserMessages.objects.none() | ||
1071 | sender_id_list = [] | ||
1072 | for q in query_set: | ||
1073 | messageobj = models.UserMessages.objects.filter(type=3, activity_id=obj.id, sender_id=q.user_id,receiver_id=user_id, is_read=0, is_bind=1, deleted_at=None) | ||
1074 | messageobj_list = messageobj_list | messageobj | ||
1075 | for message in messageobj_list: | ||
1076 | sender_id_list.append(message.sender_id) | ||
1077 | for q in query_set: | ||
1078 | if q.user_id in sender_id_list: | ||
1079 | q.is_new = True | ||
1080 | else: | ||
1081 | q.is_new = False | ||
1082 | query_set = list(query_set) | ||
1083 | query_set.sort(key=lambda x: x.is_new, reverse=True) | ||
1084 | query_set.sort(key=lambda x: x.status) | ||
1085 | return AuditionHasUserSerializer(query_set,many=True,context={"user_id":user_id}).data | ||
1086 | |||
1087 | |||
1088 | class SingerActivitysSerializer(serializers.ModelSerializer): | ||
1089 | tags = serializers.SerializerMethodField() | ||
1090 | attend_user = serializers.SerializerMethodField() | ||
1091 | project = serializers.SerializerMethodField() | ||
1092 | is_join = serializers.SerializerMethodField() | ||
1093 | attend_count = serializers.SerializerMethodField() | ||
1094 | is_take = serializers.SerializerMethodField() | ||
1095 | |||
1096 | class Meta: | ||
1097 | model = models.Activitys | ||
1098 | fields = "__all__" | ||
1099 | |||
1100 | def get_tags(self,obj): | ||
1101 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1102 | flat=True) | ||
1103 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1104 | fields=['id', 'name']).data | ||
1105 | def get_attend_user(self,obj): | ||
1106 | attend_user_ids = models.ActivityHasUsers.objects.filter(activity_id=obj.id,deleted_at=None).all().values_list('user_id',flat=True).distinct()[:6] #最多取前6个 | ||
1107 | return UserListSerializer (models.Users.objects.in_bulk(attend_user_ids).values(),many=True).data | ||
1108 | |||
1109 | def get_project(self,obj): | ||
1110 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(),many=True).data | ||
1111 | |||
1112 | def get_is_join(self,obj): | ||
1113 | singer_id = self.context['singer_id'] | ||
1114 | return models.ActivityHasUsers.objects.filter(user_id=singer_id, activity_id=obj.id).exists() | ||
1115 | |||
1116 | def get_attend_count(self,obj): | ||
1117 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
1118 | |||
1119 | def get_is_take(self,obj): | ||
1120 | singer_id = self.context['singer_id'] | ||
1121 | return models.ActivityHasUsers.objects.filter(user_id=singer_id,activity_id=obj.id,status=1).exists() | ||
1122 | |||
1123 | |||
1124 | class ActivitysHasUserSerializer(serializers.ModelSerializer): | ||
1125 | class Meta: | ||
1126 | model = models.ActivityHasUsers | ||
1127 | fields = ("demo_url","syn_status","status","version","submit_at","mode","sing_type","updated_at") | ||
1128 | |||
1129 | class ManyActivitysHasUserSerializer(serializers.ModelSerializer): | ||
1130 | user = serializers.SerializerMethodField() | ||
1131 | |||
1132 | class Meta: | ||
1133 | model = models.ActivityHasUsers | ||
1134 | fields = ( | ||
1135 | "id", "user","demo_url","durations", "type","status","syn_status","syn_data","is_checked","mode","open_id","submit_at","version","sing_type","created_at", | ||
1136 | "updated_at", | ||
1137 | "deleted_at", | ||
1138 | "activity_id") | ||
1139 | |||
1140 | def get_user(self,obj): | ||
1141 | return UserListSerializer(models.Users.objects.filter(id=obj.user_id).first(),many=False).data | ||
1142 | |||
1143 | |||
1144 | class UserExaminesSerializer(serializers.ModelSerializer): | ||
1145 | has_business = serializers.SerializerMethodField() | ||
1146 | tags = serializers.SerializerMethodField() | ||
1147 | class Meta: | ||
1148 | model = models.UserExamines | ||
1149 | fields = "__all__" | ||
1150 | def get_has_business(self,obj): | ||
1151 | return SystemBusinessSerializer(models.Users.objects.filter(id=obj.business_id,status=1,audit_status=1,deleted_at=None),many=True).data | ||
1152 | def get_tags(self,obj): | ||
1153 | return | ||
1154 | |||
1155 | class UserHasTagsSerializer(serializers.ModelSerializer): | ||
1156 | tags = serializers.SerializerMethodField() | ||
1157 | class Meta: | ||
1158 | model = models.UserHasTags | ||
1159 | fields = "__all__" | ||
1160 | |||
1161 | def get_tags(self,obj): | ||
1162 | return SystemTagsSerializer(models.SystemTags.objects.filter(id=obj.tag_id).first(),many=False).data | ||
1163 | |||
1164 | |||
1165 | class BandActivitySerializer(serializers.ModelSerializer): | ||
1166 | is_collection = serializers.SerializerMethodField() | ||
1167 | is_confirm_share = serializers.SerializerMethodField() | ||
1168 | project = serializers.SerializerMethodField() | ||
1169 | is_promote = serializers.SerializerMethodField() | ||
1170 | comfirm_time = serializers.SerializerMethodField() | ||
1171 | total_song_count = serializers.SerializerMethodField() | ||
1172 | online_song_count = serializers.SerializerMethodField() | ||
1173 | public_audio_count = serializers.SerializerMethodField() | ||
1174 | tags = serializers.SerializerMethodField() | ||
1175 | arranger = serializers.SerializerMethodField() | ||
1176 | status_tag = serializers.SerializerMethodField() | ||
1177 | is_master = serializers.SerializerMethodField() | ||
1178 | |||
1179 | def __init__(self, *args, **kwargs): | ||
1180 | # 获取传递进来的 fields 参数,如果没有默认为 None | ||
1181 | fields = kwargs.pop('fields', None) | ||
1182 | super().__init__(*args, **kwargs) | ||
1183 | |||
1184 | if fields is not None: | ||
1185 | allowed_fields = set(fields) | ||
1186 | existing_fields = set(self.fields.keys()) | ||
1187 | |||
1188 | # 找出需要删除的字段 | ||
1189 | for field_name in existing_fields - allowed_fields: | ||
1190 | self.fields.pop(field_name) | ||
1191 | |||
1192 | class Meta: | ||
1193 | model = models.Activitys | ||
1194 | fields = '__all__' | ||
1195 | |||
1196 | def get_status_tag(self,obj): | ||
1197 | if obj.is_listen: | ||
1198 | return 'listened' | ||
1199 | if self.get_is_new(obj): | ||
1200 | return 'new' | ||
1201 | |||
1202 | def get_is_new(self,obj): | ||
1203 | new_day = (datetime.datetime.now() - datetime.timedelta(days=7)).strftime("%Y-%m-%d %H:%M:%S") | ||
1204 | is_within = models.Activitys.objects.filter(id=obj.id,created_at__gte =new_day).exists() | ||
1205 | return not obj.is_listen and is_within | ||
1206 | |||
1207 | def get_is_collection(self,obj): | ||
1208 | return obj.is_collection | ||
1209 | |||
1210 | def get_is_confirm_share(self, obj): | ||
1211 | return models.ActivityShareUsers.objects.filter(activity_id=obj.id,user_id=self.context['user_id']).exists() | ||
1212 | |||
1213 | def get_project(self,obj): | ||
1214 | if self.context['project_many']:queryset = models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1) | ||
1215 | else:queryset = models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).first() | ||
1216 | return ProjectSimplesSerializer(queryset, many=self.context['project_many']).data | ||
1217 | |||
1218 | def get_is_promote(self,obj): | ||
1219 | project = models.Projects.objects.filter(id=obj.project_id, status=1, deleted_at=None).first() | ||
1220 | if not project:is_promote = 0 | ||
1221 | else:is_promote = project.is_promote | ||
1222 | return is_promote | ||
1223 | |||
1224 | def get_comfirm_time(self,obj): | ||
1225 | query = models.ProjectConfirmationTime.objects.filter(project_id=obj.project_id).first() | ||
1226 | return ProjectConfirmationTimeSerializer(query,many=False).data | ||
1227 | |||
1228 | def get_total_song_count(self,obj): | ||
1229 | return models.Activitys.objects.filter(project_id=obj.project_id, audit_status=1,deleted_at=None).exclude(status__in=[0,2,4]).count() | ||
1230 | |||
1231 | def get_online_song_count(self, obj): | ||
1232 | return models.Activitys.objects.filter(project_id=obj.project_id, audit_status=1,status=1,deleted_at=None).count() | ||
1233 | |||
1234 | def get_public_audio_count(self,obj): | ||
1235 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,type='Submit',syn_status=1,is_hide=0,deleted_at=None).count() | ||
1236 | |||
1237 | def get_tags(self, obj): | ||
1238 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id,deleted_at=None).values_list('tag_id', flat=True) | ||
1239 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True,fields=['id','name']).data | ||
1240 | |||
1241 | def get_arranger(self,obj): | ||
1242 | """编曲""" | ||
1243 | links = ActivityLinksSerializer( models.ActivityLinks.objects.filter(activity_id=obj.id,type='arranger'),many=True,fields=['user']).data | ||
1244 | in_side = list() | ||
1245 | for link in links: | ||
1246 | in_side.append({"id":link['user']['id'],"nick_name":link['user']['nick_name']}) | ||
1247 | out_side = obj.expand['arranger']['supplement'] if obj.expand.get('arranger',0) else None | ||
1248 | return {"in_side":in_side,"out_side":out_side} | ||
1249 | |||
1250 | def get_is_master(self,obj): | ||
1251 | return models.UserHasProjects.objects.filter(project_id=obj.project_id,user_id=self.context['user_id']).exists() | ||
1252 | |||
1253 | |||
1254 | |||
1255 | class ActivityDetailSerializer(serializers.ModelSerializer): | ||
1256 | is_collection = serializers.SerializerMethodField() | ||
1257 | is_confirm_share = serializers.SerializerMethodField() | ||
1258 | project = serializers.SerializerMethodField() | ||
1259 | is_promote = serializers.SerializerMethodField() | ||
1260 | comfirm_time = serializers.SerializerMethodField() | ||
1261 | total_song_count = serializers.SerializerMethodField() | ||
1262 | online_song_count = serializers.SerializerMethodField() | ||
1263 | public_audio_count = serializers.SerializerMethodField() | ||
1264 | tags = serializers.SerializerMethodField() | ||
1265 | arranger = serializers.SerializerMethodField() | ||
1266 | |||
1267 | def __init__(self, *args, **kwargs): | ||
1268 | # 获取传递进来的 fields 参数,如果没有默认为 None | ||
1269 | fields = kwargs.pop('fields', None) | ||
1270 | super().__init__(*args, **kwargs) | ||
1271 | |||
1272 | if fields is not None: | ||
1273 | allowed_fields = set(fields) | ||
1274 | existing_fields = set(self.fields.keys()) | ||
1275 | |||
1276 | # 找出需要删除的字段 | ||
1277 | for field_name in existing_fields - allowed_fields: | ||
1278 | self.fields.pop(field_name) | ||
1279 | |||
1280 | class Meta: | ||
1281 | model = models.Activitys | ||
1282 | fields = '__all__' | ||
1283 | |||
1284 | def get_is_collection(self,obj): | ||
1285 | return models.UserActivityCollections.objects.filter(user_id=self.context['user_id'], activity_id=obj.id,deleted_at=None).exists() | ||
1286 | |||
1287 | def get_is_confirm_share(self, obj): | ||
1288 | return models.ActivityShareUsers.objects.filter(activity_id=obj.id,user_id=self.context['user_id']).exists() | ||
1289 | |||
1290 | def get_project(self,obj): | ||
1291 | if self.context['project_many']:queryset = models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1) | ||
1292 | else:queryset = models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).first() | ||
1293 | return ProjectSimplesSerializer(queryset, many=self.context['project_many']).data | ||
1294 | |||
1295 | def get_is_promote(self,obj): | ||
1296 | project = models.Projects.objects.filter(id=obj.project_id, status=1, deleted_at=None).first() | ||
1297 | if not project:is_promote = 0 | ||
1298 | else:is_promote = project.is_promote | ||
1299 | return is_promote | ||
1300 | |||
1301 | def get_comfirm_time(self,obj): | ||
1302 | query = models.ProjectConfirmationTime.objects.filter(project_id=obj.project_id).first() | ||
1303 | return ProjectConfirmationTimeSerializer(query,many=False).data | ||
1304 | |||
1305 | def get_total_song_count(self,obj): | ||
1306 | return models.Activitys.objects.filter(project_id=obj.project_id,audit_status=1, deleted_at=None).exclude(status__in=[0,2,4]).count() | ||
1307 | |||
1308 | def get_online_song_count(self, obj): | ||
1309 | return models.Activitys.objects.filter(project_id=obj.project_id,audit_status=1, status=1,deleted_at=None).count() | ||
1310 | |||
1311 | def get_public_audio_count(self,obj): | ||
1312 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,type='Submit',syn_status=1,is_hide=0,deleted_at=None).count() | ||
1313 | |||
1314 | def get_tags(self, obj): | ||
1315 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id,deleted_at=None).values_list('tag_id', flat=True) | ||
1316 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True,fields=['id','name']).data | ||
1317 | |||
1318 | def get_arranger(self,obj): | ||
1319 | """编曲""" | ||
1320 | links = ActivityLinksSerializer( models.ActivityLinks.objects.filter(activity_id=obj.id,type='arranger'),many=True,fields=['user']).data | ||
1321 | in_side = list() | ||
1322 | for link in links: | ||
1323 | in_side.append({"id":link['user']['id'],"nick_name":link['user']['nick_name']}) | ||
1324 | out_side = obj.expand['arranger']['supplement'] if obj.expand.get('arranger',0) else None | ||
1325 | return {"in_side":in_side,"out_side":out_side} | ||
1326 | |||
1327 | |||
1328 | class ActivityLinksSerializer(serializers.ModelSerializer): | ||
1329 | user = serializers.SerializerMethodField() | ||
1330 | def __init__(self, *args, **kwargs): | ||
1331 | # 获取传递进来的 fields 参数,如果没有默认为 None | ||
1332 | fields = kwargs.pop('fields', None) | ||
1333 | super().__init__(*args, **kwargs) | ||
1334 | |||
1335 | if fields is not None: | ||
1336 | allowed_fields = set(fields) | ||
1337 | existing_fields = set(self.fields.keys()) | ||
1338 | |||
1339 | # 找出需要删除的字段 | ||
1340 | for field_name in existing_fields - allowed_fields: | ||
1341 | self.fields.pop(field_name) | ||
1342 | class Meta: | ||
1343 | model = models.ActivityLinks | ||
1344 | fields = "__all__" | ||
1345 | |||
1346 | def get_user(self,obj): | ||
1347 | return BusinessSerializer(models.Users.objects.filter(id=obj.link_id).first(),many=False).data | ||
1348 | |||
1349 | |||
1350 | class ProjectConfirmationTimeSerializer(serializers.ModelSerializer): | ||
1351 | class Meta: | ||
1352 | model = models.ProjectConfirmationTime | ||
1353 | fields = ('project_id','average_day','updated_at') | ||
1354 | |||
1355 | class ActivityMaterialsSerializer(serializers.ModelSerializer): | ||
1356 | class Meta: | ||
1357 | model = models.ActivityMaterials | ||
1358 | fields = "__all__" | ||
1359 | |||
1360 | class SystemBusinessSerializer(serializers.ModelSerializer): | ||
1361 | has_singer_count = serializers.SerializerMethodField() | ||
1362 | class Meta: | ||
1363 | model = models.Users | ||
1364 | fields = ('id','nick_name','real_name','avatar','has_singer_count') | ||
1365 | |||
1366 | def get_has_singer_count(self, obj): | ||
1367 | return models.Users.objects.filter(business_id=obj.id,status=1,audit_status=1,deleted_at=None).count() | ||
1368 | |||
1369 | class BusinessSerializer(serializers.ModelSerializer): | ||
1370 | class Meta: | ||
1371 | model = models.Users | ||
1372 | fields = ('id','nick_name','real_name','avatar') | ||
1373 | |||
1374 | class MixinPreviewsSerializer(serializers.ModelSerializer): | ||
1375 | class Meta: | ||
1376 | model = models.MixinPreviews | ||
1377 | fields = "__all__" | ||
1378 | |||
1379 | |||
1380 | class UserListSerializer(serializers.ModelSerializer): | ||
1381 | class Meta: | ||
1382 | model = models.Users | ||
1383 | fields = ('id','nick_name','intro','real_name','avatar','province','city','company','rate') | ||
1384 | |||
1385 | class TidingsUserSerializer(serializers.ModelSerializer): | ||
1386 | art_tag = serializers.SerializerMethodField() | ||
1387 | class Meta: | ||
1388 | model = models.Users | ||
1389 | fields = ('id','nick_name','intro','sex','real_name','avatar','art_tag') | ||
1390 | |||
1391 | def get_art_tag(self,obj): | ||
1392 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id,type=2).values_list('tag_id',flat=True)) | ||
1393 | if len(tags) > 0: | ||
1394 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True).data | ||
1395 | else: | ||
1396 | if obj.role == 'Singer': | ||
1397 | name = "歌手" | ||
1398 | elif obj.role == 'Business': | ||
1399 | name = "商务" | ||
1400 | else: | ||
1401 | name = "策划" | ||
1402 | return [{"name":name}] | ||
1403 | |||
1404 | |||
1405 | class FindSingerSerializer(serializers.ModelSerializer): | ||
1406 | sound_tag = serializers.SerializerMethodField() | ||
1407 | style_tag = serializers.SerializerMethodField() | ||
1408 | |||
1409 | class Meta: | ||
1410 | model = models.Users | ||
1411 | fields = ('id','nick_name','intro','sex','real_name','avatar','style_tag','sound_tag','sound','sound_at') | ||
1412 | |||
1413 | def get_sound_tag(self,obj): | ||
1414 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id,type=3).values_list('tag_id',flat=True)) | ||
1415 | if len(tags) > 0: | ||
1416 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True).data | ||
1417 | else: | ||
1418 | return None | ||
1419 | |||
1420 | def get_style_tag(self,obj): | ||
1421 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id,type=1).values_list('tag_id',flat=True)) | ||
1422 | if len(tags) > 0: | ||
1423 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True).data | ||
1424 | else: | ||
1425 | return None | ||
1426 | |||
1427 | |||
1428 | class VisitorUserSerializer(serializers.ModelSerializer): | ||
1429 | last_visitor_at = serializers.SerializerMethodField() | ||
1430 | visitor_count = serializers.SerializerMethodField() | ||
1431 | is_read = serializers.SerializerMethodField() | ||
1432 | |||
1433 | |||
1434 | class Meta: | ||
1435 | model = models.Users | ||
1436 | fields = ('id','nick_name','sex','real_name','avatar','last_visitor_at','visitor_count','is_read','role','identity') | ||
1437 | |||
1438 | def get_last_visitor_at(self,obj): | ||
1439 | user_id = self.context['user_id'] | ||
1440 | return models.UserVisitors.objects.filter(user_id=user_id,visitor_id=obj.id).last().created_at.strftime("%Y-%m-%d %H:%M:%S") | ||
1441 | |||
1442 | def get_visitor_count(self, obj): | ||
1443 | user_id = self.context['user_id'] | ||
1444 | return models.UserVisitors.objects.filter(user_id=user_id, visitor_id=obj.id).count() | ||
1445 | |||
1446 | def get_is_read(self,obj): | ||
1447 | user_id = self.context['user_id'] | ||
1448 | return not models.UserVisitors.objects.filter(user_id=user_id, visitor_id=obj.id,is_read=0).exists() | ||
1449 | |||
1450 | |||
1451 | class PlatfromAuditionUserSerializer(serializers.ModelSerializer): | ||
1452 | business = serializers.SerializerMethodField() | ||
1453 | class Meta: | ||
1454 | model = models.Users | ||
1455 | fields = ('id','nick_name','real_name','avatar','province','city','company','rate','business','chat_mode') | ||
1456 | |||
1457 | def get_business(self,obj): | ||
1458 | query_set = obj.business | ||
1459 | data = BusinessSerializer(query_set, many=False).data | ||
1460 | return data | ||
1461 | |||
1462 | class UserActivityCollectionsSerializer(serializers.ModelSerializer): | ||
1463 | class Meta: | ||
1464 | model = models.UserActivityCollections | ||
1465 | fields = "__all__" | ||
1466 | |||
1467 | class CollectionsHasUserSerializer(serializers.ModelSerializer): | ||
1468 | """ | ||
1469 | 推荐人,管理员绑定歌手的收藏活动用户信息 | ||
1470 | """ | ||
1471 | user = serializers.SerializerMethodField() | ||
1472 | is_new = serializers.SerializerMethodField() | ||
1473 | class Meta: | ||
1474 | model = models.UserActivityCollections | ||
1475 | fields = ("id","user_id","activity_id","created_at","user","is_new") | ||
1476 | |||
1477 | def get_user(self,obj): | ||
1478 | return UserListSerializer(models.Users.objects.filter(id=obj.user_id).first(),many=False).data | ||
1479 | |||
1480 | def get_is_new(self, obj): | ||
1481 | user_id = self.context['user_id'] | ||
1482 | return models.UserMessages.objects.filter(type=2, sender_id =obj.user_id,activity_id=obj.activity_id,receiver_id=user_id, is_read=0, is_bind=1,deleted_at=None).exists() | ||
1483 | |||
1484 | class AuditionHasUserSerializer(serializers.ModelSerializer): | ||
1485 | """ | ||
1486 | 推荐人,管理员绑定歌手的试唱活动用户信息 | ||
1487 | """ | ||
1488 | user = serializers.SerializerMethodField() | ||
1489 | is_new = serializers.SerializerMethodField() | ||
1490 | comfire_share_user = serializers.SerializerMethodField() | ||
1491 | |||
1492 | class Meta: | ||
1493 | model = models.ActivityHasUsers | ||
1494 | fields = ("id","user_id","activity_id","version","comfire_share_user","type","demo_url",'mode','sing_type','syn_status',"status","created_at","user","is_new") | ||
1495 | def get_user(self,obj): | ||
1496 | return UserListSerializer(obj.user,many=False).data | ||
1497 | |||
1498 | def get_comfire_share_user(self, obj): | ||
1499 | share_obj = models.ActivityShareUsers.objects.filter(activity_id=obj.activity_id, user_id=obj.user_id).first() | ||
1500 | if share_obj: | ||
1501 | if share_obj.share_id:return BusinessSerializer(models.Users.objects.filter(id=share_obj.share_id).first(), many=False).data | ||
1502 | else:return None | ||
1503 | else: | ||
1504 | return None | ||
1505 | |||
1506 | def get_is_new(self, obj): | ||
1507 | return obj.is_new | ||
1508 | |||
1509 | class PlatfromAuditionHasUserSerializer(serializers.ModelSerializer): | ||
1510 | """ | ||
1511 | 推荐人,管理员绑定歌手的试唱活动用户信息 | ||
1512 | """ | ||
1513 | is_new = serializers.SerializerMethodField() | ||
1514 | user = serializers.SerializerMethodField() | ||
1515 | comfire_share_user = serializers.SerializerMethodField() | ||
1516 | self_price = serializers.SerializerMethodField() | ||
1517 | |||
1518 | class Meta: | ||
1519 | model = models.ActivityHasUsers | ||
1520 | fields = ("id","user_id","activity_id","status",'syn_status','mode','sing_type',"version","type","demo_url","durations","created_at","is_new","user","comfire_share_user","self_price") #'user' ,'comfire_share_user' self_price | ||
1521 | |||
1522 | def get_comfire_share_user(self, obj): | ||
1523 | if obj.share_user_nick_name:return {"nick_name": obj.share_user_nick_name,"real_name": obj.share_user_real_name} | ||
1524 | else: return None | ||
1525 | |||
1526 | def get_user(self,obj): | ||
1527 | queryset = obj.user | ||
1528 | return PlatfromAuditionUserSerializer(queryset,many=False,context={'activity_id':obj.activity_id}).data | ||
1529 | |||
1530 | def get_is_new(self, obj): | ||
1531 | return obj.is_new | ||
1532 | |||
1533 | def get_self_price(self,obj): | ||
1534 | #增加自主报价信息 | ||
1535 | price_set = models.ActivityUserHasPrices.objects.filter(user_id=obj.user_id,activity_id=obj.activity_id).first() | ||
1536 | if price_set:self_price = ActivitysPriceSerializer(price_set,many=False).data | ||
1537 | else:self_price = None | ||
1538 | return self_price | ||
1539 | |||
1540 | |||
1541 | class MySingerSerializer(serializers.ModelSerializer): | ||
1542 | attend_count = serializers.SerializerMethodField() | ||
1543 | check_count = serializers.SerializerMethodField() | ||
1544 | is_new = serializers.SerializerMethodField() | ||
1545 | tags = serializers.SerializerMethodField() | ||
1546 | art_tag = serializers.SerializerMethodField() | ||
1547 | auth_tags = serializers.SerializerMethodField() | ||
1548 | class Meta: | ||
1549 | model = models.Users | ||
1550 | fields = ('id','avatar','art_tag','auth_tags','nick_name','real_name','last_login','attend_count','check_count','rate','company','chat_mode','is_new','tags','identity') | ||
1551 | |||
1552 | def get_auth_tags(self, obj): | ||
1553 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id, type=4).values_list('tag_id', flat=True)) | ||
1554 | if len(tags) == 0: return None | ||
1555 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in=tags, deleted_at=None), many=True,fields=['id', 'name']).data | ||
1556 | |||
1557 | def get_art_tag(self,obj): | ||
1558 | tags = list(models.UserTagRelations.objects.filter(user_id=obj.id,type=2).values_list('tag_id',flat=True)) | ||
1559 | if len(tags) > 0: | ||
1560 | return SystemTagsSerializer(models.SystemTags.objects.filter(id__in = tags,deleted_at=None).values(), many=True).data | ||
1561 | else: | ||
1562 | if obj.role == 'Singer': | ||
1563 | name = "歌手" | ||
1564 | elif obj.role == 'Business': | ||
1565 | name = "商务" | ||
1566 | else: | ||
1567 | name = "策划" | ||
1568 | return [{"name":name}] | ||
1569 | |||
1570 | def get_attend_count(self,obj): | ||
1571 | return models.ActivityHasUsers.objects.filter(user_id=obj.id,type='Submit', deleted_at=None).values_list('activity_id',flat=True).distinct().count() | ||
1572 | |||
1573 | def get_check_count(self, obj): | ||
1574 | return models.ActivityHasUsers.objects.filter(user_id=obj.id,type='Submit', status=1,deleted_at=None).values_list('activity_id',flat=True).distinct().count() | ||
1575 | |||
1576 | def get_is_new(self,obj): | ||
1577 | user_id = self.context['user_id'] | ||
1578 | return models.UserMessages.objects.filter(type=1,sender_id=obj.id,receiver_id=user_id,is_read=0,is_bind=1,deleted_at=None).exists() | ||
1579 | |||
1580 | def get_tags(self,obj): | ||
1581 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1582 | flat=True) | ||
1583 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1584 | fields=['id', 'name']).data | ||
1585 | |||
1586 | |||
1587 | |||
1588 | class TidingsActivity(serializers.ModelSerializer): | ||
1589 | tags = serializers.SerializerMethodField() | ||
1590 | project = serializers.SerializerMethodField() | ||
1591 | class Meta: | ||
1592 | model = models.Activitys | ||
1593 | fields = ('id','song_name','is_official','sub_title','cover','tags','project') | ||
1594 | |||
1595 | def get_tags(self, obj): | ||
1596 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1597 | flat=True) | ||
1598 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1599 | fields=['id', 'name']).data | ||
1600 | def get_project(self, obj): | ||
1601 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(), many=True).data | ||
1602 | |||
1603 | class CompleteActivity(serializers.ModelSerializer): | ||
1604 | tags = serializers.SerializerMethodField() | ||
1605 | project = serializers.SerializerMethodField() | ||
1606 | attend_count = serializers.SerializerMethodField() | ||
1607 | confirm_user = serializers.SerializerMethodField() | ||
1608 | view_count = serializers.SerializerMethodField() | ||
1609 | class Meta: | ||
1610 | model = models.Activitys | ||
1611 | fields = "__all__" | ||
1612 | |||
1613 | def get_view_count(self,obj): | ||
1614 | return models.UserViewActivity.objects.filter(activity_id=obj.id,deleted_at=None).all().count() | ||
1615 | |||
1616 | def get_tags(self, obj): | ||
1617 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1618 | flat=True) | ||
1619 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1620 | fields=['id', 'name']).data | ||
1621 | def get_project(self, obj): | ||
1622 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(), many=True).data | ||
1623 | |||
1624 | def get_attend_count(self, obj): | ||
1625 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
1626 | |||
1627 | def get_confirm_user(self,obj): | ||
1628 | ahu = models.ActivityHasUsers.objects.filter(activity_id=obj.id,status=1,deleted_at=None).first() | ||
1629 | if ahu: | ||
1630 | user_id = ahu.user_id | ||
1631 | return UserListSerializer(models.Users.objects.filter(id=user_id,deleted_at=None).first(),many=False).data | ||
1632 | else: | ||
1633 | return None | ||
1634 | |||
1635 | |||
1636 | |||
1637 | |||
1638 | class RecommendActivitySerializer(serializers.ModelSerializer): | ||
1639 | tags = serializers.SerializerMethodField() | ||
1640 | project = serializers.SerializerMethodField() | ||
1641 | attend_count = serializers.SerializerMethodField() | ||
1642 | confirm_user = serializers.SerializerMethodField() | ||
1643 | view_count = serializers.SerializerMethodField() | ||
1644 | marks = serializers.SerializerMethodField() | ||
1645 | class Meta: | ||
1646 | model = models.Activitys | ||
1647 | fields = "__all__" | ||
1648 | |||
1649 | def get_view_count(self,obj): | ||
1650 | return models.UserViewActivity.objects.filter(activity_id=obj.id,deleted_at=None).all().count() | ||
1651 | |||
1652 | def get_tags(self, obj): | ||
1653 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1654 | flat=True) | ||
1655 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1656 | fields=['id', 'name']).data | ||
1657 | def get_project(self, obj): | ||
1658 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(), many=True).data | ||
1659 | |||
1660 | def get_attend_count(self, obj): | ||
1661 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,deleted_at=None).all().values('user_id').distinct().count() | ||
1662 | |||
1663 | def get_confirm_user(self,obj): | ||
1664 | ahu = models.ActivityHasUsers.objects.filter(activity_id=obj.id,status=1,deleted_at=None).first() | ||
1665 | if ahu: | ||
1666 | user_id = ahu.user_id | ||
1667 | return UserListSerializer(models.Users.objects.filter(id=user_id,deleted_at=None).first(),many=False).data | ||
1668 | else: | ||
1669 | return None | ||
1670 | |||
1671 | def get_marks(self,obj): | ||
1672 | if obj.r_status:return ActivityHasRecommendSerializer(models.ActivityHasRecommends.objects.filter(activity_id=obj.id, type=1, deleted_at=None),many=True).data | ||
1673 | else: | ||
1674 | return None | ||
1675 | |||
1676 | |||
1677 | |||
1678 | class ActivityHasRecommendSerializer(serializers.ModelSerializer): | ||
1679 | class Meta: | ||
1680 | model = models.ActivityHasRecommends | ||
1681 | fields = ("id","content") | ||
1682 | |||
1683 | class Events(serializers.ModelSerializer): | ||
1684 | class Meta: | ||
1685 | model = models.Events | ||
1686 | fields = "__all__" | ||
1687 | |||
1688 | |||
1689 | class WeiXinAuthUser(serializers.ModelSerializer): | ||
1690 | token = serializers.SerializerMethodField() | ||
1691 | class Meta: | ||
1692 | model = models.Users | ||
1693 | fields = ("nick_name","real_name","avatar","token","phone") | ||
1694 | |||
1695 | def get_token(self,obj): | ||
1696 | return obj.token | ||
1697 | |||
1698 | class AppVersionSerializer(serializers.ModelSerializer): | ||
1699 | is_force = serializers.SerializerMethodField() | ||
1700 | class Meta: | ||
1701 | model = models.AppVersion | ||
1702 | fields =("app_ver","app_no","os","url","remark","is_force") | ||
1703 | |||
1704 | def get_is_force(self,obj): | ||
1705 | app_version = self.context['app_version'] | ||
1706 | os = self.context['os'] | ||
1707 | force_exists = models.AppVersion.objects.filter(os=os,is_force=1,app_ver__gt=app_version,app_ver__lte=obj.app_ver,deleted_at=None).exists() | ||
1708 | if force_exists:return 1 | ||
1709 | else:return 0 | ||
1710 | |||
1711 | class SystemConfigSerializer(serializers.ModelSerializer): | ||
1712 | class Meta: | ||
1713 | model = models.SystemConfig | ||
1714 | fields =("name","content","remark","identifier","weight","updated_at","created_at") | ||
1715 | |||
1716 | |||
1717 | class SystemMsgTidingsSerializer(serializers.ModelSerializer): | ||
1718 | auther = serializers.SerializerMethodField() | ||
1719 | recommend_singers = serializers.SerializerMethodField() | ||
1720 | recommend_activitys = serializers.SerializerMethodField() | ||
1721 | sounds = serializers.SerializerMethodField() | ||
1722 | photos = serializers.SerializerMethodField() | ||
1723 | activity = serializers.SerializerMethodField() | ||
1724 | class Meta: | ||
1725 | model = models.UserHasTidings | ||
1726 | fields = "__all__" | ||
1727 | |||
1728 | def get_auther(self,obj): | ||
1729 | return UserListSerializer(models.Users.objects.filter(id=obj.user_id).first(),many=False).data | ||
1730 | |||
1731 | def get_recommend_singers(self,obj): | ||
1732 | user_ids = list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=1).values_list('value',flat=True)) | ||
1733 | return UserListSerializer(models.Users.objects.filter(id__in=user_ids,status=1,deleted_at=None).all(),many=True).data | ||
1734 | |||
1735 | def get_recommend_activitys(self,obj): | ||
1736 | activity_ids = list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=2).values_list('value',flat=True)) | ||
1737 | return TidingsActivity(models.Activitys.objects.filter(id__in=activity_ids,status=1,deleted_at=None).all(),many=True).data | ||
1738 | |||
1739 | def get_sounds(self,obj): | ||
1740 | return list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=3).order_by('created_at').values_list('value',flat=True)) | ||
1741 | |||
1742 | def get_photos(self,obj): | ||
1743 | return list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=4).order_by('created_at').values_list('value',flat=True)) | ||
1744 | |||
1745 | def get_activity(self, obj): | ||
1746 | return TidingsActivity(models.Activitys.objects.filter(id=obj.activity_id).first(), many=False).data | ||
1747 | |||
1748 | |||
1749 | class CommunityTidingsSerializer(serializers.ModelSerializer): | ||
1750 | user = serializers.SerializerMethodField() | ||
1751 | recommend_singers = serializers.SerializerMethodField() | ||
1752 | recommend_activitys = serializers.SerializerMethodField() | ||
1753 | sounds = serializers.SerializerMethodField() | ||
1754 | photos = serializers.SerializerMethodField() | ||
1755 | like_count = serializers.SerializerMethodField() | ||
1756 | unlike_count = serializers.SerializerMethodField() | ||
1757 | is_like = serializers.SerializerMethodField() | ||
1758 | is_unlike = serializers.SerializerMethodField() | ||
1759 | activity = serializers.SerializerMethodField() | ||
1760 | chat_count = serializers.SerializerMethodField() | ||
1761 | is_chat = serializers.SerializerMethodField() | ||
1762 | user_id = serializers.SerializerMethodField() | ||
1763 | comment_count = serializers.SerializerMethodField() | ||
1764 | # comments = serializers.SerializerMethodField() | ||
1765 | |||
1766 | class Meta: | ||
1767 | model = models.UserHasTidings | ||
1768 | fields = "__all__" | ||
1769 | |||
1770 | def get_is_chat(self,obj): | ||
1771 | user_id = self.context['user_id'] | ||
1772 | return models.TidingsHasChat.objects.filter(user_id=user_id,tidings_id=obj.id,).exists() | ||
1773 | |||
1774 | def get_chat_count(self,obj): | ||
1775 | return models.TidingsHasChat.objects.filter(tidings_id=obj.id).values('user_id').count() | ||
1776 | |||
1777 | def get_activity(self, obj): | ||
1778 | if obj.activity_id: | ||
1779 | return TidingsActivity(models.Activitys.objects.filter(id=obj.activity_id).first(), many=False).data | ||
1780 | else: | ||
1781 | return None | ||
1782 | |||
1783 | def get_user(self,obj): | ||
1784 | return TidingsUserSerializer(models.Users.objects.filter(id=obj.user_id).first(),many=False).data | ||
1785 | |||
1786 | def get_recommend_singers(self,obj): | ||
1787 | user_ids = list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=1).values_list('value',flat=True)) | ||
1788 | return TidingsUserSerializer(models.Users.objects.filter(id__in=user_ids,status=1,deleted_at=None).all(),many=True).data | ||
1789 | |||
1790 | def get_recommend_activitys(self,obj): | ||
1791 | activity_ids = list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=2).values_list('value',flat=True)) | ||
1792 | return TidingsActivity(models.Activitys.objects.filter(id__in=activity_ids,deleted_at=None).all(),many=True).data | ||
1793 | |||
1794 | def get_sounds(self,obj): | ||
1795 | return list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=3).order_by('created_at').values_list('value',flat=True)) | ||
1796 | |||
1797 | def get_photos(self,obj): | ||
1798 | return list(models.TidingsHasContents.objects.filter(tidings_id=obj.id,type=4).order_by('created_at').values_list('value',flat=True)) | ||
1799 | |||
1800 | def get_like_count(self,obj): | ||
1801 | return models.TidingsHasInteracts.objects.filter(type=1,type_id=obj.id,status=1,deleted_at=None).count() | ||
1802 | |||
1803 | def get_is_like(self, obj): | ||
1804 | user_id = self.context['user_id'] | ||
1805 | return models.TidingsHasInteracts.objects.filter(type=1, type_id=obj.id, status=1, user_id =user_id ,deleted_at=None).exists() | ||
1806 | |||
1807 | def get_unlike_count(self,obj): | ||
1808 | return models.TidingsHasInteracts.objects.filter(type=1,type_id=obj.id,status=2,deleted_at=None).count() | ||
1809 | |||
1810 | def get_is_unlike(self, obj): | ||
1811 | user_id = self.context['user_id'] | ||
1812 | return models.TidingsHasInteracts.objects.filter(type=1, type_id=obj.id, status=2, user_id =user_id ,deleted_at=None).exists() | ||
1813 | |||
1814 | def get_user_id(self,obj): | ||
1815 | return obj.user_id | ||
1816 | |||
1817 | def get_comment_count(self,obj): | ||
1818 | return models.TidingsHasComments.objects.filter(tidings_id=obj.id,deleted_at=None).count() | ||
1819 | # | ||
1820 | # def get_comments(self,obj): | ||
1821 | # queryset = models.TidingsHasComments.objects.filter(tidings_id=obj.id,deleted_at=None).order_by('created_at')[:3] | ||
1822 | # return TidingsHasCommentsSerializer(queryset,many=True).data | ||
1823 | |||
1824 | |||
1825 | class TidingsSeleteActivitySerializer(serializers.ModelSerializer): | ||
1826 | tags = serializers.SerializerMethodField() | ||
1827 | project = serializers.SerializerMethodField() | ||
1828 | view_count = serializers.SerializerMethodField() | ||
1829 | submit_count = serializers.SerializerMethodField() | ||
1830 | class Meta: | ||
1831 | model = models.Activitys | ||
1832 | fields = "__all__" | ||
1833 | |||
1834 | def get_view_count(self,obj): | ||
1835 | return models.UserViewActivity.objects.filter(activity_id=obj.id,deleted_at=None).all().count() | ||
1836 | |||
1837 | def get_tags(self, obj): | ||
1838 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1839 | flat=True) | ||
1840 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1841 | fields=['id', 'name']).data | ||
1842 | def get_project(self, obj): | ||
1843 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id,deleted_at=None,status=1).all(), many=True).data | ||
1844 | |||
1845 | def get_submit_count(self,obj): | ||
1846 | return models.ActivityHasUsers.objects.filter(activity_id=obj.id,type="Submit",deleted_at=None).count() | ||
1847 | |||
1848 | |||
1849 | class SystemMessageSerializer(serializers.ModelSerializer): | ||
1850 | sender = serializers.SerializerMethodField() | ||
1851 | class Meta: | ||
1852 | model = models.UserMessages | ||
1853 | fields = "__all__" | ||
1854 | |||
1855 | def get_sender(self,obj): | ||
1856 | return TidingsUserSerializer(models.Users.objects.filter(id=obj.sender_id).first(),many=False).data | ||
1857 | |||
1858 | class CustomerUserSerializer(serializers.ModelSerializer): | ||
1859 | info = serializers.SerializerMethodField() | ||
1860 | class Meta: | ||
1861 | model = models.Users | ||
1862 | fields = ('id','nick_name','avatar','info','identity') | ||
1863 | |||
1864 | def get_info(self,obj): | ||
1865 | return '使用中有任何问题,请咨询我:)' | ||
1866 | |||
1867 | |||
1868 | class SingerCompleteSerializer(serializers.ModelSerializer): | ||
1869 | tags = serializers.SerializerMethodField() | ||
1870 | project = serializers.SerializerMethodField() | ||
1871 | submit_info = serializers.SerializerMethodField() | ||
1872 | copyright = serializers.SerializerMethodField() | ||
1873 | |||
1874 | class Meta: | ||
1875 | model = models.Activitys | ||
1876 | fields = ("id", "status", "is_official", "cover", "song_name", "created_at","match_at", "sub_title", "guide", "lyric","clip_lyric", "tags", "project","submit_info","copyright") | ||
1877 | |||
1878 | |||
1879 | def get_tags(self, obj): | ||
1880 | tags = models.ActivityHasTags.objects.filter(activity_id=obj.id, deleted_at=None).values_list('tag_id', | ||
1881 | flat=True) | ||
1882 | return SystemTagsSerializer(models.SystemTags.objects.filter(deleted_at=None).in_bulk(tags).values(), many=True, | ||
1883 | fields=['id', 'name']).data | ||
1884 | def get_project(self, obj): | ||
1885 | return ProjectsSerializer(models.Projects.objects.filter(id=obj.project_id, deleted_at=None, status=1).all(),many=True).data | ||
1886 | |||
1887 | def get_submit_info(self, obj): | ||
1888 | user_id = self.context['user_id'] | ||
1889 | return ActivitysHasUserSerializer(models.ActivityHasUsers.objects.filter(activity_id=obj.id, user_id=user_id, type="Submit",deleted_at=None).first(), many=False).data | ||
1890 | |||
1891 | def get_copyright(self,obj): | ||
1892 | return SingerCompleteCopyrightSerializer(models.Users.objects.filter(id=obj.user_id).first(),many=False).data | ||
1893 | |||
1894 | |||
1895 | class SingerCompleteCopyrightSerializer(serializers.ModelSerializer): | ||
1896 | class Meta: | ||
1897 | model = models.Users | ||
1898 | fields = ('id','nick_name','real_name','avatar') | ||
1899 | |||
1900 | class SingerBusinessSerializer(serializers.ModelSerializer): | ||
1901 | class Meta: | ||
1902 | model = models.Users | ||
1903 | fields = ('id','nick_name','real_name','avatar') | ||
1904 | |||
1905 | class ChatRelationSerializer(serializers.ModelSerializer): | ||
1906 | is_invite = serializers.SerializerMethodField() | ||
1907 | identity = serializers.SerializerMethodField() | ||
1908 | is_group_out = serializers.SerializerMethodField() | ||
1909 | is_request = serializers.SerializerMethodField() | ||
1910 | project_invite_info = serializers.SerializerMethodField() | ||
1911 | project_out_info = serializers.SerializerMethodField() | ||
1912 | |||
1913 | class Meta: | ||
1914 | model = models.Users | ||
1915 | fields = ('id','is_invite','identity','is_group_out','is_request','project_invite_info','project_out_info') | ||
1916 | |||
1917 | def get_is_invite(self,obj): | ||
1918 | return models.GorupInvites.objects.filter(invite_id=self.context['receiver_id'],user_id=self.context['sender']['id'],status=1,type=1).exists() | ||
1919 | |||
1920 | def get_identity(self,obj): | ||
1921 | identity = '' | ||
1922 | is_relation = models.Users.objects.filter(id=self.context['sender']['id'], business_id=self.context['receiver_id']).exists() | ||
1923 | if is_relation: | ||
1924 | identity = '我的队长' | ||
1925 | is_relation = models.Users.objects.filter(id=self.context['receiver_id'], business_id=self.context['sender']['id']).exists() | ||
1926 | if is_relation: | ||
1927 | identity = '我的队员' | ||
1928 | return identity | ||
1929 | |||
1930 | def get_is_group_out(self,obj): | ||
1931 | query = models.GroupHasMembers.objects.filter(member_id=self.context['sender']['id'], role=1, deleted_at=None).first() | ||
1932 | group_id = query.group_id if query else 0 | ||
1933 | return models.GroupHasMembers.objects.filter(member_id=self.context['receiver_id'], group_id=group_id, status=2,deleted_at=None).exists() | ||
1934 | |||
1935 | def get_is_request(self,obj): | ||
1936 | return models.GorupInvites.objects.filter(invite_id=self.context['sender']['id'],user_id=self.context['receiver_id'],type=2,status=1).exists() | ||
1937 | |||
1938 | def get_project_invite_info(self,obj): | ||
1939 | project_ids = list(models.ProjectHasMembers.objects.filter(user_id=self.context['sender']['id'], invite_id=self.context['receiver_id'], status=0, deleted_at=None).values_list('project_id', flat=True)) | ||
1940 | projects = models.Projects.objects.filter(id__in=project_ids, status=1, deleted_at=None).values('id','name') | ||
1941 | if len(project_ids) > 0: | ||
1942 | id = projects[0]['id'] | ||
1943 | name = projects[0]['name'] | ||
1944 | else: | ||
1945 | id = 0 | ||
1946 | name = '' | ||
1947 | return {"id":id,"name":name,"count":len(projects)} | ||
1948 | |||
1949 | |||
1950 | def get_project_out_info(self,obj): | ||
1951 | query = models.ProjectHasMembers.objects.filter(user_id=self.context['receiver_id'], status=3,deleted_at=None).last() | ||
1952 | if query: | ||
1953 | project_id = query.project_id | ||
1954 | master_ids = list(models.UserHasProjects.objects.filter(project_id=project_id).values_list('user_id',flat=True)) | ||
1955 | if self.context['sender']['id'] in master_ids: | ||
1956 | is_project_out = True | ||
1957 | name = models.Projects.objects.filter(id=project_id).first().name | ||
1958 | id = project_id | ||
1959 | else: | ||
1960 | is_project_out = False | ||
1961 | name = '' | ||
1962 | id = 0 | ||
1963 | else: | ||
1964 | is_project_out = False | ||
1965 | name = '' | ||
1966 | id = 0 | ||
1967 | project_query = models.SystemConfig.objects.filter(identifier='VnyE3PTXOUPDEb4WZLBjM').first() | ||
1968 | limit_count = project_query.content if project_query else 7 | ||
1969 | project_out_info = {"is_out": is_project_out, "limit_count": limit_count,"name":name,'id':id} | ||
1970 | return project_out_info | ||
1971 | |||
1972 | class ChatAgentSerializer(serializers.ModelSerializer): | ||
1973 | business = serializers.SerializerMethodField() | ||
1974 | isfirst_agentchat = serializers.SerializerMethodField() | ||
1975 | chat_mode = serializers.SerializerMethodField() | ||
1976 | sender_chat_mode = serializers.SerializerMethodField() | ||
1977 | class Meta: | ||
1978 | model = models.Users | ||
1979 | fields = ('id', 'nick_name', 'real_name', 'avatar','chat_mode','sender_chat_mode','business','isfirst_agentchat') | ||
1980 | |||
1981 | def get_business(self,obj): | ||
1982 | if obj.business_id:return SingerBusinessSerializer(models.Users.objects.filter(id=obj.business_id).first(),many=False).data | ||
1983 | else:return None | ||
1984 | |||
1985 | def get_isfirst_agentchat(self,obj): | ||
1986 | send_id = self.context['send_id'] | ||
1987 | return not models.UserChatAgentRecords.objects.filter(send_id=send_id,user_id=obj.id,business_id=obj.business_id).exists() | ||
1988 | |||
1989 | def get_chat_mode(self,obj): | ||
1990 | send_id = self.context['send_id'] | ||
1991 | if send_id == obj.business_id:return 0 #如果是推荐人和歌手私聊不限制聊天 | ||
1992 | else:return obj.chat_mode | ||
1993 | |||
1994 | def get_sender_chat_mode(self,obj): | ||
1995 | send_id = self.context['send_id'] | ||
1996 | if send_id == obj.business_id: return 0 # 如果是推荐人和歌手私聊不限制聊天 | ||
1997 | return models.Users.objects.filter(id=send_id).first().chat_mode | ||
1998 | |||
1999 | class TidingsHasCommentsSerializer(serializers.ModelSerializer): | ||
2000 | user = serializers.SerializerMethodField() | ||
2001 | reply_to_user = serializers.SerializerMethodField() | ||
2002 | |||
2003 | class Meta: | ||
2004 | model = models.TidingsHasComments | ||
2005 | fields = ('id', 'tidings_id', 'user_id', 'content', 'created_at','user','reply_to_user') | ||
2006 | |||
2007 | def get_user(self,obj): | ||
2008 | return SingerBusinessSerializer(models.Users.objects.filter(id=obj.user_id).first(),many=False).data | ||
2009 | |||
2010 | def get_reply_to_user(self,obj): | ||
2011 | reply_user = models.TidingsHasComments.objects.filter(id=obj.parent_id).first() | ||
2012 | if reply_user:reply_user_id = reply_user.user_id | ||
2013 | else:return None | ||
2014 | return SingerBusinessSerializer(models.Users.objects.filter(id=reply_user_id).first(),many=False).data | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/templates/appshare.html
0 → 100644
1 | <!DOCTYPE html> | ||
2 | <html lang="zh-CN"> | ||
3 | <head> | ||
4 | <meta charset="UTF-8"> | ||
5 | <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.2,user-scalable=no" /> | ||
6 | <title>分享</title> | ||
7 | <!-- <link rel="stylesheet" href="style/style.css">--> | ||
8 | <style> | ||
9 | * { | ||
10 | margin: 0px; | ||
11 | padding: 0px; | ||
12 | } | ||
13 | |||
14 | /*默认640下,按着设计图25号字体*/ | ||
15 | body { | ||
16 | font-size: 0.25rem; | ||
17 | font-family: Microsoft YaHei, SimHei, SimSun; | ||
18 | background: #F7F7F7; | ||
19 | box-sizing: border-box; | ||
20 | } | ||
21 | |||
22 | html { | ||
23 | -webkit-text-size-adjust: 100%; | ||
24 | -ms-text-size-adjust: 100%; | ||
25 | } | ||
26 | |||
27 | ol, | ||
28 | ul, | ||
29 | li { | ||
30 | list-style: none; | ||
31 | } | ||
32 | |||
33 | table { | ||
34 | border-collapse: collapse; | ||
35 | } | ||
36 | |||
37 | h1, | ||
38 | h2, | ||
39 | h3, | ||
40 | h4, | ||
41 | h5, | ||
42 | h6, | ||
43 | small { | ||
44 | font-size: 100%; | ||
45 | font-weight: normal | ||
46 | } | ||
47 | |||
48 | input[type=button] { | ||
49 | -webkit-appearance: none; | ||
50 | /*去除iphone input默认样式*/ | ||
51 | } | ||
52 | |||
53 | input::-ms-clear { | ||
54 | display: none; | ||
55 | } | ||
56 | |||
57 | div { | ||
58 | box-sizing: border-box; | ||
59 | } | ||
60 | |||
61 | a, | ||
62 | a:hover { | ||
63 | text-decoration: none; | ||
64 | color: white; | ||
65 | } | ||
66 | |||
67 | .call { | ||
68 | color: #319de6; | ||
69 | text-decoration: none; | ||
70 | } | ||
71 | |||
72 | |||
73 | /*设置输入提示字体*/ | ||
74 | ::-webkit-input-placeholder { | ||
75 | color: #fff; | ||
76 | } | ||
77 | |||
78 | ::-moz-placeholder { | ||
79 | color: #fff; | ||
80 | } | ||
81 | |||
82 | :-moz-placeholder { | ||
83 | color: #fff; | ||
84 | } | ||
85 | |||
86 | input:-ms-input-placeholder, | ||
87 | textarea:-ms-input-placeholder { | ||
88 | color: #ffffff; | ||
89 | } | ||
90 | |||
91 | /* 清除浮动 */ | ||
92 | .clearfix:before, | ||
93 | .clearfix:after { | ||
94 | content: ""; | ||
95 | display: table; | ||
96 | } | ||
97 | |||
98 | .clearfix:after { | ||
99 | clear: both; | ||
100 | overflow: hidden; | ||
101 | } | ||
102 | |||
103 | .clearfix { | ||
104 | zoom: 1; | ||
105 | /* for ie6 & ie7 */ | ||
106 | } | ||
107 | |||
108 | .clear { | ||
109 | clear: both; | ||
110 | display: block; | ||
111 | } | ||
112 | |||
113 | body { | ||
114 | width: 100vw; | ||
115 | font-family: PingFang SC, PingFang SC-Medium; | ||
116 | } | ||
117 | |||
118 | .conBox { | ||
119 | z-index: 2; | ||
120 | width: 100vw; | ||
121 | display: flex; | ||
122 | flex-direction: column; | ||
123 | align-items: center; | ||
124 | background: #242521; | ||
125 | padding-bottom: 2.76rem; | ||
126 | } | ||
127 | .imgBox{ | ||
128 | display: flex; | ||
129 | flex-direction: column; | ||
130 | margin-top: 1.04rem; | ||
131 | } | ||
132 | .img1{ | ||
133 | width: 7.5rem; | ||
134 | height: 9.46rem; | ||
135 | } | ||
136 | .img2{ | ||
137 | width: 7.5rem; | ||
138 | height: 7.46rem; | ||
139 | } | ||
140 | .img3{ | ||
141 | width: 7.5rem; | ||
142 | height: 10.38rem; | ||
143 | } | ||
144 | |||
145 | |||
146 | .logoBox { | ||
147 | height: 1.04rem; | ||
148 | display: flex; | ||
149 | align-items: center; | ||
150 | position: fixed; | ||
151 | width: 100%; | ||
152 | top: 0; | ||
153 | left: 0; | ||
154 | z-index: 9; | ||
155 | padding-left: 0.38rem; | ||
156 | padding-right: 0.38rem; | ||
157 | background: #fff; | ||
158 | } | ||
159 | |||
160 | .logo { | ||
161 | height: 0.64rem; | ||
162 | width: 0.64rem; | ||
163 | } | ||
164 | |||
165 | .name { | ||
166 | margin-right: auto; | ||
167 | color: #333; | ||
168 | font-size: 0.32rem; | ||
169 | font-weight: 500; | ||
170 | margin-left: 0.12rem; | ||
171 | } | ||
172 | |||
173 | .btn { | ||
174 | width: 1.4rem; | ||
175 | height: 0.56rem; | ||
176 | background: linear-gradient(91deg, #ff9100 0%, #ff5100 100%); | ||
177 | border-radius: 1.2rem; | ||
178 | font-size: 0.24rem; | ||
179 | display: flex; | ||
180 | align-items: center; | ||
181 | justify-content: center; | ||
182 | } | ||
183 | |||
184 | .openApp { | ||
185 | width: 5.32rem; | ||
186 | height: 0.8rem; | ||
187 | color: #FFFFFF; | ||
188 | z-index: 2; | ||
189 | font-size: 0.28rem; | ||
190 | background: linear-gradient(90deg, #ff5100 0%, #ff9100 100%); | ||
191 | border-radius: 2rem; | ||
192 | position: fixed; | ||
193 | bottom: 0.96rem; | ||
194 | display: flex; | ||
195 | align-items: center; | ||
196 | justify-content: center; | ||
197 | } | ||
198 | |||
199 | .openDiv { | ||
200 | width: 100%; | ||
201 | display: flex; | ||
202 | align-items: center; | ||
203 | justify-content: center; | ||
204 | flex-direction: column; | ||
205 | margin-top: 0.48rem; | ||
206 | } | ||
207 | |||
208 | .openP { | ||
209 | font-size: 0.32rem; | ||
210 | color: #fff; | ||
211 | } | ||
212 | </style> | ||
213 | <!-- <script src="js/jquery-3.6.0.min.js"></script>--> | ||
214 | <script> | ||
215 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&D.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(j),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(j).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var D,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^([^.]*)(?:\.(.+)|)/;function we(){return!0}function Te(){return!1}function Ce(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ee(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ee(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Te;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Se(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,we)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=be.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=be.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click",we),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?we:Te,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Te,isPropagationStopped:Te,isImmediatePropagationStopped:Te,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=we,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=we,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=we,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Se(this,e,Ce),!1},trigger:function(){return Se(this,e),!0},_default:function(){return!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return Ee(this,e,t,n,r)},one:function(e,t,n,r){return Ee(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Te),this.each(function(){S.event.remove(this,e,n,t)})}});var ke=/<script|<style|<link/i,Ae=/checked\s*(?:[^=]|=\s*.checked.)/i,Ne=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function He(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Ae.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),He(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),De)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,qe),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(Ne,""),u,l))}return n}function Oe(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Le(o[r],a[r]);else Le(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return He(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||je(this,e).appendChild(e)})},prepend:function(){return He(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=je(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ke.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return He(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Re=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Me=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ie=new RegExp(ne.join("|"),"i");function We(e,t,n){var r,i,o,a,s=e.style;return(n=n||Re(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Pe.test(a)&&Ie.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function Fe(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var Be=["Webkit","Moz","ms"],$e=E.createElement("div").style,_e={};function ze(e){var t=S.cssProps[e]||_e[e];return t||(e in $e?e:_e[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Be.length;while(n--)if((e=Be[n]+t)in $e)return e}(e)||e)}var Ue=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ve={position:"absolute",visibility:"hidden",display:"block"},Ge={letterSpacing:"0",fontWeight:"400"};function Ye(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Qe(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Je(e,t,n){var r=Re(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=We(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Qe(e,t,n||(i?"border":"content"),o,r,a)+"px"}function Ke(e,t,n,r,i){return new Ke.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=We(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Xe.test(t),l=e.style;if(u||(t=ze(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Xe.test(t)||(t=ze(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=We(e,t,r)),"normal"===i&&t in Ge&&(i=Ge[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ue.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Je(e,u,n):Me(e,Ve,function(){return Je(e,u,n)})},set:function(e,t,n){var r,i=Re(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Qe(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Qe(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Ye(0,t,s)}}}),S.cssHooks.marginLeft=Fe(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(We(e,"marginLeft"))||e.getBoundingClientRect().left-Me(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Ye)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Re(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=Ke).prototype={constructor:Ke,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=Ke.propHooks[this.prop];return e&&e.get?e.get(this):Ke.propHooks._default.get(this)},run:function(e){var t,n=Ke.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ke.propHooks._default.set(this),this}}).init.prototype=Ke.prototype,(Ke.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[ze(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=Ke.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=Ke.prototype.init,S.fx.step={};var Ze,et,tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){et&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(ot):C.setTimeout(ot,S.fx.interval),S.fx.tick())}function at(){return C.setTimeout(function(){Ze=void 0}),Ze=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function lt(o,e,t){var n,a,r=0,i=lt.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=Ze||at(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:Ze||at(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=lt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ut,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(lt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],lt.tweeners[n]=lt.tweeners[n]||[],lt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],rt.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ut(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?lt.prefilters.unshift(e):lt.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=lt(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&it.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(st(r,!0),e,t,n)}}),S.each({slideDown:st("show"),slideUp:st("hide"),slideToggle:st("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(Ze=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),Ze=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){et||(et=!0,ot())},S.fx.stop=function(){et=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},tt=E.createElement("input"),nt=E.createElement("select").appendChild(E.createElement("option")),tt.type="checkbox",y.checkOn=""!==tt.value,y.optSelected=nt.selected,(tt=E.createElement("input")).value="t",tt.type="radio",y.radioValue="t"===tt.value;var ct,ft=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=ft[t]||S.find.attr;ft[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=ft[o],ft[o]=r,r=null!=a(e,t,n)?o:null,ft[o]=i),r}});var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(P)||[]).join(" ")}function gt(e){return e.getAttribute&&e.getAttribute("class")||""}function vt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,gt(this)))});if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,gt(this)))});if(!arguments.length)return this.attr("class","");if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,gt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=vt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=gt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+ht(gt(n))+" ").indexOf(t))return!0;return!1}});var yt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(yt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:ht(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!mt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,mt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,xt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,xt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var bt=C.location,wt={guid:Date.now()},Tt=/\?/;S.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||S.error("Invalid XML: "+(n?S.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Ct=/\[\]$/,Et=/\r?\n/g,St=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function At(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||Ct.test(n)?i(n,t):At(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)At(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)At(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&kt.test(this.nodeName)&&!St.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(Et,"\r\n")}}):{name:t.name,value:n.replace(Et,"\r\n")}}).get()}});var Nt=/%20/g,jt=/#.*$/,Dt=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\/\//,Ot={},Pt={},Rt="*/".concat("*"),Mt=E.createElement("a");function It(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Wt(t,i,o,a){var s={},u=t===Pt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Ft(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Mt.href=bt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Rt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,S.ajaxSettings),t):Ft(S.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=qt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||bt.href)+"").replace(Ht,bt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Mt.protocol+"//"+Mt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Wt(Ot,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Lt.test(v.type),f=v.url.replace(jt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Nt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Tt.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Dt,"$1"),o=(Tt.test(f)?"&":"?")+"_="+wt.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+Rt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Wt(Pt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&S.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},$t=S.ajaxSettings.xhr();y.cors=!!$t&&"withCredentials"in $t,y.ajax=$t=!!$t,S.ajaxTransport(function(i){var o,a;if(y.cors||$t&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Bt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=ht(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Xt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Xt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Vt=C.jQuery,Gt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Gt),e&&C.jQuery===S&&(C.jQuery=Vt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S}); | ||
216 | </script> | ||
217 | <!-- <script src="js/s.js"></script>--> | ||
218 | <script> | ||
219 | (function (doc, win) { | ||
220 | var docEl = doc.documentElement, | ||
221 | resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', | ||
222 | recalc = function () { | ||
223 | var clientWidth = docEl.clientWidth; | ||
224 | if (!clientWidth) return; | ||
225 | docEl.style.fontSize = 100 * (clientWidth / 750) + 'px'; | ||
226 | }; | ||
227 | |||
228 | if (!doc.addEventListener) return; | ||
229 | win.addEventListener(resizeEvt, recalc, false); | ||
230 | doc.addEventListener('DOMContentLoaded', recalc, false); | ||
231 | })(document, window); | ||
232 | </script> | ||
233 | </head> | ||
234 | <body> | ||
235 | <div class="conBox"> | ||
236 | <div class="logoBox"> | ||
237 | <img class="logo" src="https://hisin.oss-cn-hangzhou.aliyuncs.com/image/logo/logo.png"> | ||
238 | <span class="name">独家好歌,征集歌手</span> | ||
239 | <a class="btn" onclick="submitFn()">打开</a> | ||
240 | </div> | ||
241 | <div class="imgBox"> | ||
242 | <img class="img1" src="https://hisin.oss-cn-hangzhou.aliyuncs.com/image/logo/shareapp/1.png"> | ||
243 | <img class="img2" src="https://hisin.oss-cn-hangzhou.aliyuncs.com/image/logo/shareapp/2.png"> | ||
244 | <img class="img3" src="https://hisin.oss-cn-hangzhou.aliyuncs.com/image/logo/shareapp/3.png"> | ||
245 | </div> | ||
246 | |||
247 | <div class="openApp" onclick="submitFn()" >打开APP</div> | ||
248 | </div> | ||
249 | <!-- <script src="js/d.js"></script>--> | ||
250 | <script> | ||
251 | function submitFn() { | ||
252 | //判断浏览器 | ||
253 | var u = navigator.userAgent; | ||
254 | var d = new Date(); | ||
255 | var t0 = d.getTime(); | ||
256 | if(u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) { | ||
257 | //Android 向安卓同事索要链接 | ||
258 | if(openApp('hikoon.tech://hising/index')) { | ||
259 | openApp('hikoon.tech://hising/index'); | ||
260 | } else { | ||
261 | //由于打开需要1~2秒,利用这个时间差来处理--打开app后,返回h5页面会出现页面变成app下载页面,影响用户体验 | ||
262 | var delay = setInterval(function() { | ||
263 | var d = new Date(); | ||
264 | var t1 = d.getTime(); | ||
265 | if(t1 - t0 < 3000 && t1 - t0 > 2000) { | ||
266 | // alert('检测到未安装,请下载APP'); | ||
267 | window.location.href = "https://a.app.qq.com/o/simple.jsp?pkgname=com.hikoon.hising"; | ||
268 | } | ||
269 | if(t1 - t0 >= 3000) { | ||
270 | clearInterval(delay); | ||
271 | } | ||
272 | }, 1000); | ||
273 | } | ||
274 | } else if(u.indexOf('iPhone') > -1) { | ||
275 | //ios直接跳转到下载商店 | ||
276 | window.location.href = "https://apps.apple.com/us/app/%E6%B5%B7%E6%98%9F%E8%AF%95%E5%94%B1/id1636460395"; | ||
277 | }else{ | ||
278 | } | ||
279 | }; | ||
280 | |||
281 | function openApp(src) { | ||
282 | // 通过iframe的方式试图打开APP,如果能正常打开,会直接切换到APP,并自动阻止a标签的默认行为 | ||
283 | // 否则打开a标签的href链接 | ||
284 | var ifr = document.createElement('iframe'); | ||
285 | ifr.src = src; | ||
286 | ifr.style.display = 'none'; | ||
287 | document.body.appendChild(ifr); | ||
288 | window.setTimeout(function() { | ||
289 | document.body.removeChild(ifr); | ||
290 | }, 2000); | ||
291 | } | ||
292 | </script> | ||
293 | </body> | ||
294 | </html> | ||
295 |
api/templates/index.html
0 → 100644
File mode changed
api/templates/share.html
0 → 100644
This diff could not be displayed because it is too large.
api/templates/user_agreement.html
0 → 100644
1 | <html> | ||
2 | <head> | ||
3 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
4 | <meta http-equiv="Content-Style-Type" content="text/css" /> | ||
5 | <meta name="generator" content="Aspose.Words for .NET 15.1.0.0" /><title></title> | ||
6 | </head> | ||
7 | <body style="padding:50px;"> | ||
8 | <div style="line-height: 48px;"> | ||
9 | <p style="background-color:#ffffff; margin:0pt; orphans:0; text-align:center; widows:0"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">“海星试唱”微信小程序/APP</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">用户协议</span></p><p style="background-color:#ffffff; margin:0pt; orphans:0; text-align:justify; widows:0"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">欢迎使用“海星试唱”微信小程序/APP软件及服务!</span></p><p style="background-color:#ffffff; margin:0pt; orphans:0; text-align:justify; widows:0"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">为使用“海星试唱”微信小程序/APP软件(以下简称</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">“</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">本软件</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">”</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">)及服务,你应当阅读并遵守《“海星试唱”微信小程序/APP</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">用户协议</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">》(以下简称</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">“</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">本协议</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">”</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">)</span><span style="background-color:#ffffff; color:#333333; font-family:Calibri; font-size:12pt; font-weight:bold"> </span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">。请你务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款,并选择接受或不接受。限制、免责条款可能以加粗等形式提示你注意。</span></p><p style="background-color:#ffffff; margin:0pt; orphans:0; text-align:justify; widows:0"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">除非你已阅读并接受本协议所有条款,否则你无权下载、安装或使用本软件及相关服务。你的下载、安装、使用、注册、登录等行为即视为你已阅读并同意上述协议的约束。</span></p><p style="background-color:#ffffff; margin:0pt; orphans:0; text-align:justify; widows:0"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">如果你未满</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">18</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">周岁,请在法定监护人的陪同下阅读本协议及上述其他协议,并特别注意未成年人使用条款。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="color:#333333; font-family:楷体; font-size:12pt; font-weight:bold"> </span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1. 接受条款</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">本软件</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">根据以下服务条款为您提供服务。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">这些条款包括本软件</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">可能不断发布的关于本服务的相关协议、业务指引和规则</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">以及版权声明</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">等内容。上述内容一经正式发布,即为本协议不可分割的组成部分,你同样应当遵守</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">2. 服务说明</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">目前向合法注册用户提供</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">在线试听歌曲小样、在线试唱歌曲小样、自主上传试唱音频文件等</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">服务(以下简称“本服务”),您可以在</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">中</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:47:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">选择在线</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">录制并保存上传自己的</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:47:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">试唱</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:47:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">音频</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">或</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:47:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">选择以邮件方式获取对应试唱伴奏等资料后</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:48:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">在线下</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">您</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:48:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">自行</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">通过其他硬件录制的</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:49:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">试唱</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">音频上传至</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">。除非本使用协议另有其它明示规定,增加或强化目前本服务的任何新功能,包括所推出的新产品,均受到本使用协议之规范。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您了解并同意,本服务仅依其当前所呈现的状况提供,对于任何用户信息或个人化设定之时效、删除、传递错误、未予储存或其它任何问题,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">均不承担任何责任。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">保留不经事先通知为维修保养、升级或其它目的暂停本服务任何部分的权利,并无需承担任何责任。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:51:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">对于您</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:52:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">使用本软件服务</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:56:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">获取的试唱资料</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:30:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">(包括但不限于歌词、伴奏、音频等)</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:56:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">及</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:56:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">/或您</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:52:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">录制的试唱音</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:08:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">视</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:52:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">频</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:52:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:56:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:52:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">仅</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:56:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">能</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:57:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">用</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:53:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">于</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:09:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">个人试唱录制使用</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:09:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:09:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">并仅能</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:53:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">上传至本软件</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:53:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:53:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">未经</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:54:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱平台书面同意</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:55:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:55:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您不得</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:57:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">泄露给任何第三方或</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:55:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">发布在任何</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:55:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">其他</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:55:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">平台</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:55:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:13:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">本软件试唱资料及您使用</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:14:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">试唱资料制作的</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:57:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">全部</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:58:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">音乐作品</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:58:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">/录音</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:08:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">录像</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:58:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">制品</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:08:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">/视听作品</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:58:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">的</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:59:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">完整著作权和邻接权均归属于北京海葵科技有限公司</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:04:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">(以下简称“海葵”)</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:59:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">或其指定的第三方</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:30:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,您不得抄袭</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:31:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">、模仿或提前泄露在短视频或音乐平台</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:30:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,也不可在未取得</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:31:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海葵书面</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:30:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">许可的情况下翻唱、二次创作</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T14:59:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">。如因您未按规定使用本软件内的试唱资料</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:00:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">及</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:00:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">/或您</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:00:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">录制的试唱音</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:08:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">视</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:00:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">频</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:00:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">,海葵或其指定的第三方有权</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:02:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">要求您赔偿</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:04:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">因此造成的一切直接损失、间接损失(包括但不限于</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:05:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">词曲成本、软件运营成本、</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:04:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海葵支付的差旅费、律师费、公证费、诉讼/仲裁费、保全费、鉴定费等)</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:05:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">。</span></ins></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">3. 遵守法律</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:normal">您同意遵守中华人民共和国相关法律法规的所有规定,并对以任何方式使用本服务的任何行为及其结果承担全部责任。如您的行为违反国家法律和法规的任何规定,有可能构成犯罪的,将被追究刑事责任,并由您承担全部法律责任。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">同时如果</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有理由认为您的任何行为,包括但不限于您的任何言论和其它行为违反或可能违反国家法律和法规的任何规定,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">可在任何时候不经任何事先通知终止向您提供服务并删除相关言论、音视频等内容,并无需承担任何责任。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">未成年人用户及其监护人理解并确认,如您违反法律法规、本协议内容,则您及您的监护人应依照法律法规承担因此而导致的全部法律责任。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">4. 您的注册义务</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您注册成功后,本产品将为您提供一个帐号(下称“帐号”)。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您在申请使用本产品服务时,应当向我们提供真实、准确的个人资料,以完成实名认证;您应确保开通本服务所提供的姓名</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">、所属公司</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">等信息为本人所有,并授权我们通过依法成立的合法采集机构或认证机构对您所提供的信息的真实性和有效性进行认证。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">如个人资料有任何变动,您须及时在本产品中予以更新。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">为了能使用本服务全部功能,您同意以下事项:依本服务注册提示请您填写正确的</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:17:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">姓名、身份证号码、个人</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:17:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">实名</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">手机号、密码和艺名</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:17:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">等信息</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">,并确保今后更新的手机号、艺名、头像等资料的有效性和合法性。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">若您提供任何违法、不道德或</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">认为不适合在</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">上展示的资料</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:15:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">或使用他人信息</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:16:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">进行注册</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">;或者</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有理由怀疑你的资料属于程序或恶意操作,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有权暂停或终止您的帐号,并拒绝您于现在和未来使用本服务之全部或任何部分。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您理解并承诺,您所设置的</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">不得违反国家法律法规及“</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">”的相关规则,您的</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">名称、头像等注册信息及其他个人信息中不得出现违法和不良信息,未经他人许可不得用他人名义(包括但不限于冒用他人姓名、名称、字号、头像等或采取其他足以让人引起混淆的方式)开设</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">,不得恶意注册</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">(包括但不限于频繁注册、批量注册</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">等行为)。您在</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">注册及使用过程中需遵守相关法律法规,不得实施任何侵害国家利益、损害其他公民合法权益,有害社会道德风尚的行为。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">有权对您提交的注册信息进行审核。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="color:#333333; font-family:楷体; font-size:12pt"> </span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">5. 用户帐号、密码及安全</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">完成本服务的注册程序并成功注册之后,您可使用您的手机号和验证码,Email和密码,登录到您在</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">的帐号(下称“帐号”)。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">保护您的帐号安全,是您的责任。您应对所有使用您的密码及帐号(包括他人使用您的密码及帐号)的活动负完全的责任。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您同意:</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">1)您的</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号遭到未获授权的使用,或者发生其它任何安全问题时,您将立即通知</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">2)如果您未保管好自己的帐号和密码,因此而产生的任何损失或损害,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">不承担任何责任;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">3)</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">每个用户都要对其帐号中的所有行为和事件负全责。如果因您未保管好自己的帐号和密码而对您、</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">或第三方造成的损害,您将负全部责任。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">因</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">故意或者重大过失导致的损害除外;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">4)</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">如用户在申请开通服务后连续六个月未实际使用,则</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有权回收用户</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:06:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">帐号使用权</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">5)</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:07:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">每个用户仅能注册一个帐号,帐号所有权属于海星试唱平台所有,用户拥有使用权。</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您在“</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">”中的注册</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">仅限于您本人使用,未经</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">书面同意,禁止以任何形式赠与、借用、出租、转让、售卖或以其他方式许可他人使用该</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">。如果</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">发现或者有合理理由认为使用者并非</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">初始注册人,为保障</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">安全,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">有权立即暂停或终止向该注册</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">提供服务,并有权永久禁用该</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">。同时我们非常重视对未成年人个人信息的保护,未成年用户在填写个人信息时,请加强个人保护意识并谨慎对待,并应在取得监护人的同意以及在监护人指导下正确使用本软件及相关服务。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">6. </span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">用户隐私政策</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您提供的登记资料及</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">保留的有关您的若干其它资料将受到中国有关隐私的法律和本公司《用户隐私政策》之规范。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">7. 提供者之责任</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">根据有关法律法规,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">在此郑重提请您注意,</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:38:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">除本软件提供之试唱资料外</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:38:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">,</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">任何经由本服务而发布、上传的文字、资讯、资料、音频、视频、照片、图形、视讯、信息或其它资料(以下简称“内容 ”),无论系公开还是私下传送,均由内容提供者承担责任。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">仅为用户提供内容存储空间,无法控制经由本服务传送之内容,因此不保证内容的正确性、完整性、合法性或品质。您已预知使用本服务时,可能会接触到令人不快、不适当或令人厌恶之内容。在任何情况下,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">均不为任何内容负责,但</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">有权依法停止传输任何前述内容并采取相应行动,包括但不限于暂停用户使用本服务的全部或部分,删除相关内容,保存有关记录,并向有关机关报告。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">用户在录音时,如果使用其他的配乐、伴奏、照片等可能涉及第三方版权及其他权利的内容配合录制并上传,则用户需要确认对该配乐和伴奏、照片等享有相应使用权,否则</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">可删除您上传的内容。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">8. 用户行为</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">用户同意将不会利用本服务进行任何违法或不正当的活动,包括但不限于下列行为:</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">1)发布或以其它方式传送含有下列内容之一的信息:</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 反对宪法所确定的基本原则的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 损害国家荣誉和利益的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 煽动民族仇恨、民族歧视、破坏民族团结的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 破坏国家宗教政策,宣扬邪教和封建迷信的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 散布谣言,扰乱社会秩序,破坏社会稳定的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 侮辱或者诽谤他人,侵害他人合法权利的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 含有虚假、诈骗、有害、胁迫、侵害他人隐私、骚扰、侵害、中伤、粗俗、猥亵、或其它道德上令人反感的内容;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 含有中国法律、法规、规章、条例以及任何具有法律效力之规范所限制或禁止的其它内容的;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 含有</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">认为不适合在</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">展示的内容;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">2)以任何方式危害他人的合法权益;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">3)冒充其他任何人或机构,或以虚伪不实的方式陈述或谎称与任何人或机构有关;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">4)将依据任何法律或合约或法定关系(例如由于雇佣关系和依据保密合约所得知或揭露之内部资料、专属及机密资料)知悉但无权传送之任何内容加以发布、发送电子邮件或以其它方式传送;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">5)将侵害他人著作权、专利权、商标权、商业秘密、或其它专属权利(以下简称“专属权利”)之内容加以发布或以其它方式传送;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">6)将任何广告信函、促销资料、垃圾邮件、滥发信件、连锁信件、直销或其它任何形式的劝诱资料加以发布、发送或以其它方式传送;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">7)将设计目的在于干扰、破坏或限制任何计算机软件、硬件或通讯设备功能之计算机病毒(包括但不限于木马程序(trojan horses)、蠕虫(worms)、定时炸弹、删除蝇(cancelbots)(以下简称“病毒”)或其它计算机代码、档案和程序之任何资料,加以发布、发送或以其它方式传送;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">8)干扰或破坏本服务或与本服务相连线之服务器和网络,或违反任何关于本服务连线网络之规定、程序、政策或规范;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">9)跟踪、人肉搜索或以其它方式骚扰他人;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">10)故意或非故意地违反任何适用的当地、国家法律,以及任何具有法律效力的规则;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">11)未经合法授权而截获、篡改、收集、储存或删除他人个人信息、站内邮件或其它数据资料,或将获知的此类资料用于任何非法或不正当目的。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">12)含有任何下列损害未成年人身心健康和合法权益的行为和内容:</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 涉及未成年人色情低俗的内容;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 涉及侵害未成年人身体/财产/人格/隐私的行为;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 涉及未成年人不当行为的内容;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 涉及毒害未成年人身心健康和价值观的内容;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 涉及过度消费未成年人的内容;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 其他危害未成年人生命、财产、健康的行为和内容。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您已认可</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">未对用户的使用行为进行全面控制,您使用任何内容时,包括依赖前述内容之正确性、完整性、合法性、或实用性时,您同意将自行加以判断并承担所有风险,而不依赖于</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">。但</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">依其自行之考虑,拒绝和删除可经由本服务提供之违反本条款的或其它引起</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">反感的任何内容。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您了解并同意,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">依据法律法规的要求,或基于诚信为了以下目的或在合理必要范围内,认定必须将内容加以保存或揭露时,得加以保存或揭露:</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">a)遵守法律程序;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">b)执行本使用协议;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">c)回应任何第三人提出的权利主张;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">d)保护</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">、其用户及公众之权利、财产或个人安全;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">e)其它</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">认为有必要的情况。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#ff0000; font-family:楷体; font-size:12pt; font-weight:bold">9.</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:33:00'"><span style="background-color:#ffffff; color:#ff0000; font-family:楷体; font-size:12pt; font-weight:bold">权利声明</span></ins></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:33:00'"><span style="background-color:#ffffff; color:#ff0000; font-family:楷体; font-size:12pt; font-weight:bold">本软件的一切知识产权,以及与本软件相关的所有信息内容,包括但不限于:文字表述及其组合、图标、图饰、图像、图表、色彩、界面设计、版面框架、有关数据、附加程序、印刷材料或电子文档等均为海葵公司所有,受著作权法和国际著作权条约以及其他知识产权法律法规的保护。</span></ins></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">0</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 违约处理</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1)针对您违反本协议或其他服务条款的行为,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有权自行独立判断并视情况采取预先警示、拒绝发布、立即停止传输信息、删除评论、音频、视频、音视频等内容、短期禁止发言、限制</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">部分或者全部功能直至终止提供服务、永久关闭</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">等措施。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有权公告处理结果,且有权根据实际情况决定是否恢复相关</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T15:25:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">帐号</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">的使用。对涉嫌违反法律法规、涉嫌违法犯罪的行为,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">将保存有关记录,并有权依法向有关主管部门报告、配合有关主管部门调查、向公安机关报案等。对已删除内容</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有权不予恢复。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">2)因您违反本协议或其他服务条款规定,引起第三方投诉或诉讼索赔的,您应当自行处理并承担可能因此产生的全部法律责任。因您的违法或违约等行为导致</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">及其关联方、控制公司、继承公司向任何第三方赔偿或遭受国家机关处罚的,您还应足额赔偿</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">及其关联方、控制公司、继承公司因此遭受的全部损失。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">3)公司尊重并保护您及他人的知识产权、名誉权、姓名权、隐私权等合法权益。您保证,在使用“</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">”软件及相关服务时上传的文字、图片、视频、音频等不侵犯任何第三方的知识产权、名誉权、姓名权、隐私权等权利及合法权益。否则,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有权在收到权利方或者相关方通知的情况下移除该涉嫌侵权内容。针对第三方提出的全部权利主张,您应自行处理并承担可能因此产生的全部法律责任;如因您的侵权行为导致</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">及其关联方、控制公司、继承公司遭受损失的(包括但不限于经济、商誉等损失),您还应足额赔偿</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">及其关联方、控制公司、继承公司遭受的全部损失。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 复制、拷贝、出售、转售等的规定</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您同意不对本服务任何部分或本服务所使用或获得的内容,进行复制、拷贝、出售、转售或用于任何其它商业目的。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">2</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 关于使用及储存之一般措施</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您承认关于本服务的使用</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">有权制订一般措施及限制,包含但不限于本服务将保留所发布内容或其它发布内容之最长期间,以及一定期间内您使用本服务之次数上限(及每次使用时间之上限)。通过本服务发布或传送之任何信息、通讯资料和其它内容,如被删除或未予储存,您同意</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">毋须承担任何责任。您也同意,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">有权依其自行之考虑,不论通知与否,随时变更这些一般措施及限制。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">3</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 服务之修改</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">有权于任何时间暂时或永久修改或终止本服务(或其任何部分),且无论通知与否。您同意对于本服务所作的任何修改、暂停或终止,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">对您和任何第三人均无需承担任何责任。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">4</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 终止服务</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您同意</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">基于其自行之考虑,因任何理由,包含但不限于缺乏使用,或</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">认为您已经违反本使用协议的文字及精神,终止您的帐号或本服务之使用(或服务之任何部分),并将您在本服务内任何内容加以移除并删除。您同意依本使用协议任何规定提供之本服务,无需进行事先通知即可中断或终止,您承认并同意,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">可立即关闭或删除您的帐号及您帐号中所有相关信息及文件,及/或禁止继续使用前述文件或本服务。此外,您同意若本服务之使用被中断或终止或您的帐号及相关信息和文件被关闭或删除,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">对您或任何第三人均不承担任何责任。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">5</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. </span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">之专属权利</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">您了解并同意,本服务及本服务所使用之相关软件(以下简称“软件”)含有受到相关知识产权及其它法律保护之专有保密资料。您也了解并同意,经由本服务向您呈现</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">歌曲、歌词、专辑封面图片</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">内容,亦受到著作权、商标权、服务商标、专利权或其它专属权利之法律保护。未经</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">或</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:41:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海葵</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">明示授权,您不得修改、出租、出借、出售、散布本服务或软件之任何部份或全部,或据以制作衍生著作,或使用擅自修改后的软件,包括但不限于为了未经授权而使用本服务之目的。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">仅授予您个人、不可移转及非专属之使用权,使您得于单机计算机使用其软件之目的码,但您不得(并不得允许任何第三人)复制、修改、创作衍生著作、进行还原工程、反向组译,或以其它方式发现原始码,或出售、转让、再授权或提供软件设定担保,或以其它方式移转软件之任何权利。您同意将通过由</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">所提供的界面而非任何其它途径使用本服务。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">6</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 担保与保证</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您明确了解并同意∶</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1)本使用协议的任何规定不会免除</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">对造成您人身伤害的、或因故意或重大过失造成您财产损失的任何责任;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">2)您使用本服务之风险由您个人负担。本服务系依“现状”及“现有”基础提供。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">对“服务”、“资料”或“产品”不提供任何明示或默示的担保或保证,包含但不限于商业适售性、特定目的之适用性及未侵害他人权利等担保或保证;</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">对于因“服务”、“资料”或“产品”所生之任何直接、间接、附带的或因此而导致之衍生性损失不承担任何责任。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">3)</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">不保证以下事项∶</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 本服务将符合您的要求;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 本服务将不受干扰、及时提供、安全可靠或不会出错;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 使用本服务取得之结果正确可靠;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">* 您经由本服务购买或取得之任何产品、服务、资讯或其它信息将符合您的期望;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">4)是否使用本服务下载或取得任何资料应由您自行考虑且自负风险,因任何资料之下载而导致的您电脑系统之任何损坏或数据流失等后果,由您自行承担;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">5)您自</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">或经由本服务取得的任何建议或信息,无论是书面或口头形式,除非本使用协议有明确规定,将不构成本使用协议以外之任何保证。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">17</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 责任限制</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您明确了解并同意,基于以下原因而造成的,包括但不限于经济利益、信誉、应用、数据损失或其它无形损失,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">不承担任何直接、间接、连带、特别、衍生性或惩罚性赔偿责任:</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">1)本服务之使用或无法使用;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">2)为替换从或通过本服务购买或取得之任何商品、数据、信息、服务,收到的讯息,或缔结之交易而发生的成本;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">3)您的传输或数据遭到未获授权的存取或变造;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">4)任何第三方在本服务中所作之声明或行为;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">5)与本服务相关的其它事宜,但本使用协议有明确规定的除外;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">6)第三方以任何方式发布或投递欺诈性信息,或诱导用户受到经济损失,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">不承担任何责任。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">18</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. </span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">商标信息</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">网、</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">以及其它</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">注册商标、标志及产品、服务名称,均为</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">公司之商标(以下简称“</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">标记”)。未经</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">事先书面同意,您同意不将</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">标记以任何方式展示或使用或作其它处理,或表示您有权展示、使用或另行处理</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">标记。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">19</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 知识产权之保护</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">尊重他人的任何权利(包括知识产权),同时也要求我们的使用者也尊重他人之权利。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">在适当情况下,可自行决定终止侵害或违反他人权利之使用者的帐号并有权删除相关内容。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">如果您对他人的知识产权造成了侵害,</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">将依国家法律法规的规定,或在适当的情形下,将依其服务条款或其相关规范性规定,删除特定内容或以至终止您对账户的使用并有权删除相关内容。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">若您认为您的作品的著作权遭到侵害或您的知识产权被侵犯,根据《信息网络传播权保护条例》的规定,您需及时向</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">联系并提供详实的举证材料。或请到中华人民共和国国家版权局下载《要求删除或断开链接侵权网络内容的通知》(下称“删除通知”)的示范格式,如果您不明白“删除通知”的内容,请登录中华人民共和国国家版权局查看《要求删除或断开链接侵权网络内容的通知》填写说明。</span></p><p style="background-color:#ffffff; margin:0pt; text-align:justify"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">2</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">0</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">. 一般条款</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">1</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">)本使用协议及您与</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">之关系,均受到中华人民共和国法律管辖。</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">您与</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">就本服务、本使用协议或其它有关事项发生的争议,应首先友好协商解决,协商不成时应提请</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:47:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt; font-weight:bold">湖北省武汉市硚口区有管辖权的人民法院裁决</span></ins><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">2</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">)</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">未行使或执行本使用协议任何权利或规定,不构成对前述权利或权利之放弃;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">3</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">)倘本使用协议之任何规定因与中华人民共和国法律抵触而无效,您依然同意应依照法律,努力使该规定所反映之当事人意向具备效力,且本使用协议其它规定仍应具有完整的效力及效果;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">4</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">)本使用协议之标题仅供方便而设,不具任何法律或契约效果;</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">5</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">) 只要您登录了</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">,就代表您接受任何以上所有协议。</span><br /><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">6</span><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">)</span><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:49:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">海星试唱</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:48:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">有权随时根据有关法律、法规的变化以及公司经营状况和经营策略的调整等修改本协议,并随附于新版本软件。当发生有关争议时,以最新的协议</span></ins><ins style="-aw-revision-author:'FZ'; -aw-revision-datetime:'2022-05-07T16:48:00'"><span style="background-color:#ffffff; color:#333333; font-family:楷体; font-size:12pt">文本为准。如果不同意改动的内容,用户可以自行删除本软件。如果用户继续使用本软件,则视为您接受本协议的变动。</span></ins></p></div><div class="cnzz" style="display: none;"> | ||
10 | <script src="https://s23.cnzz.com/z_stat.php?id=1277655852&web_id=1277655852" language="JavaScript"></script> | ||
11 | </div> | ||
12 | <div class="docpe" style="position: absolute;color: white;margin-left:-450;"> | ||
13 | <a target="_blank" href="http://www.docpe.com">档铺网——在线文档免费处理</a> | ||
14 | </div> | ||
15 | </body> | ||
16 | </html> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/tests.py
0 → 100644
1 | # -*-coding:utf-8 -*- | ||
2 | import os | ||
3 | import requests | ||
4 | from pydub import AudioSegment | ||
5 | from django.core.cache import caches | ||
6 | import time, random, json | ||
7 | import base64 | ||
8 | import hashlib | ||
9 | from Crypto.Cipher import AES | ||
10 | from Crypto import Random | ||
11 | |||
12 | appid = "wx0f3844b1458ccfb9" | ||
13 | secret = "f9fa09c6cf3b4db19906d876d9c64755" | ||
14 | |||
15 | def split_mp3(): | ||
16 | |||
17 | new_name = './static/out444.mp3' | ||
18 | use_name = './static/12345.mp3' | ||
19 | input_music = AudioSegment.from_mp3(use_name) | ||
20 | # 截取音频后31000毫秒 = 31秒 | ||
21 | output_music = input_music[31000:] | ||
22 | # 保存音频,指定音频比特率为64k | ||
23 | output_music.export(new_name, bitrate="64k") | ||
24 | print(new_name + '完成!') | ||
25 | |||
26 | |||
27 | def WeChatApi(code): | ||
28 | appid = "wx0f3844b1458ccfb9" | ||
29 | secret = "f9fa09c6cf3b4db19906d876d9c64755" | ||
30 | parmas = { | ||
31 | 'appid': appid, | ||
32 | 'secret': secret, | ||
33 | 'js_code': code, | ||
34 | 'grant_type': 'authorization_code' | ||
35 | } | ||
36 | url = 'https://api.weixin.qq.com/sns/jscode2session' | ||
37 | r = requests.get(url, params=parmas).json() | ||
38 | print (r) | ||
39 | try: | ||
40 | return r['openid'],r['unionid'] | ||
41 | except: | ||
42 | return None,None | ||
43 | |||
44 | def get_access_toke(): | ||
45 | url = 'https://api.weixin.qq.com/cgi-bin/token' | ||
46 | parmas = { | ||
47 | "grant_type":"client_credential", | ||
48 | "appid":appid, | ||
49 | "secret":secret | ||
50 | } | ||
51 | r = requests.get(url,params=parmas).json() | ||
52 | print (r) | ||
53 | |||
54 | |||
55 | def WxPushInfo(data): | ||
56 | nickname = data['nickname'] | ||
57 | result = data['result'] | ||
58 | remarks = data['remarks'] | ||
59 | touser = data['touser'] | ||
60 | access_token = data['access_token'] | ||
61 | url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={}'.format(access_token) | ||
62 | postdata = { | ||
63 | "touser":touser, | ||
64 | "template_id":"B0s4RIurXwoegzK4tLWNU_H-xB2kUIE_E_ft5Ur6Auk", | ||
65 | "data":{ | ||
66 | "name10":{"value":nickname}, | ||
67 | "phrase5":{"value":result}, | ||
68 | "thing11":{"value":remarks} | ||
69 | } | ||
70 | } | ||
71 | r = requests.post(url, json=postdata).json() | ||
72 | print(r) | ||
73 | |||
74 | def GetWxToken(): | ||
75 | token = caches['default'].get('wx_access_token') | ||
76 | if not token: | ||
77 | appid = "wx0f3844b1458ccfb9" | ||
78 | secret = "f9fa09c6cf3b4db19906d876d9c64755" | ||
79 | url = 'https://api.weixin.qq.com/cgi-bin/token' | ||
80 | parmas = { | ||
81 | "grant_type":"client_credential", | ||
82 | "appid":appid, | ||
83 | "secret":secret | ||
84 | } | ||
85 | r = requests.get(url,params=parmas).json() | ||
86 | caches['default'].add('wx_access_token', r['access_token'] , r['expires_in']) #expires_in | ||
87 | return r['access_token'] | ||
88 | else: | ||
89 | return token | ||
90 | |||
91 | def Test(data): | ||
92 | import hashlib | ||
93 | channel = 'register_audit_channel' | ||
94 | open_id = data['open_id'] | ||
95 | url = 'http://hi-sing-admin-dev.hikoon.com/api/provider/wechat/pushSubscribeMessage' | ||
96 | md5_str = channel + open_id + 'tb0iwb7TE9TIbkG8iFsxldrHJRFdeP1g' | ||
97 | hl = hashlib.md5() | ||
98 | hl.update(md5_str.encode(encoding='utf8')) | ||
99 | secret = hl.hexdigest() | ||
100 | data = { | ||
101 | 'secret': secret, | ||
102 | 'channel': channel, | ||
103 | 'open_id': open_id, | ||
104 | 'data': data['data'] | ||
105 | } | ||
106 | r = requests.post(url,json=data).json() | ||
107 | print (r) | ||
108 | |||
109 | def test(): | ||
110 | import requests | ||
111 | url = "127.0.0.1:8000/api/register" | ||
112 | payload = { | ||
113 | "nick_name": "🍹🐼💑", | ||
114 | "real_name": "魏晗13457", | ||
115 | "phone": "17780983939", | ||
116 | "email": "17qwe111@qq.com", | ||
117 | "origin_type": "Other", | ||
118 | "remarks": "黄辉浩", | ||
119 | "role": "SystemUser", | ||
120 | "password": "112358ys", | ||
121 | "confirm_password": "112358ys", | ||
122 | "sms_code": 123456, | ||
123 | "vx_code":"051vPN000xA8EN1rW2100URGiX3vPN0t" | ||
124 | } | ||
125 | headers = { | ||
126 | 'Content-Type': 'application/json' | ||
127 | } | ||
128 | response = requests.request("POST", url, headers=headers, json=payload) | ||
129 | |||
130 | print(response.text) | ||
131 | |||
132 | |||
133 | def toMp3(): | ||
134 | import os | ||
135 | path = './static/' | ||
136 | file = '1234.m4a' | ||
137 | os.system("ffmpeg -i "+ path+file+ " " + path+ ".mp3" ) | ||
138 | |||
139 | |||
140 | |||
141 | class JPush(): | ||
142 | |||
143 | def __init__(self): | ||
144 | self.app_key = '860a3d4ecfaf3c38eb539c4e' | ||
145 | self.master_secret = 'df208c0eb485ed3ab3b18ff2' | ||
146 | |||
147 | def https_request(self, body, url, content_type=None, version=None, params=None): | ||
148 | https = requests.Session() | ||
149 | https.auth = (self.app_key,self.master_secret) | ||
150 | headers = {} | ||
151 | headers['user-agent'] = 'jpush-api-python-client' | ||
152 | headers['connection'] = 'keep-alive' | ||
153 | headers['content-type'] = 'application/json;charset:utf-8' | ||
154 | response = https.request('POST', url, data=body, params=params, headers=headers) | ||
155 | print (response.text) | ||
156 | print (dict(json.loads(response.content), **{'status_code': response.status_code})) | ||
157 | return dict(json.loads(response.content), **{'status_code': response.status_code}) | ||
158 | |||
159 | |||
160 | def push_params_v3(self,title,content, receiver_value=None,content_type=None, extras=None, platform="ios,android"): | ||
161 | sendno = int(random.randint(1, 999)) | ||
162 | payload = dict() | ||
163 | payload['platform'] = platform | ||
164 | payload['audience'] = { | ||
165 | "alias": receiver_value | ||
166 | } | ||
167 | payload["inapp_message"] = {"inapp_message": False} | ||
168 | payload['notification'] = { | ||
169 | "android": {"alert": content,"badge_add_num": 1,"alternate_alert": "","style": 0,"category": "","priority": 0,"title": title,"intent": {"url": ""},"alert_type": 7, "alternate_title": "", "extras": extras }, | ||
170 | "ios": {"alert": content, "sound": "default", "extras": extras}, | ||
171 | } | ||
172 | payload['options'] = {"apns_production": False, "time_to_live": 86400, 'sendno': sendno, | ||
173 | "third_party_channel":{ | ||
174 | "xiaomi": {"importance":"NORMAL","distribution":"secondary_push","distribution_fcm":"secondary_fcm_push"}, | ||
175 | "huawei": {"importance": "NORMAL"}, | ||
176 | # "honor": {"importance": "NORMAL"}, | ||
177 | # "meizu": {"importance": "NORMAL"}, | ||
178 | "oppo": {"importance": "NORMAL"}, | ||
179 | "vivo": {"importance": "NORMAL"}, | ||
180 | } | ||
181 | } | ||
182 | return payload | ||
183 | |||
184 | |||
185 | def jpush_v3(self, data): | ||
186 | payload = self.push_params_v3(title=data['title'],content=data['content'],content_type=data['content_type'],receiver_value=data['receiver_value'],extras=data['extras']) | ||
187 | body = json.dumps(payload) | ||
188 | return self.https_request(body, "https://api.jpush.cn/v3/push", 'application/json', version=1) | ||
189 | |||
190 | def get_alias(): | ||
191 | url = 'https://device.jpush.cn/v3/aliases/test189' | ||
192 | token = str(base64.b64encode(b'860a3d4ecfaf3c38eb539c4e:df208c0eb485ed3ab3b18ff2'),'utf-8') | ||
193 | print (token) | ||
194 | headers = { | ||
195 | 'Authorization': 'Basic {}'.format(token), | ||
196 | 'Accept': 'application / json' | ||
197 | } | ||
198 | resp = requests.get(url,headers=headers).text | ||
199 | print (resp) | ||
200 | |||
201 | def remove_alias(): | ||
202 | url = 'https://device.jpush.cn/v3/aliases/test189' | ||
203 | token = str(base64.b64encode(b'860a3d4ecfaf3c38eb539c4e:df208c0eb485ed3ab3b18ff2'), 'utf-8') | ||
204 | headers = { | ||
205 | 'Authorization': 'Basic {}'.format(token), | ||
206 | 'Accept': 'application / json' | ||
207 | } | ||
208 | data = { | ||
209 | "registration_ids":{"remove": ["121c83f760d835d731c"]} | ||
210 | } | ||
211 | resp = requests.post(url,headers=headers,json=data).text | ||
212 | print (resp) | ||
213 | |||
214 | |||
215 | def Msg_Push_Server(data): | ||
216 | secret = 'hNA32TZVxFGL9xv526Yg74XSNcutM3DiqfktZcHq0084jI6o2VetEjAndY8zlNTP' | ||
217 | p = '{channel}&{data}&{secret}&{time}'.format(channel=data['channel'],data=data['data'],secret=secret,time=data['time']).encode() | ||
218 | p = base64.b64encode(p) | ||
219 | hl = hashlib.md5() | ||
220 | hl.update(p) | ||
221 | sign = hl.hexdigest() | ||
222 | data['sign'] = sign | ||
223 | data['data'] = json.loads(data['data']) | ||
224 | url = "https://hi-sing-admin-dev.hikoon.com/api/provider" | ||
225 | resp = requests.request('POST',url,json=data).text | ||
226 | |||
227 | |||
228 | |||
229 | if __name__ == '__main__': | ||
230 | # data = {"title":"标题","content":"测试推送","content_type":"text","receiver_value":['test189'],"extras":{"type":"","value":""}} | ||
231 | # JPush().jpush_v3(data) | ||
232 | # TLSSigAPIv2.main() | ||
233 | |||
234 | # get_alias() | ||
235 | # remove_alias() | ||
236 | |||
237 | data = {"channel":"ActivityPublish","data":'{"activityId":69}',"time":int(time.time())} | ||
238 | Msg_Push_Server(data) |
api/verification.py
0 → 100644
1 | #-*-coding:utf-8 -*- | ||
2 | import logging | ||
3 | |||
4 | from django import forms | ||
5 | from rest_framework import serializers | ||
6 | |||
7 | def error_message(obj): | ||
8 | return list(obj.errors.values())[0][0] | ||
9 | |||
10 | class LoginVerify(serializers.Serializer): | ||
11 | phone = serializers.CharField(allow_blank=False,error_messages={"blank":"账号不能为空","required": "缺少必填参数phone"}) | ||
12 | password = serializers.CharField(allow_blank=False,error_messages={"blank":"密码不能为空","required": "缺少必填参数password"}) | ||
13 | |||
14 | class V2LoginVerify(serializers.Serializer): | ||
15 | phone = serializers.CharField(allow_null=False,error_messages={"blank":"账号不能为空","required": "缺少必填参数phone"}) | ||
16 | sms_code = serializers.IntegerField(allow_null=False,error_messages={"blank":"验证码不能为空","required": "缺少必填参数sms_code","invalid":"验证码只能是数字"}) | ||
17 | |||
18 | class SendVerify(serializers.Serializer): | ||
19 | phone = serializers.CharField(allow_blank=False,error_messages={"blank":"手机号不能为空","required": "缺少必填参数phone"}) | ||
20 | |||
21 | class v2SendVerify(serializers.Serializer): | ||
22 | phone = serializers.CharField(allow_blank=False,error_messages={"blank":"手机号不能为空","required": "缺少必填参数phone"}) | ||
23 | area_code = serializers.IntegerField(allow_null=False,error_messages={'invalid':'area_code数据格式错误',"blank":"区号不能为空","required": "缺少必填参数area_code"}) | ||
24 | |||
25 | class SingerRegister(forms.Form): | ||
26 | nick_name = forms.CharField(min_length=2,max_length=16,error_messages={"min_length":"昵称最小长度为2","max_length":"昵称最大长度为16","required": "昵称不能为空"}) | ||
27 | real_name = forms.CharField(error_messages={"required": "真名不能为空"}) | ||
28 | email = forms.EmailField(error_messages={"required": "邮箱不能为空", "invalid": "邮箱格式错误"}) | ||
29 | password = forms.CharField(error_messages={"required": "密码不能为空"}) | ||
30 | confirm_password = forms.CharField(error_messages={"required": "重复密码不能为空"}) | ||
31 | phone = forms.CharField(max_length=11,min_length=11,error_messages={"required": "手机号不能为空","max_length":"手机号码长度不正确","min_length":"手机号码长度不正确"}) | ||
32 | sms_code = forms.IntegerField(error_messages={"required": "验证码不能为空","invalid":"验证码只能是数字"}) | ||
33 | role = forms.CharField(error_messages={"required": "角色身份不能为空"}) | ||
34 | # vx_code = forms.CharField(error_messages={"required": "vx_code不能为空"}) | ||
35 | is_referee = forms.IntegerField(error_messages={"required": "推荐人不能为空"}) | ||
36 | province = forms.CharField(error_messages={"required": "所在省不能为空"}) | ||
37 | city = forms.CharField(error_messages={"required": "所在省不能为空"}) | ||
38 | is_push = forms.IntegerField(error_messages={"required": "is_push不能为空"}) | ||
39 | |||
40 | |||
41 | class V2SingerRegister(forms.Form): | ||
42 | nick_name = forms.CharField(min_length=2,max_length=16,error_messages={"min_length":"昵称最小长度为2","max_length":"昵称最大长度为16","required": "昵称不能为空"}) | ||
43 | real_name = forms.CharField(error_messages={"required": "真名不能为空"}) | ||
44 | email = forms.EmailField(error_messages={"required": "邮箱不能为空", "invalid": "邮箱格式错误"}) | ||
45 | area_code = forms.IntegerField(error_messages={'invalid':'area_code数据格式错误',"required": "缺少必填参数area_code"}) | ||
46 | phone = forms.CharField(error_messages={"required": "手机号不能为空"}) | ||
47 | sms_code = forms.IntegerField(error_messages={"required": "验证码不能为空","invalid":"验证码只能是数字"}) | ||
48 | role = forms.CharField(error_messages={"required": "角色身份不能为空"}) | ||
49 | is_referee = forms.IntegerField(error_messages={"required": "推荐人不能为空"}) | ||
50 | |||
51 | |||
52 | class V3UserRegister(forms.Form): | ||
53 | nick_name = forms.CharField(min_length=2, max_length=16,error_messages={"min_length": "昵称最小长度为2", "max_length": "昵称最大长度为16","required": "昵称不能为空"}) | ||
54 | real_name = forms.CharField(error_messages={"required": "真名不能为空"}) | ||
55 | email = forms.EmailField(error_messages={"required": "邮箱不能为空", "invalid": "邮箱格式错误"}) | ||
56 | area_code = forms.IntegerField(error_messages={"required": "缺少必填参数area_code",'invalid':'area_code数据格式错误'}) | ||
57 | phone = forms.CharField(error_messages={"required": "手机号不能为空"}) | ||
58 | sms_code = forms.IntegerField(error_messages={"required": "验证码不能为空", "invalid": "验证码只能是数字"}) | ||
59 | |||
60 | class BusinessRegister(forms.Form): | ||
61 | nick_name = forms.CharField(min_length=2,max_length=16,error_messages={"min_length":"昵称最小长度为2","max_length":"昵称最大长度为16","required": "昵称不能为空"}) | ||
62 | real_name = forms.CharField(error_messages={"required": "真名不能为空"}) | ||
63 | email = forms.EmailField(error_messages={"required": "邮箱不能为空", "invalid": "邮箱格式错误"}) | ||
64 | password = forms.CharField(error_messages={"required": "密码不能为空"}) | ||
65 | confirm_password = forms.CharField(error_messages={"required": "重复密码不能为空"}) | ||
66 | phone = forms.CharField(max_length=11,min_length=11,error_messages={"required": "手机号不能为空","max_length":"手机号码长度不正确","min_length":"手机号码长度不正确"}) | ||
67 | sms_code = forms.IntegerField(error_messages={"required": "验证码不能为空","invalid":"验证码只能是数字"}) | ||
68 | role = forms.CharField(error_messages={"required": "角色身份不能为空"}) | ||
69 | is_push = forms.IntegerField(error_messages={"required": "is_push不能为空"}) | ||
70 | # vx_code = forms.CharField(error_messages={"required": "vx_code不能为空"}) | ||
71 | company = forms.CharField(error_messages={"required": "所在公司不能为空"}) | ||
72 | |||
73 | class V2BusinessRegister(forms.Form): | ||
74 | nick_name = forms.CharField(min_length=2,max_length=16,error_messages={"min_length":"昵称最小长度为2","max_length":"昵称最大长度为16","required": "昵称不能为空"}) | ||
75 | real_name = forms.CharField(error_messages={"required": "真名不能为空"}) | ||
76 | email = forms.EmailField(error_messages={"required": "邮箱不能为空", "invalid": "邮箱格式错误"}) | ||
77 | area_code = forms.IntegerField(error_messages={'invalid':'area_code数据格式错误',"required": "缺少必填参数area_code"}) | ||
78 | phone = forms.CharField(error_messages={"required": "手机号不能为空"}) | ||
79 | sms_code = forms.IntegerField(error_messages={"required": "验证码不能为空","invalid":"验证码只能是数字"}) | ||
80 | role = forms.CharField(error_messages={"required": "角色身份不能为空"}) | ||
81 | company = forms.CharField(error_messages={"required": "所在公司不能为空"}) | ||
82 | |||
83 | |||
84 | class bind_verification(forms.Form): | ||
85 | vx_code = forms.CharField(error_messages={"required": "vx_code不能为空"}) | ||
86 | |||
87 | |||
88 | class reset_verification(forms.Form): | ||
89 | password = forms.CharField(error_messages={"required": "密码不能为空"}) | ||
90 | confirm_password = forms.CharField(error_messages={"required": "重复密码不能为空"}) | ||
91 | phone = forms.CharField(max_length=11,min_length=11,error_messages={"required": "手机号不能为空","max_length":"手机号码长度不正确","min_length":"手机号码长度不正确"}) | ||
92 | sms_code = forms.IntegerField(error_messages={"required": "验证码不能为空","invalid":"验证码只能是数字"}) | ||
93 | |||
94 | |||
95 | class examine_verification(forms.Form): | ||
96 | examine_id = forms.IntegerField(error_messages={"required": "待审核用户id不能为空"}) | ||
97 | examine_status = forms.IntegerField(error_messages={"required": "审核状态不能为空"}) | ||
98 | |||
99 | |||
100 | class view_activity_verification(forms.Form): | ||
101 | activity_id = forms.CharField(error_messages={"required": "活动id不能为空"}) | ||
102 | |||
103 | class update_user_verification(forms.Form): | ||
104 | avatar = forms.CharField(error_messages={"required": "头像不能为空"}) | ||
105 | |||
106 | class update_submit_verification(forms.Form): | ||
107 | activity_id = forms.CharField(error_messages={"required": "活动id不能为空"}) | ||
108 | has_id = forms.CharField(error_messages={"required": "关联id不能为空不能为空"}) | ||
109 | |||
110 | |||
111 | class singer_submit_examine_verification(forms.Form): | ||
112 | nick_name = forms.CharField(error_messages={"required": "昵称不能为空"}) | ||
113 | real_name = forms.CharField(error_messages={"required": "真名不能为空"}) | ||
114 | is_referee = forms.IntegerField(error_messages={"required": "推荐人不能为空"}) | ||
115 | province = forms.CharField(error_messages={"required": "所在省不能为空"}) | ||
116 | city = forms.CharField(error_messages={"required": "所在省不能为空"}) | ||
117 | |||
118 | |||
119 | class v2_singer_submit_examine_verification(forms.Form): | ||
120 | nick_name = forms.CharField(error_messages={"required": "缺少必填参数nick_name"}) | ||
121 | real_name = forms.CharField(error_messages={"required": "缺少必填参数real_name"}) | ||
122 | email = forms.CharField(error_messages={"required": "缺少必填参数email"}) | ||
123 | # business_id = forms.CharField(error_messages={"required": "缺少必填参数business_id"}) | ||
124 | is_referee = forms.IntegerField(error_messages={"required": "缺少必填参数is_referee"}) | ||
125 | |||
126 | |||
127 | class business_submit_examine_verification(forms.Form): | ||
128 | nick_name = forms.CharField(error_messages={"required": "昵称不能为空"}) | ||
129 | real_name = forms.CharField(error_messages={"required": "真名不能为空"}) | ||
130 | company = forms.CharField(error_messages={"required": "所在公司不能为空"}) | ||
131 | |||
132 | class v2_business_submit_examine_verification(forms.Form): | ||
133 | nick_name = forms.CharField(error_messages={"required": "缺少必填参数nick_name"}) | ||
134 | real_name = forms.CharField(error_messages={"required": "缺少必填参数real_name"}) | ||
135 | email = forms.CharField(error_messages={"required": "缺少必填参数email"}) | ||
136 | company = forms.CharField(error_messages={"required": "缺少必填参数company"}) | ||
137 | |||
138 | |||
139 | class user_tags_verification(forms.Form): | ||
140 | tags = forms.CharField(error_messages={"required": "标签不能为空"}) | ||
141 | |||
142 | |||
143 | class online_save_verification(forms.Form): | ||
144 | activity_id = forms.CharField(error_messages={"required": "活动id不能为空"}) | ||
145 | person_url = forms.CharField(error_messages={"required": "人声不能为空"}) | ||
146 | bg_url = forms.CharField(error_messages={"required": "混响程度 不能为空"}) | ||
147 | bg_volume = forms.FloatField(error_messages={"required": "伴奏音调不能为空"}) | ||
148 | person_volume = forms.FloatField(error_messages={"required": "人声音量不能为空"}) | ||
149 | offset = forms.IntegerField(error_messages={"required": "偏移量不能为空"}) | ||
150 | mix_type = forms.IntegerField(min_value=0,max_value=3,error_messages={"required": "混响程度 不能为空","min_value":"mix_type的值在0-3之间","max_value":"mix_type的值在0-3之间"}) | ||
151 | demo_url = forms.CharField() | ||
152 | |||
153 | |||
154 | |||
155 | class mixin_previews(forms.Form): | ||
156 | activity_id = forms.CharField(error_messages={"required": "活动id不能为空"}) | ||
157 | person_url = forms.CharField(error_messages={"required": "人声不能为空"}) | ||
158 | bg_url = forms.CharField(error_messages={"required": "混响程度 不能为空"}) | ||
159 | bg_volume = forms.FloatField(error_messages={"required": "伴奏音调不能为空"}) | ||
160 | person_volume = forms.FloatField(error_messages={"required": "人声音量不能为空"}) | ||
161 | offset = forms.IntegerField(error_messages={"required": "偏移量不能为空"}) | ||
162 | mix_type = forms.IntegerField(min_value=0,max_value=3,error_messages={"required": "混响程度 不能为空","min_value":"mix_type的值在0-3之间","max_value":"mix_type的值在0-3之间"}) | ||
163 | |||
164 | class part_mixin_previews(forms.Form): | ||
165 | activity_id = forms.CharField(error_messages={"required": "活动id不能为空"}) | ||
166 | person_url = forms.CharField(error_messages={"required": "人声不能为空"}) | ||
167 | bg_url = forms.CharField(error_messages={"required": "混响程度 不能为空"}) | ||
168 | bg_volume = forms.FloatField(error_messages={"required": "伴奏音调不能为空"}) | ||
169 | person_volume = forms.FloatField(error_messages={"required": "人声音量不能为空"}) | ||
170 | offset = forms.IntegerField(error_messages={"required": "偏移量不能为空"}) | ||
171 | mix_type = forms.IntegerField(min_value=0,max_value=3,error_messages={"required": "混响程度 不能为空","min_value":"mix_type的值在0-3之间","max_value":"mix_type的值在0-3之间"}) | ||
172 | start_time = forms.FloatField(error_messages={"required": "片段开始时间不能为空"}) | ||
173 | end_time = forms.FloatField(error_messages={"required": "片段结束时间不能为空"}) | ||
174 | |||
175 | |||
176 | class mixin_check(forms.Form): | ||
177 | id = forms.IntegerField(error_messages={"required": "id不能为空"}) | ||
178 | |||
179 | class aoto_submit(forms.Form): | ||
180 | url = forms.CharField(error_messages={"required": "url不能为空"}) | ||
181 | activity_id = forms.CharField(error_messages={"required": "activity_id不能为空"}) | ||
182 | type = forms.CharField(required=False, initial='Submit') | ||
183 | def clean_type(self): | ||
184 | value = self.cleaned_data.get('type', 'Submit') | ||
185 | if not value: | ||
186 | value = 'Submit' | ||
187 | elif value not in ['Submit','Save']: | ||
188 | raise forms.ValidationError('type 必须是Submit或者Save') | ||
189 | return value | ||
190 | |||
191 | class join_activity(forms.Form): | ||
192 | activity_id = forms.CharField(error_messages={"required": "缺少必要参数activity_id"}) | ||
193 | join_type = forms.CharField(error_messages={"required": "缺少必要参数join_type"}) | ||
194 | sing_type = forms.CharField(error_messages={"required": "缺少必要参数sing_type"}) | ||
195 | url = forms.CharField(error_messages={"required": "缺少必要参数url"}) | ||
196 | |||
197 | class collection(forms.Form): | ||
198 | activity_id = forms.CharField(error_messages={"required": "活动id不能为空"}) | ||
199 | |||
200 | |||
201 | class singer_update(forms.Form): | ||
202 | singer_id = forms.CharField(error_messages={"required": "歌手id不能为空"}) | ||
203 | rate = forms.CharField(error_messages={"required": "分成模式不能为空"}) | ||
204 | company = forms.CharField(error_messages={"required": "经纪公司不能为空"}) | ||
205 | |||
206 | class singer_updatev2(forms.Form): | ||
207 | singer_id = forms.CharField(error_messages={"required": "歌手id不能为空"}) | ||
208 | # rate = forms.CharField(error_messages={"required": "分成模式不能为空"}) | ||
209 | # company = forms.CharField(error_messages={"required": "经纪公司不能为空"}) | ||
210 | chat_mode = forms.IntegerField(min_value=0,max_value=1,error_messages={"min_value":"值在0-1之间","max_value":"值在0-1之间","required": "缺少chat_mode参数"}) | ||
211 | is_all = forms.IntegerField(min_value=0,max_value=1,error_messages={"min_value":"值在0-1之间","max_value":"值在0-1之间","required": "缺少is_all参数"}) | ||
212 | |||
213 | class user_activity_unlike(forms.Form): | ||
214 | activity_id = forms.CharField(error_messages={"required": "活动id不能为空"}) | ||
215 | |||
216 | |||
217 | class WechatAuth(forms.Form): | ||
218 | vx_code = forms.CharField(error_messages={"required": "缺少必要参数vx_code"}) | ||
219 | platform = forms.CharField(error_messages={"required": "缺少必要参数platform"}) | ||
220 | |||
221 | |||
222 | class EditorVerify(forms.Form): | ||
223 | field = forms.CharField(error_messages={"required": "缺少必要参数field"}) | ||
224 | value = forms.CharField(error_messages={"required": "缺少必要参数value"}) | ||
225 | |||
226 | class ConfirmSingerVerify(forms.Form): | ||
227 | activity_id = forms.IntegerField(error_messages={"required": "缺少必要参数activity_id"}) | ||
228 | singer_id = forms.CharField(error_messages={"required": "缺少必要参数singer_id"}) | ||
229 | status = forms.IntegerField(max_value=2,min_value=1,error_messages={"required": "缺少必要参数status","max_value":"最大值是2","min_value":"最小值是1"}) | ||
230 | |||
231 | class ChangePhoneVrify(forms.Form): | ||
232 | phone = forms.CharField(error_messages={"required": "缺少必要参数phone"}) | ||
233 | sms_code = forms.IntegerField(error_messages={"required": "缺少必要参数sms_code","invalid":"验证码只能是数字"}) | ||
234 | area_code = forms.IntegerField(error_messages={'invalid':'area_code数据格式错误',"required": "缺少必填参数area_code"}) | ||
235 | |||
236 | class PushNotifications(forms.Form): | ||
237 | title = forms.CharField(error_messages={"required": "缺少必要参数title"}) | ||
238 | content = forms.CharField(error_messages={"required": "缺少必要参数content"}) | ||
239 | receivers = forms.JSONField(error_messages={"required": "缺少必要参数receivers"}) | ||
240 | |||
241 | class UserSound(serializers.Serializer): | ||
242 | tags = serializers.JSONField(allow_null=True,error_messages={"required": "缺少必要参数tags"}) | ||
243 | sound_url = serializers.CharField(allow_blank=True, error_messages={"required": "缺少必要参数sound_url"}) | ||
244 | |||
245 | class CreataFollow(serializers.Serializer): | ||
246 | following_id = serializers.IntegerField(error_messages={"required": "缺少必要参数following_id"}) | ||
247 | |||
248 | class EditorUser(serializers.Serializer): | ||
249 | avatar = serializers.CharField(required=False) | ||
250 | cover = serializers.CharField(required=False) | ||
251 | nick_name = serializers.CharField(required=False,allow_blank=False, min_length=2,max_length=16,error_messages={"blank":"昵称不能为空","min_length":"长度不能小于2","max_length":"长度不能大于16"}) | ||
252 | sex = serializers.IntegerField(required=False,min_value=0,max_value=2,error_messages={'invalid':'sex数据格式错误',"min_value": "参数范围在0-2之间","max_value": "参数范围在0-2之间"}) | ||
253 | intro = serializers.CharField(required=False,allow_blank=True) | ||
254 | art_tag = serializers.JSONField(required=False) | ||
255 | style_tag = serializers.JSONField(required=False) | ||
256 | company = serializers.CharField(required=False,allow_blank=True) | ||
257 | province = serializers.CharField(required=False) | ||
258 | city = serializers.CharField(required=False) | ||
259 | |||
260 | class SplitAudio(serializers.Serializer): | ||
261 | activity_id = serializers.IntegerField(error_messages={"required": "缺少必要参数activity_id"}) | ||
262 | status = serializers.IntegerField(error_messages={"required": "缺少必要参数status"}) | ||
263 | |||
264 | |||
265 | class TidingsVerify(serializers.Serializer): | ||
266 | title = serializers.CharField(required=False,allow_blank=True, max_length=1000,error_messages={"max_length":"长度不能超过1000"}) | ||
267 | activity_ids = serializers.ListField(required=False,allow_null=True) | ||
268 | singer_ids = serializers.ListField(required=False,allow_null=True) | ||
269 | sounds = serializers.ListField(required=False,allow_null=True) | ||
270 | photos = serializers.ListField(required=False,max_length=3,allow_null=True,error_messages={"max_length":"长度不能超过3"}) | ||
271 | type = serializers.IntegerField(max_value=4,min_value=1 ,error_messages={"min_value":"type值范围在1~4","max_value":"type值范围在1~4","required":"缺少必要参数type"}) | ||
272 | |||
273 | class TidingsLimitVerify(serializers.Serializer): | ||
274 | tidings_id = serializers.IntegerField(error_messages={"required": "缺少必要参数tidings_id"}) | ||
275 | status = serializers.IntegerField(error_messages={"required": "缺少必要参数status"}) | ||
276 | |||
277 | class TidingsReportVerify(serializers.Serializer): | ||
278 | tidings_id = serializers.IntegerField(required=False,default=0,error_messages={"required": "缺少必要参数tidings_id"}) | ||
279 | reason = serializers.CharField(max_length=100,error_messages={"required": "缺少必要参数reason","max_length":"长度不能超过100","blank":"reason不能为空"}) | ||
280 | |||
281 | class TidingsRecordUserVerify(serializers.Serializer): | ||
282 | tidings_id = serializers.ListField(error_messages={"required": "缺少必要参数tidings_id"}) | ||
283 | |||
284 | |||
285 | class TidingsInteractsVerify(serializers.Serializer): | ||
286 | type = serializers.IntegerField(min_value=1,max_value=4,error_messages={"min_value":"type值范围在1~4","max_value":"type值范围在1~4","required": "缺少必要参数type"}) | ||
287 | type_id = serializers.IntegerField(error_messages={"required": "缺少必要参数type_id"}) | ||
288 | status = serializers.IntegerField(min_value=1,max_value=2,error_messages={"min_value":"status值范围在1~2","max_value":"status值范围在1~2","required": "缺少必要参数status"}) | ||
289 | |||
290 | |||
291 | class TidingsDeleteVerify(serializers.Serializer): | ||
292 | tidings_id = serializers.IntegerField(error_messages={"required": "缺少必要参数tidings_id"}) | ||
293 | |||
294 | |||
295 | class InteractsDeleteVerify(serializers.Serializer): | ||
296 | type = serializers.IntegerField(min_value=1,max_value=4,error_messages={"min_value":"type值范围在1~4","max_value":"type值范围在1~4","required": "缺少必要参数type"}) | ||
297 | type_id = serializers.IntegerField(error_messages={"required": "缺少必要参数type_id"}) | ||
298 | status = serializers.IntegerField(min_value=1,max_value=2,error_messages={"min_value":"status值范围在1~2","max_value":"status值范围在1~2","required": "缺少必要参数status"}) | ||
299 | |||
300 | |||
301 | class ShareUsersVerify(serializers.Serializer): | ||
302 | activity_id = serializers.IntegerField(error_messages={"required": "缺少必要参数activity_id"}) | ||
303 | share_id = serializers.IntegerField(required=False) | ||
304 | |||
305 | class TidingsChatVerify(serializers.Serializer): | ||
306 | tidings_id = serializers.IntegerField(error_messages={"required": "缺少必要参数tidings_id"}) | ||
307 | |||
308 | class UnlikeTidingsVerify(serializers.Serializer): | ||
309 | tidings_id = serializers.IntegerField(error_messages={"required": "缺少必要参数tidings_id"}) | ||
310 | |||
311 | |||
312 | class ChatAgentRecordVerify(serializers.Serializer): | ||
313 | user_id = serializers.IntegerField(error_messages={"required": "缺少必要参数user_id"}) | ||
314 | |||
315 | class PushTidingsCommentsVerify(serializers.Serializer): | ||
316 | tidings_id = serializers.IntegerField(error_messages={"required": "缺少必要参数tidings_id"}) | ||
317 | content = serializers.CharField(max_length=200,error_messages={"max_length":"评论字数超过限制","blank":"评论不能为空","required": "缺少必要参数content"}) | ||
318 | |||
319 | |||
320 | class DeleCommentsVerify(serializers.Serializer): | ||
321 | comment_id = serializers.IntegerField(error_messages={"required": "缺少必要参数comment_id"}) | ||
322 | |||
323 | class AvtivitysPriceVerification(serializers.Serializer): | ||
324 | activity_id = serializers.IntegerField(error_messages={"required": "缺少必要参数activity_id"}) | ||
325 | value = serializers.JSONField(error_messages={"required": "缺少必要参数value",'invalid':'value是json数据类型'}) | ||
326 | is_deduct = serializers.IntegerField(min_value=0,max_value=1,error_messages={"required": "缺少必要参数is_deduct","min_value":"is_deduct值范围在0~1","max_value":"is_deduct值范围在0~1"}) | ||
327 | is_talk = serializers.IntegerField(min_value=0,max_value=1,error_messages={"required": "缺少必要参数is_talk","min_value":"is_talk值范围在0~1","max_value":"is_talk值范围在0~1"}) | ||
328 | address_id = serializers.IntegerField(error_messages={"required": "缺少必要参数address_id"}) | ||
329 | is_accept_address = serializers.IntegerField(min_value=0,max_value=1,error_messages={"required": "缺少必要参数is_accept_address","min_value":"is_accept_address值范围在0~1","max_value":"is_accept_address值范围在0~1"}) | ||
330 | |||
331 | |||
332 | class SubmitPriceVerification(serializers.Serializer): | ||
333 | value = serializers.JSONField(error_messages={"required": "缺少必要参数value",'invalid':'value是json数据类型'}) | ||
334 | is_deduct = serializers.IntegerField(min_value=0,max_value=1,error_messages={"required": "缺少必要参数is_deduct","min_value":"is_deduct值范围在0~1","max_value":"is_deduct值范围在0~1"}) | ||
335 | is_talk = serializers.IntegerField(min_value=0,max_value=1,error_messages={"required": "缺少必要参数is_talk","min_value":"is_talk值范围在0~1","max_value":"is_talk值范围在0~1"}) | ||
336 | address_id = serializers.IntegerField(error_messages={"required": "缺少必要参数address_id"}) | ||
337 | is_accept_address = serializers.IntegerField(min_value=0,max_value=1,error_messages={"required": "缺少必要参数is_accept_address","min_value":"is_accept_address值范围在0~1","max_value":"is_accept_address值范围在0~1"}) | ||
338 | |||
339 |
api/views.py
0 → 100644
1 | # Create your views here\ | ||
2 | import datetime | ||
3 | from api import models | ||
4 | from HisinApi import settings | ||
5 | from django.conf import settings | ||
6 | from django.http import JsonResponse | ||
7 | from django.contrib.auth import get_user_model | ||
8 | import jwt | ||
9 | from django.forms.models import model_to_dict | ||
10 | from rest_framework.pagination import PageNumberPagination | ||
11 | from HisinApi.settings import OSS_BASE_FILE,OSS_ENDPOINT,OSS_ID,OSS_KEY,OSS_BUKET | ||
12 | import json | ||
13 | import oss2 | ||
14 | import random | ||
15 | import uuid | ||
16 | import librosa | ||
17 | import pydub | ||
18 | import matplotlib.pyplot as plt | ||
19 | import soundfile | ||
20 | import numpy as np | ||
21 | import time | ||
22 | import threading | ||
23 | import requests | ||
24 | from django.core.cache import caches | ||
25 | import hashlib | ||
26 | from django.utils import timezone | ||
27 | from api.loggin import logger | ||
28 | import base64 | ||
29 | from django_redis import get_redis_connection | ||
30 | import os,shutil | ||
31 | from django.db import transaction | ||
32 | import jieba | ||
33 | from api import schedules | ||
34 | |||
35 | |||
36 | |||
37 | from django.db import close_old_connections | ||
38 | |||
39 | UserModel = get_user_model() | ||
40 | |||
41 | #定义拆分文件线程最大数量 | ||
42 | sem = threading.Semaphore(4) | ||
43 | |||
44 | con = get_redis_connection("default") | ||
45 | |||
46 | |||
47 | def rate_limit(seconds=10): | ||
48 | def decorator(view): | ||
49 | def wrapper(request, *args, **kwargs): | ||
50 | now = time.time() | ||
51 | logger.info('session:{}'.format(request.session.items())) | ||
52 | request_time = request.session.get('request_time', 0) | ||
53 | interval_time = int(now - request_time) | ||
54 | logger.info("now:{},request_time:{}".format(now,request_time)) | ||
55 | logger.info('interval_time:{}'.format(interval_time)) | ||
56 | if interval_time < seconds: | ||
57 | request.session['request_time'] = time.time() | ||
58 | return JsonResponse(ResponseFactory(code=400,message="访问频繁,请稍后再试",data=None,status='fail')) | ||
59 | else: | ||
60 | request.session['request_time'] = time.time() | ||
61 | return view(request, *args, **kwargs) | ||
62 | return wrapper | ||
63 | return decorator | ||
64 | |||
65 | def upload_image(file): | ||
66 | """ | ||
67 | ! 上传单张图片 | ||
68 | :param file: b字节文件 | ||
69 | :return: 若成功返回图片路径,若不成功返回空 | ||
70 | """ | ||
71 | auth = oss2.Auth(OSS_ID, OSS_KEY) | ||
72 | bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUKET) | ||
73 | |||
74 | number = uuid.uuid4() | ||
75 | date = time.strftime("%Y-%m-%d", time.localtime()) | ||
76 | base_fil_name = 'image/' + date + '/' + str(number) + '.jpg' | ||
77 | file_name = OSS_BASE_FILE + base_fil_name | ||
78 | headers = dict() | ||
79 | headers["x-oss-storage-class"] = "Standard" | ||
80 | headers["x-oss-object-acl"] = oss2.OBJECT_ACL_PUBLIC_READ_WRITE | ||
81 | res = bucket.put_object(base_fil_name, file,headers=headers) | ||
82 | if res.status == 200: | ||
83 | return file_name | ||
84 | else: | ||
85 | return False | ||
86 | |||
87 | def upload_audio(file): | ||
88 | """ | ||
89 | ! 上传单张图片 | ||
90 | :param file: b字节文件 | ||
91 | :return: 若成功返回图片路径,若不成功返回空 | ||
92 | """ | ||
93 | auth = oss2.Auth(OSS_ID, OSS_KEY) | ||
94 | bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUKET) | ||
95 | number = uuid.uuid4() | ||
96 | date = time.strftime("%Y-%m-%d", time.localtime()) | ||
97 | base_fil_name = 'mp3/'+date+'/' + str(number) + '.mp3' | ||
98 | file_name = OSS_BASE_FILE+ base_fil_name | ||
99 | headers = dict() | ||
100 | headers["x-oss-storage-class"] = "Standard" | ||
101 | headers["x-oss-object-acl"] = oss2.OBJECT_ACL_PUBLIC_READ_WRITE | ||
102 | res = bucket.put_object(base_fil_name, file,headers=headers) | ||
103 | if res.status == 200: | ||
104 | return file_name | ||
105 | else: | ||
106 | return False | ||
107 | |||
108 | def auto_upload_audio(file,file_type): | ||
109 | """ | ||
110 | ! 上传单张图片 | ||
111 | :param file: b字节文件 | ||
112 | :return: 若成功返回图片路径,若不成功返回空 | ||
113 | """ | ||
114 | auth = oss2.Auth(OSS_ID, OSS_KEY) | ||
115 | bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUKET) | ||
116 | |||
117 | number = uuid.uuid4() | ||
118 | date = time.strftime("%Y-%m-%d", time.localtime()) | ||
119 | # file_type = file.name.split('.')[1] | ||
120 | # base_fil_name = 'mp3/'+date+'/' + str(number) + '.'+ file_type | ||
121 | base_fil_name = 'mp3/'+date+'/' + str(number) + '.' + file_type | ||
122 | |||
123 | file_name = OSS_BASE_FILE+ base_fil_name | ||
124 | headers = dict() | ||
125 | headers["x-oss-storage-class"] = "Standard" | ||
126 | headers["x-oss-object-acl"] = oss2.OBJECT_ACL_PUBLIC_READ_WRITE | ||
127 | res = bucket.put_object(base_fil_name, file,headers=headers) | ||
128 | if res.status == 200: | ||
129 | # return file_name,file_type | ||
130 | return file_name | ||
131 | |||
132 | else: | ||
133 | return False | ||
134 | |||
135 | |||
136 | class PageNumberPagination(PageNumberPagination): | ||
137 | page_size = 10 | ||
138 | page_size_query_param = 'size' | ||
139 | page_query_param = 'page' | ||
140 | max_page_size = None | ||
141 | |||
142 | def ResponseFactory(code,message,data,status): | ||
143 | return {'code':code,'message':message,'data':data,'status':status} | ||
144 | |||
145 | |||
146 | def AuthPermissionRequired(): | ||
147 | """ | ||
148 | 权限认证 | ||
149 | """ | ||
150 | def decorator(view_func): | ||
151 | def _wrapped_view(request, *args, **kwargs): | ||
152 | try: | ||
153 | auth = request.META.get('HTTP_AUTHORIZATION').split() | ||
154 | except AttributeError: | ||
155 | return JsonResponse(ResponseFactory(code=401,message="无身份验证头",data=None,status='fail')) | ||
156 | # 用户通过API获取数据验证流程 | ||
157 | if auth[0].lower() == 'token': | ||
158 | try: | ||
159 | dict = jwt.decode(auth[1], settings.SECRET_KEY, algorithms=['HS256']) | ||
160 | user_id = dict.get('data').get('id') | ||
161 | env = dict.get('data').get('env') | ||
162 | except jwt.ExpiredSignatureError: | ||
163 | return JsonResponse(ResponseFactory(code=401, message="身份验证过期", data=None, status='fail')) | ||
164 | except jwt.InvalidTokenError: | ||
165 | return JsonResponse(ResponseFactory(code=401, message="无效的身份验证", data=None, status='fail')) | ||
166 | except Exception as e: | ||
167 | return JsonResponse(ResponseFactory(code=401, message="无效的身份验证", data=None, status='fail')) | ||
168 | try: | ||
169 | if settings.ENV != env: | ||
170 | return JsonResponse(ResponseFactory(code=401, message="用户不存在", data=None, status='fail')) | ||
171 | user = UserModel.objects.get(id=user_id,deleted_at=None) | ||
172 | # 更新用户登录时间,由于登录入口比较多,登录时间难以维护,统一到这里维护 | ||
173 | UserModel.objects.filter(id=user_id, deleted_at=None).update(last_login = timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
174 | # 积分 | ||
175 | user_point_record(user_id, type='Login') | ||
176 | if user.status == 0: | ||
177 | return JsonResponse(ResponseFactory(code=401, message="用户已被禁用", data=None, status='fail')) | ||
178 | except UserModel.DoesNotExist: | ||
179 | return JsonResponse(ResponseFactory(code=401, message="用户不存在", data=None, status='fail')) | ||
180 | else: | ||
181 | return JsonResponse(ResponseFactory(code=401, message="不支持此类验证", data=None, status='fail')) | ||
182 | return view_func(request, *args, **kwargs) | ||
183 | return _wrapped_view | ||
184 | return decorator | ||
185 | |||
186 | def get_user_info(requests): | ||
187 | auth = requests.META.get('HTTP_AUTHORIZATION').split() | ||
188 | userId = jwt.decode(auth[1], settings.SECRET_KEY, algorithms=['HS256'])['data']['id'] | ||
189 | user = model_to_dict(models.Users.objects.get(id=userId)) | ||
190 | if user['business']:user['business_id'] = user['business'] | ||
191 | else:user['business_id'] = 0 | ||
192 | del user['password'] | ||
193 | return user | ||
194 | |||
195 | def object_to_json(obj): | ||
196 | return dict([(kk, obj.__dict__[kk]) for kk in obj.__dict__.keys() if kk != "_state"]) | ||
197 | |||
198 | |||
199 | |||
200 | class ChangeAudio(): | ||
201 | |||
202 | def __init__(self,file,base_path,type): | ||
203 | #### 文件变调 | ||
204 | plt.rcParams['font.sans-serif'] = ['SimHei'] | ||
205 | plt.rcParams['axes.unicode_minus'] = False | ||
206 | self.fs = 44100 | ||
207 | self.outPath = base_path+"/out" | ||
208 | self.wav_data, self.sr = librosa.load(file, sr=22050, mono=False) | ||
209 | self.type = type | ||
210 | |||
211 | def change_step(self,step): | ||
212 | with sem: | ||
213 | y_third = librosa.effects.pitch_shift(self.wav_data, self.sr, n_steps=step) | ||
214 | stereo = y_third.transpose() | ||
215 | _outpath = self.outPath+self.type+str(step)+'.wav' | ||
216 | soundfile.write(_outpath, stereo, self.sr) | ||
217 | sound = pydub.AudioSegment.from_wav(_outpath) | ||
218 | sound.export(self.outPath+self.type+str(step) + '.mp3', format="mp3") | ||
219 | |||
220 | def WeChatApi(code): | ||
221 | appid = "wx0f3844b1458ccfb9" | ||
222 | secret = "f9fa09c6cf3b4db19906d876d9c64755" | ||
223 | parmas = { | ||
224 | 'appid': appid, | ||
225 | 'secret': secret, | ||
226 | 'js_code': code, | ||
227 | 'grant_type': 'authorization_code' | ||
228 | } | ||
229 | url = 'https://api.weixin.qq.com/sns/jscode2session' | ||
230 | r = requests.get(url, params=parmas).json() | ||
231 | try: | ||
232 | return r['openid'],r['unionid'] | ||
233 | except: | ||
234 | return None,None | ||
235 | |||
236 | def AppWechatApi(code): | ||
237 | appid = 'wx78893f93dbc3a231' | ||
238 | secret = 'd709febdd41d0c966cc24bb9d93e2626' | ||
239 | url = 'https://api.weixin.qq.com/sns/oauth2/access_token' | ||
240 | parmas = { | ||
241 | 'appid': appid, | ||
242 | 'secret': secret, | ||
243 | 'code': code, | ||
244 | 'grant_type': 'authorization_code' | ||
245 | } | ||
246 | r = requests.get(url, params=parmas).json() | ||
247 | try: | ||
248 | return r['openid'], r['unionid'] | ||
249 | except: | ||
250 | return None, None | ||
251 | |||
252 | def GetWxToken(): | ||
253 | token = caches['default'].get('wx_access_token') | ||
254 | if not token: | ||
255 | appid = "wx0f3844b1458ccfb9" | ||
256 | secret = "f9fa09c6cf3b4db19906d876d9c64755" | ||
257 | url = 'https://api.weixin.qq.com/cgi-bin/token' | ||
258 | parmas = { | ||
259 | "grant_type":"client_credential", | ||
260 | "appid":appid, | ||
261 | "secret":secret | ||
262 | } | ||
263 | r = requests.get(url,params=parmas).json() | ||
264 | caches['default'].add('wx_access_token', r['access_token'] ,6000) #expires_in | ||
265 | return r['access_token'] | ||
266 | else: | ||
267 | return token | ||
268 | |||
269 | |||
270 | def pushSubscribeMessage(data): | ||
271 | channel = data['channel'] | ||
272 | open_ids = data['open_id'] | ||
273 | if settings.ENV == 'pro': | ||
274 | url = 'https://hi-sing-admin.hikoon.com/api/provider/wechat/pushSubscribeMessage' | ||
275 | else: | ||
276 | url = 'https://hi-sing-admin-dev.hikoon.com/api/provider/wechat/pushSubscribeMessage' | ||
277 | md5_str = channel + ''.join(open_ids) + 'tb0iwb7TE9TIbkG8iFsxldrHJRFdeP1g' | ||
278 | hl = hashlib.md5() | ||
279 | hl.update(md5_str.encode(encoding='utf8')) | ||
280 | secret = hl.hexdigest() | ||
281 | data = { | ||
282 | 'secret': secret, | ||
283 | 'channel': channel, | ||
284 | 'open_ids': open_ids, | ||
285 | 'data': data['data'] | ||
286 | } | ||
287 | requests.post(url,json=data).json() | ||
288 | |||
289 | def createMessage(data): | ||
290 | message_list = [] | ||
291 | for receiver in data['receivers']: | ||
292 | obj = models.UserMessages( | ||
293 | title = data.get('title',''), | ||
294 | content=data.get('content', ''), | ||
295 | sender_id = data.get('sender_id'), | ||
296 | receiver_id = receiver, | ||
297 | activity_id = data.get('activity_id',0), | ||
298 | type = data.get('type'), | ||
299 | is_read = 0, | ||
300 | is_bind = data.get('is_bind',0), | ||
301 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
302 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
303 | ) | ||
304 | message_list.append(obj) | ||
305 | models.UserMessages.objects.bulk_create(message_list) | ||
306 | |||
307 | def get_oss_file(url): | ||
308 | """[文件] | ||
309 | |||
310 | 内网访问oss资源 | ||
311 | :return: | ||
312 | """ | ||
313 | if settings.ENV == 'pro': | ||
314 | url = url.replace(settings.OSS_BASE_FILE,settings.OSS_INTERNAL) | ||
315 | return requests.get(url, verify=False).content | ||
316 | |||
317 | def deleteMessage(data): | ||
318 | models.UserMessages.objects.filter(sender_id=data['sender_id'],activity_id=data['activity_id'],type=data['type'],is_read=0).update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
319 | |||
320 | def user_point_record(user_id,type,singer_id=0,activity_id=0): | ||
321 | """ | ||
322 | :param user_id: | ||
323 | :param type: | ||
324 | :return: | ||
325 | """ | ||
326 | rules = { | ||
327 | 'Login':[1,None], | ||
328 | 'Listen':[None,None], | ||
329 | 'SubmitPart':[5,None], | ||
330 | 'SubmitFull':[2,None], | ||
331 | 'Confirm':[None,None], | ||
332 | 'ShareSong':[3,None], | ||
333 | 'BindSinger': [None,20], | ||
334 | 'SingerSubmitPart': [10, None], | ||
335 | 'SingerSubmitFull': [6, None], | ||
336 | 'SingerConfirm': [None, None], | ||
337 | 'Subscribe': [1, 1], | ||
338 | 'AutoSubmit' :[2,None], | ||
339 | 'SingerAutoSubmit':[6, None] | ||
340 | } | ||
341 | pointItem = rules.get(type,'') | ||
342 | if pointItem: | ||
343 | #一天内积分次数 | ||
344 | today = datetime.date.today().strftime('%Y-%m-%d') | ||
345 | oneday_count = models.UserPoints.objects.filter(type=type,user_id=user_id,created_at__gte=today).count() | ||
346 | history_count = models.UserPoints.objects.filter(type=type,user_id=user_id).count() | ||
347 | is_history = pointItem[1] == None or pointItem[1] > history_count | ||
348 | is_one = pointItem[0] == None or pointItem[0] > oneday_count | ||
349 | is_singer = not singer_id or not models.UserPoints.objects.filter(type=type, user_id=user_id,singer_id=singer_id,activity_id=activity_id) | ||
350 | is_activity = not activity_id or not models.UserPoints.objects.filter(type=type, user_id=user_id,activity_id=activity_id,singer_id=singer_id) | ||
351 | if is_one and is_history and is_singer and is_activity: | ||
352 | models.UserPoints.objects.create( | ||
353 | type = type, | ||
354 | user_id = user_id, | ||
355 | singer_id = singer_id, | ||
356 | activity_id = activity_id, | ||
357 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
358 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
359 | ) | ||
360 | |||
361 | class JPush(): | ||
362 | """ | ||
363 | 极光推送 | ||
364 | """ | ||
365 | def __init__(self): | ||
366 | self.app_key = settings.J_APP_KEY | ||
367 | self.master_secret = settings.J_MASTER_SECRET | ||
368 | |||
369 | def https_request(self, body, url, content_type=None, version=None, params=None): | ||
370 | https = requests.Session() | ||
371 | https.auth = (self.app_key,self.master_secret) | ||
372 | headers = {} | ||
373 | headers['user-agent'] = 'jpush-api-python-client' | ||
374 | headers['connection'] = 'keep-alive' | ||
375 | headers['content-type'] = 'application/json;charset:utf-8' | ||
376 | response = https.request('POST', url, data=body, params=params, headers=headers) | ||
377 | logger.info(dict(json.loads(response.content), **{'status_code': response.status_code})) | ||
378 | return dict(json.loads(response.content), **{'status_code': response.status_code}) | ||
379 | |||
380 | def push_params_v3(self,title,content, receiver_value=None,content_type=None, extras=None, platform="ios,android"): | ||
381 | sendno = int(random.randint(999, 999999)) | ||
382 | payload = dict() | ||
383 | payload['platform'] = platform | ||
384 | if settings.ENV == 'dev': | ||
385 | receiver_value = list('test'+str(i) for i in receiver_value) | ||
386 | apns_production = False | ||
387 | else: | ||
388 | apns_production = True | ||
389 | payload['audience'] = { | ||
390 | "alias": receiver_value | ||
391 | } | ||
392 | payload['notification'] = { | ||
393 | "android": {"alert": content, "badge_add_num": 1, "alternate_alert": "", "style": 0, "category": "", | ||
394 | "priority": 0, "title": title, "intent": {"url": ""}, "alert_type": 7, "alternate_title": "", | ||
395 | "extras": extras}, | ||
396 | "ios": {"alert": {"body": content,"title": title}, "sound": "default", "extras": extras}, | ||
397 | } | ||
398 | payload['options'] = {"apns_production": apns_production, "time_to_live": 86400 * 3, 'sendno': sendno, | ||
399 | "third_party_channel":{ | ||
400 | "xiaomi": {"importance":"NORMAL"}, | ||
401 | "huawei": {"importance": "NORMAL"}, | ||
402 | "honor": {"importance": "NORMAL"}, | ||
403 | "meizu": {"importance": "NORMAL"}, | ||
404 | "oppo": {"importance": "NORMAL"}, | ||
405 | "vivo": {"importance": "NORMAL"}, | ||
406 | } | ||
407 | } | ||
408 | logger.info(payload) | ||
409 | return payload | ||
410 | |||
411 | def jpush_v3(self, data): | ||
412 | payload = self.push_params_v3(title=data['title'],content=data['content'],content_type=data['content_type'],receiver_value=data['receiver_value'],extras=data['extras']) | ||
413 | body = json.dumps(payload) | ||
414 | return self.https_request(body, "https://api.jpush.cn/v3/push", 'application/json', version=1) | ||
415 | |||
416 | |||
417 | |||
418 | def Msg_Push_Server(data): | ||
419 | secret = settings.YJ_SECRET | ||
420 | p = '{channel}&{data}&{secret}&{time}'.format(channel=data['channel'],data=data['data'],secret=secret,time=data['time']).encode() | ||
421 | p = base64.b64encode(p) | ||
422 | hl = hashlib.md5() | ||
423 | hl.update(p) | ||
424 | sign = hl.hexdigest() | ||
425 | data['sign'] = sign | ||
426 | data['data'] = json.loads(data['data']) | ||
427 | logger.info("推送参数:{}".format(str(data))) | ||
428 | if settings.ENV == 'pro': | ||
429 | url = 'https://hi-sing-admin.hikoon.com/api/provider' | ||
430 | else: | ||
431 | url = 'https://hi-sing-admin-dev.hikoon.com/api/provider' | ||
432 | resp = requests.post(url,json=data).text | ||
433 | logger.info("推送结果:{}".format(str(resp))) | ||
434 | |||
435 | def remove_alias_device(alias): | ||
436 | try: | ||
437 | if settings.ENV == 'dev': | ||
438 | alias ='test' + str(alias) | ||
439 | #获取设备 | ||
440 | url = 'https://device.jpush.cn/v3/aliases/{}'.format(alias) | ||
441 | m_str = bytes('{}:{}'.format(settings.J_APP_KEY,settings.J_MASTER_SECRET), 'utf-8') | ||
442 | token = str(base64.b64encode(m_str), 'utf-8') | ||
443 | headers = { | ||
444 | 'Authorization': 'Basic {}'.format(token), | ||
445 | 'Accept': 'application / json' | ||
446 | } | ||
447 | resp = requests.get(url, headers=headers).json() | ||
448 | try: | ||
449 | registration_ids = resp['registration_ids'] | ||
450 | except: | ||
451 | registration_ids = [] | ||
452 | #删除设备 | ||
453 | headers = { | ||
454 | 'Authorization': 'Basic {}'.format(token), | ||
455 | 'Accept': 'application / json' | ||
456 | } | ||
457 | data = { | ||
458 | "registration_ids": {"remove":registration_ids } | ||
459 | } | ||
460 | requests.post(url, headers=headers, json=data) | ||
461 | except Exception as e: | ||
462 | print (e) | ||
463 | |||
464 | |||
465 | def upload_oss(file,activity_id,type,name): | ||
466 | """上传到oss,地址存入mysql""" | ||
467 | with open(file,'rb') as f: | ||
468 | data = f.read() | ||
469 | f.close() | ||
470 | url = upload_audio(data) | ||
471 | return url | ||
472 | |||
473 | def run_split_audio(activity_id, activity_status,push_date): | ||
474 | """ | ||
475 | :param activity_id: | ||
476 | :param activity_status: | ||
477 | :param push_date: | ||
478 | :return: | ||
479 | 拆分物料 | ||
480 | """ | ||
481 | # 文件目录定义 | ||
482 | t = str(int(time.time())) + str(random.randint(0, 100000)) | ||
483 | base_path = "./api/static/{}".format(t) | ||
484 | os.mkdir(base_path) | ||
485 | try: | ||
486 | # 下载活动物料 | ||
487 | close_old_connections() | ||
488 | activitys = models.Activitys.objects.filter(id=activity_id).first() | ||
489 | guide_file = requests.get(activitys.guide, verify=False).content | ||
490 | accompany_file = requests.get(activitys.karaoke, verify=False).content | ||
491 | f1 = base_path + '/guide.mp3' | ||
492 | f2 = base_path + '/accompany.mp3' | ||
493 | |||
494 | # #保存上传文件 | ||
495 | with open(f1, "wb") as ff: | ||
496 | ff.write(guide_file) | ||
497 | ff.close() | ||
498 | with open(f2, "wb") as fff: | ||
499 | fff.write(accompany_file) | ||
500 | fff.close() | ||
501 | guide_split_audio = ChangeAudio(file=f1, base_path=base_path, type='GuideDinging') | ||
502 | acc_split_audio = ChangeAudio(file=f2, base_path=base_path, type='Accompany') | ||
503 | |||
504 | for i in range(-3, 4): | ||
505 | guide_split_audio.change_step(i) | ||
506 | for i in range(-3, 4): | ||
507 | acc_split_audio.change_step(i) | ||
508 | |||
509 | # 上传文件到OSS,地址保存至数据库 | ||
510 | types = ['GuideDinging', 'Accompany'] | ||
511 | activitymaterials_obj_list = [] | ||
512 | for type in types: | ||
513 | for name in range(-3, 4): | ||
514 | file = base_path + '/out' + type + str(name) + '.mp3' | ||
515 | url = upload_oss(file, activity_id, type, name) | ||
516 | am_obj = models.ActivityMaterials( | ||
517 | activity_id=activity_id, | ||
518 | type=type, | ||
519 | url=url, | ||
520 | tone=name, | ||
521 | created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
522 | updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S") | ||
523 | ) | ||
524 | activitymaterials_obj_list.append(am_obj) | ||
525 | try: | ||
526 | close_old_connections() | ||
527 | with transaction.atomic(): | ||
528 | # 判断是否已存在数据 | ||
529 | is_exists = models.ActivityMaterials.objects.filter(activity_id=activity_id, | ||
530 | deleted_at=None).exists() | ||
531 | if is_exists: | ||
532 | # 先删掉之前的拆分物料 | ||
533 | models.ActivityMaterials.objects.filter(activity_id=activity_id).delete() | ||
534 | models.ActivityMaterials.objects.bulk_create(activitymaterials_obj_list) | ||
535 | # 改变活动状态 | ||
536 | models.Activitys.objects.filter(id=activity_id).update(status=activity_status, | ||
537 | updated_at=timezone.now().strftime( | ||
538 | "%Y-%m-%d %H:%M:%S")) | ||
539 | con.rpop('split_audio_queue') | ||
540 | # 触发消息推送 | ||
541 | data = {"channel": "ActivityPublish", "data": '{"activityId":' + str(activity_id) + '}', | ||
542 | "time": int(time.time())} | ||
543 | Msg_Push_Server(data) | ||
544 | except Exception as e: | ||
545 | logger.info('数据准备完成,同步数据库失败:{}'.format(e)) | ||
546 | # 删除拆分的文件 | ||
547 | shutil.rmtree(base_path) | ||
548 | except Exception as e: | ||
549 | # 删除拆分的文件 | ||
550 | shutil.rmtree(base_path) | ||
551 | logger.info('avtivity_split_error:{}'.format(e)) | ||
552 | #如果超过1天处理失败,则归为处理失败 | ||
553 | now = (datetime.datetime.now() + datetime.timedelta(days = -1)).strftime("%Y-%m-%d %H:%M:%S") | ||
554 | if now > push_date: | ||
555 | models.Activitys.objects.filter(id=activity_id).update(status=4, updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")) | ||
556 | # 队列去掉数据 | ||
557 | con.rpop('split_audio_queue') | ||
558 | time.sleep(5) | ||
559 | |||
560 | def senstive_word_check(text): | ||
561 | with open('./api/static/min_word.txt','rb') as f: | ||
562 | senstive_word = f.read().decode("utf-8").replace('\r', '') | ||
563 | f.close() | ||
564 | jieba.load_userdict('./api/static/min_word.txt') | ||
565 | word_list = jieba.lcut(text) | ||
566 | senstive_word_list = senstive_word.split('\n') | ||
567 | for word in word_list: | ||
568 | if word in senstive_word_list:return True | ||
569 | else:pass | ||
570 | return False | ||
571 | |||
572 | |||
573 | def user_permission(id): | ||
574 | """返回用户试听,试唱权限""" | ||
575 | permission = list() | ||
576 | #检测是否在试唱白名单 | ||
577 | singobj = models.SystemConfig.objects.filter(identifier='Jy-zgPbcSXSGnvHIx8moq', status=1,deleted_at=None).first() | ||
578 | if singobj: | ||
579 | if str(id) in singobj.content.split(','): | ||
580 | permission.append(2) | ||
581 | tags = list(models.UserTagRelations.objects.filter(user_id=id, type=4).values_list('tag_id', flat=True)) | ||
582 | if len(tags) == 0: return permission | ||
583 | expands = models.SystemTags.objects.filter(id__in=tags, deleted_at=None).values_list('expand', flat=True) | ||
584 | for expand in expands: | ||
585 | permission = permission + expand['permission'] | ||
586 | return permission | ||
587 | |||
588 | |||
589 | def push_relation(): | ||
590 | users = models.Users.objects.filter(deleted_at=None).all() | ||
591 | for user in users: | ||
592 | if user.business_id: | ||
593 | #创建群组 | ||
594 | models.Groups.objects.update_or_create(defaults = {'created_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
595 | 'updated_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S")}, user_id=user.business_id,deleted_at=None) | ||
596 | |||
597 | #加入群 | ||
598 | group_id = models.Groups.objects.filter(user_id=user.business_id).first().id | ||
599 | #团长入群 | ||
600 | models.GroupHasMembers.objects.update_or_create(group_id=group_id,member_id=user.business_id,deleted_at=None, defaults={"role":1,"created_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"),"updated_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S")}) | ||
601 | #成员入群 | ||
602 | models.GroupHasMembers.objects.update_or_create(group_id=group_id,member_id=user.id, deleted_at=None,defaults={"created_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S"),"updated_at":timezone.now().strftime("%Y-%m-%d %H:%M:%S")}) | ||
603 | |||
604 | # | ||
605 | # # #异步开启定时任务:活动拆分 | ||
606 | def startJob(): | ||
607 | while True: | ||
608 | try: | ||
609 | if con.llen("split_audio_queue") > 0: | ||
610 | last_index = con.llen("split_audio_queue") - 1 | ||
611 | item = eval(con.lindex('split_audio_queue',last_index)) | ||
612 | run_split_audio(item['id'],item['status'],item['time']) | ||
613 | else: | ||
614 | time.sleep(5) | ||
615 | except Exception as e: | ||
616 | time.sleep(60) | ||
617 | logger.info('拆分异常:{}'.format(e)) | ||
618 | |||
619 | t = threading.Thread(target=startJob) | ||
620 | t.setDaemon(True) | ||
621 | t.start() | ||
622 | |||
623 | # 异步开启定时任务:厂牌确认时间统计 | ||
624 | t1 = threading.Thread(target=schedules.run) | ||
625 | t1.setDaemon(True) | ||
626 | t1.start() | ||
627 | |||
628 | # t1 = threading.Thread(target=push_relation) | ||
629 | # t1.setDaemon(True) | ||
630 | # t1.start() | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
db.sqlite3
0 → 100644
File mode changed
manage.py
0 → 100644
1 | #!/usr/bin/env python | ||
2 | """Django's command-line utility for administrative tasks.""" | ||
3 | import os | ||
4 | import sys | ||
5 | |||
6 | |||
7 | def main(): | ||
8 | """Run administrative tasks.""" | ||
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'HisinApi.settings') | ||
10 | try: | ||
11 | from django.core.management import execute_from_command_line | ||
12 | except ImportError as exc: | ||
13 | raise ImportError( | ||
14 | "Couldn't import Django. Are you sure it's installed and " | ||
15 | "available on your PYTHONPATH environment variable? Did you " | ||
16 | "forget to activate a virtual environment?" | ||
17 | ) from exc | ||
18 | execute_from_command_line(sys.argv) | ||
19 | |||
20 | |||
21 | if __name__ == '__main__': | ||
22 | main() |
requirements.txt
0 → 100644
1 | aliyun-python-sdk-core==2.13.35 | ||
2 | aliyun-python-sdk-kms==2.15.0 | ||
3 | django==3.2.12 | ||
4 | django-redis-cache==3.0.1 | ||
5 | django-rest-jwt==0.1.46 | ||
6 | djangorestframework==3.13.1 | ||
7 | djangorestframework-jwt==1.11.0 | ||
8 | gevent==21.1.2 | ||
9 | mysql-connector-python==8.0.18 | ||
10 | oss2==2.14.0 | ||
11 | PyJWT==2.7.0 | ||
12 | PyMySQL==0.10.1 | ||
13 | redis==3.5.3 | ||
14 | requests==2.25.0 | ||
15 | django-ratelimit==3.0.1 | ||
16 | librosa==0.9.1 | ||
17 | pydub==0.25.1 | ||
18 | pyroomacoustics==0.7.3 | ||
19 | eyed3==0.9.6 | ||
20 | jieba==0.42.1 | ||
21 | twilio==8.2.0 | ||
22 | django_redis | ||
23 | matplotlib | ||
24 | schedule |
-
Please register or sign in to post a comment