Commit beadfd91 beadfd913ea6fa5906791a107c7ab3aba7c64c46 by 杨俊

Init

0 parents
No preview for this file type
1 .idea
2 *.exe
3 *.pyc
4 *.log
5 api/static
6 HisinApi/settings.py
...\ No newline at end of file ...\ No newline at end of file
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
No preview for this file type
1 import pymysql
2 pymysql.version_info = (1, 4, 13, "final", 0)
3 pymysql.install_as_MySQLdb()
...\ No newline at end of file ...\ No newline at end of file
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()
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
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()
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
No preview for this file type
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
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
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
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
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'))
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
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
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
File mode changed
1 from django.contrib import admin
1 from django.apps import AppConfig
2
3
4 class WxMiniapiConfig(AppConfig):
5 default_auto_field = 'django.db.models.BigAutoField'
6 name = 'api'
File mode changed
File mode changed
1 import logging
2
3
4 # 获取logger对象
5 logger = logging.getLogger(__name__)
...\ No newline at end of file ...\ No newline at end of file
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
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 = ()
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
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
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
File mode changed
This diff could not be displayed because it is too large.
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">&#xa0;</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">&#xa0;</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">&#xa0;</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
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)
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
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
File mode changed
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()
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