fix download function

storage_cloud
nineven 5 years ago
parent f9de02f139
commit 7147e09335
  1. 16
      fir_client/src/components/FirAppInfostimeline.vue
  2. 38
      fir_client/src/components/FirDownload.vue
  3. 22
      fir_client/src/restful/index.js
  4. 4
      fir_ser/api/urls.py
  5. 57
      fir_ser/api/utils/serializer.py
  6. 2
      fir_ser/api/utils/storage/aliyunApi.py
  7. 4
      fir_ser/api/utils/storage/localApi.py
  8. 2
      fir_ser/api/utils/storage/qiniuApi.py
  9. 4
      fir_ser/api/utils/storage/storage.py
  10. 4
      fir_ser/api/views/apps.py
  11. 142
      fir_ser/api/views/download.py
  12. 5
      fir_ser/api/views/login.py
  13. 3
      fir_ser/fir_ser/urls.py

@ -121,7 +121,7 @@
</template>
<script>
import {deletereleaseapp, getapptimeline, updatereleaseapp} from "../restful"
import {deletereleaseapp, getapptimeline, getdownloadurl, updatereleaseapp} from "../restful"
export default {
name: "FirAppInfostimeline",
@ -138,7 +138,19 @@
},
methods: {
downloadPackage(app){
window.location.href=app.download_url;
getdownloadurl(res=>{
if(res.code === 1000){
window.location.href=res.data.download_url;
}
}, {
'data': {
'token': app.download_token,
'short': this.currentapp.short,
'release_id': app.release_id,
"isdownload":true
},
'app_id': this.currentapp.app_id
})
},
previewRelase(app){
this.$router.push({name: 'FirDownload', params: { short: this.currentapp.short },query:{release_id:app.release_id}})

@ -63,7 +63,7 @@
<button v-if="isdownload" disabled="" class="loading" style="min-width: 43px; width: 43px; padding: 12px 0; border-top-color: transparent; border-left-color: transparent;">&nbsp;</button>
<button v-else @click="download" >
<el-link icon="el-icon-loadings" :href="downloadurl" type="primary" :underline="false"> 下载安装 </el-link>
<el-link icon="el-icon-loadings" type="primary" :underline="false"> 下载安装 </el-link>
</button>
</div>
@ -143,7 +143,7 @@
<script>
import QRCode from 'qrcodejs2'
import {getDownloadToken} from '../restful'
import {getShortAppinfo,getdownloadurl} from '../restful'
export default {
name: "FirDownload",
@ -159,13 +159,33 @@
wrong: false,
msg: '',
dchoice:false,
downloadtoken:"",
downloadurl:"",
isdownload:false,
}
}, methods: {
download() {
this.isdownload = true;
getdownloadurl(res=>{
if(res.code === 1000){
if(this.currentappinfo.type === 1){
this.downloadurl="itms-services://?action=download-manifest&url="+res.data.download_url;
}else{
if(this.agent !== ''){
this.downloadurl = res.data.download_url;
}
}
window.location.href=this.downloadurl;
}
}, {
'data': {
'token': this.mcurrentappinfo.download_token,
'short': this.currentappinfo.short,
'release_id': this.mcurrentappinfo.release_id,
},
'app_id': this.currentappinfo.app_id
})
},
qrcode() {
new QRCode('qrcode', {
@ -179,9 +199,8 @@
if(this.$route.query.release_id){
params["release_id"]=this.$route.query.release_id
}
getDownloadToken(data => {
getShortAppinfo(data => {
if (data.code === 1000) {
this.downloadtoken = data.data.download_token;
if(!data.data.master_release.release_id){
this.$message({
message:"该 release 版本不存在,请检查",
@ -253,15 +272,6 @@
this.miscomboappinfo={};
this.iscomboappinfo = {};
}
this.downloadurl = this.mcurrentappinfo.download_url;
if(this.currentappinfo.type ===1){
let ios_plist="&type=resigned.plist";
this.downloadurl="itms-services://?action=download-manifest&url="+this.downloadurl+ios_plist
}
if(this.mcurrentappinfo.binary_url && this.agent !== ''){
this.downloadurl=this.mcurrentappinfo.binary_url;
window.location.href=this.mcurrentappinfo.binary_url;
}
}
else {

@ -543,11 +543,11 @@ export function getapptimeline(callBack, params, load = true) {
}
/**获取下载token */
export function getDownloadToken(callBack, params, load = true) {
/**根据短链接获取应用信息 */
export function getShortAppinfo(callBack, params, load = true) {
getData(
false,
USERSEVER + '/download_token/' + params.short ,
USERSEVER + '/short/' + params.short ,
params,
data => {
callBack(data);
@ -597,6 +597,22 @@ export function getuploadToken(callBack, params, load = true) {
);
}
/**获取下载的url */
export function getdownloadurl(callBack, params, load = true) {
getData(
false,
USERSEVER + '/install/'+params.app_id ,
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}
export function uploadstorage(certinfo,file,successCallback,processCallback) {
let config = {

@ -21,7 +21,7 @@ from api.views.logout import LogoutView
from api.views.captcha import CaptchaView
from api.views.apps import AppsView,AppInfoView,AppReleaseinfoView
from api.views.localuploads import UploadView,UploadImgView
from api.views.download import DownloadTokenView
from api.views.download import ShortDownloadView
from api.views.uploads import OssUploadView
@ -39,6 +39,6 @@ urlpatterns = [
re_path("^upload$",UploadView.as_view()),
re_path("^img/upload$",UploadImgView.as_view()),
re_path("^userinfo",UserInfoView.as_view()),
re_path("^download_token/(?P<short>\w+)$", DownloadTokenView.as_view()),
re_path("^short/(?P<short>\w+)$", ShortDownloadView.as_view()),
re_path("^qiniuupload$", OssUploadView.as_view()),
]

@ -1,11 +1,11 @@
from rest_framework import serializers
from api import models
from api.utils.app.apputils import bytes2human
from api.utils.storage.storage import Storage
from api.utils.TokenManager import DownloadToken
import os
token_obj = DownloadToken()
class UserInfoSerializer(serializers.ModelSerializer):
# gender = serializers.SerializerMethodField(source="get_gender_display")
@ -45,7 +45,7 @@ class AppsSerializer(serializers.ModelSerializer):
release_id=self.context.get("release_id")).first()
if master_release_obj:
icon_url = "/".join([obj.user_id.domain_name, master_release_obj.icon_url])
icon_url = ""
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
@ -63,35 +63,30 @@ class AppsSerializer(serializers.ModelSerializer):
"binary_url":master_release_obj.binary_url,
}
if self.context.get("download_token", None) and self.context.get("download_token") != "download_token":
download_url = "/".join([obj.user_id.domain_name, "download", master_release_obj.release_id])
download_url = download_url + "?token=" + self.context.get("download_token")
if obj.type == 0:
apptype='.apk'
else:
apptype = '.ipa'
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
download_url = storage.get_download_url(master_release_obj.release_id+apptype)
datainfo["download_url"] = download_url
download_url = ""
# if self.context.get("storage", None) and self.context.get("storage") != "undefined":
# if obj.type == 0:
# apptype = '.apk'
# else:
# apptype = '.ipa'
# storage = self.context.get("storage", None)
# download_url = storage.get_download_url(master_release_obj.release_id+apptype)
download_token = token_obj.make_token(master_release_obj.release_id,600)
datainfo["download_token"] = download_token
return datainfo
else:
return {}
class AppReleaseSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppReleaseInfo
fields = ["app_version", "icon_url", "build_version",
"release_type", "minimum_os_version",
"created_time", "binary_size", "release_id", "size", "type", "editing", "master_color", "changelog",
"is_master",'download_url','binary_url']
download_url = serializers.SerializerMethodField()
"is_master",'download_token','binary_url']
download_token = serializers.SerializerMethodField()
size = serializers.SerializerMethodField()
type = serializers.SerializerMethodField()
editing = serializers.SerializerMethodField()
@ -104,19 +99,19 @@ class AppReleaseSerializer(serializers.ModelSerializer):
def get_binary_size(self,obj):
return bytes2human(obj.binary_size)
def get_download_url(self,obj):
def get_download_token(self,obj):
# download_url = "/".join([obj.app_id.user_id.domain_name, "download", obj.release_id])
# download_url = download_url + "?token=" + make_download_token(obj.release_id,300)
download_url=''
if obj.release_type == 0:
apptype = '.apk'
else:
apptype = '.ipa'
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
download_url = storage.get_download_url(obj.release_id + apptype)
return download_url
# if obj.release_type == 0:
# apptype = '.apk'
# else:
# apptype = '.ipa'
# if self.context.get("storage", None) and self.context.get("storage") != "undefined":
# storage = self.context.get("storage", None)
# download_url = storage.get_download_url(obj.release_id + apptype)
download_token = token_obj.make_token(obj.release_id, 600)
return download_token
def get_icon_url(self, obj):
icon_url="/".join([obj.app_id.user_id.domain_name, obj.icon_url])

@ -98,7 +98,7 @@ class AliYunOss(object):
auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token)
self.bucket = oss2.Bucket(auth, self.endpoint,self.bucket_name)
def get_download_url(self,name,expires=1800):
def get_download_url(self,name,expires=1800,ftype=None):
# self.get_auth_bucket(name,expires)
private_url=self.bucket.sign_url('GET',name,expires)
print(private_url)

@ -18,10 +18,12 @@ class LocalStorage(object):
dtoken = DownloadToken()
return dtoken.make_token(name,expires)
def get_download_url(self,name,expires=1800):
def get_download_url(self,name,expires=1800,ftype=None):
dtoken = DownloadToken()
base_url = '/'.join([self.domain_name,'download', name])
download_url = base_url + "?token=" + dtoken.make_token(name,expires)
if ftype:
download_url = download_url + '&ftype=' + ftype
return download_url
def del_file(self,name):

@ -31,7 +31,7 @@ class QiNiuOss(object):
# print(token)
return token
def get_download_url(self,name,expires=1800):
def get_download_url(self,name,expires=1800,ftype=None):
#有两种方式构造base_url的形式
base_url = '%s/%s' % (self.domain_name, name)
#或者直接输入url的方式下载

@ -19,9 +19,9 @@ class Storage(object):
if self.storage:
return self.storage.get_upload_token(filename, expires)
def get_download_url(self, filename, expires=1800):
def get_download_url(self, filename, expires=1800,ftype=None):
if self.storage:
return self.storage.get_download_url(filename, expires)
return self.storage.get_download_url(filename, expires,ftype)
def delete_file(self, filename, apptype=None):
if self.storage:

@ -16,7 +16,6 @@ from api.utils.storage.storage import Storage
from api.models import Apps, AppReleaseInfo
from api.utils.serializer import AppsSerializer, AppReleaseSerializer, UserInfoSerializer
from api.utils.app.apputils import delete_apps_icon_storage
from rest_framework.pagination import PageNumberPagination
@ -206,7 +205,8 @@ class AppInfoView(APIView):
random_file_name)
release_obj.save()
delete_apps_icon_storage(old_file_name, 'icons')
storage = Storage(request.user)
storage.delete_file(old_file_name)
else:
res.code = 1003

@ -8,6 +8,9 @@ from api.utils.response import BaseResponse
from rest_framework.response import Response
from fir_ser import settings
from api.utils.TokenManager import DownloadToken
from api.utils.app.randomstrings import make_random_uuid
from api.utils.app.apputils import make_resigned
from api.utils.storage.storage import Storage
import os
from api.utils.serializer import AppsSerializer
@ -15,18 +18,15 @@ from api.models import Apps,AppReleaseInfo
from django.http import FileResponse
class DownloadView(APIView):
'''
文件下载接口
文件下载接口,适用于本地存储和所有plist文件下载
'''
# authentication_classes = [ExpiringTokenAuthentication, ]
# parser_classes = (MultiPartParser,)
def get(self,request,filename):
# release_id = release_id.split(".")[1]
res = BaseResponse()
print(filename)
downtoken = request.query_params.get("token", None)
iostype = request.query_params.get("type",None)
ftype = request.query_params.get("ftype",None)
if not downtoken:
res.code=1004
res.msg="缺失token"
@ -34,6 +34,7 @@ class DownloadView(APIView):
dtoken = DownloadToken()
if dtoken.verify_token(downtoken,filename):
if not ftype:
file_path = os.path.join(settings.MEDIA_ROOT, filename)
try:
response = FileResponse(open(file_path, 'rb'))
@ -44,92 +45,87 @@ class DownloadView(APIView):
response['Content-Disposition'] = 'attachment; filename=' + filename
return response
else:
if ftype == 'plist':
release_obj = AppReleaseInfo.objects.filter(release_id=filename.split('.')[0]).first()
if release_obj:
storage = Storage(release_obj.app_id.user_id)
bundle_id = release_obj.app_id.bundle_id
bundle_version = release_obj.build_version
name = release_obj.app_id.name
ios_plist_bytes = make_resigned(storage.get_download_url(filename),storage.get_download_url(release_obj.icon_url),bundle_id,bundle_version,name)
response = FileResponse(ios_plist_bytes)
response['content_type'] = "application/x-plist"
response['Content-Disposition'] = 'attachment; filename=' + make_random_uuid()
return response
res.code=1004
res.msg="token校验失败"
return Response(res.dict)
# #校验成功,可以下载数据
# apprelease_obj = AppReleaseInfo.objects.filter(release_id=release_id).first()
# if apprelease_obj:
# try:
# app_type="ipa"
# if apprelease_obj.release_type == 0:
# app_type = "apk"
#
# if iostype == "resigned.plist":
# file_path=make_random_uuid()
#
# downtoken=dtoken.make_token([release_id])
# domain_name = apprelease_obj.app_id.user_id.domain_name
# if not domain_name:
# ser_url = request.META.get("HTTP_HOST", "/")
# SERVER_PROTOCOL = request.META.get("SERVER_PROTOCOL", "http/1.1")
# ser_protocol = SERVER_PROTOCOL.split("/")[0].lower()
# domain_name = "%s://%s" % (ser_protocol, ser_url)
# bin_url = domain_name+"/download/"+\
# release_id+"?token="+\
# downtoken
# img_url=apprelease_obj.icon_url
# bundle_id = apprelease_obj.app_id.bundle_id
# bundle_version = apprelease_obj.build_version
# name = apprelease_obj.app_id.name
# ios_plist_bytes = make_resigned(bin_url,img_url,bundle_id,bundle_version,name)
# response = FileResponse(ios_plist_bytes)
# response['content_type'] = "text/xml"
#
#
# else:
#
# apprelease_obj.app_id.count_hits+=1
# apprelease_obj.app_id.save()
#
# file_path = os.path.join(settings.MEDIA_ROOT,"apps","%s"%(release_id+"."+app_type))
# response = FileResponse(open(file_path, 'rb'))
# response['content_type'] = "application/octet-stream"
# response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)
# return response
# except Exception:
# raise Http404
# pass
# else:
# res.code=1004
# res.msg="token校验失败"
# return Response(res.dict)
class DownloadTokenView(APIView):
class ShortDownloadView(APIView):
'''
获取下载的token信息
根据下载短链接获取应用信息
'''
# authentication_classes = [ExpiringTokenAuthentication, ]
# parser_classes = (MultiPartParser,)
def get(self,request,short):
res = BaseResponse()
release_ids=[]
release_id = request.query_params.get("release_id", None)
if release_id:
release_ids = [release_id]
# res.data["release_id"] = release_id
dtoken = DownloadToken()
app_obj = Apps.objects.filter(short=short).first()
# release_id = AppReleaseInfo.objects.filter(app_id=app_obj).first().release_id
if not app_obj:
res.code=1003
res.msg="该应用不存在"
return Response(res.dict)
app_release_obj = AppReleaseInfo.objects.filter(app_id=app_obj,is_master=True).first()
release_ids.append(app_release_obj.release_id)
if app_obj.has_combo:
release_ids.append(AppReleaseInfo.objects.filter(app_id=app_obj.has_combo,is_master=True).first().release_id)
download_token = dtoken.make_token(release_ids)
app_serializer = AppsSerializer(app_obj,context={"release_id":release_id,"download_token":download_token})
app_serializer = AppsSerializer(app_obj,context={"release_id":release_id,"storage":Storage(app_obj.user_id)})
res.data = app_serializer.data
res.data["download_token"]=download_token
return Response(res.dict)
class InstallView(APIView):
'''
安装操作前端通过token 认证认证成功之后返回 下载连接并且 让下载次数加一
'''
def get(self,request,app_id):
res = BaseResponse()
downtoken = request.query_params.get("token", None)
short = request.query_params.get("short",None)
release_id = request.query_params.get("release_id",None)
isdownload = request.query_params.get("isdownload",None)
if not downtoken or not short or not release_id:
res.code=1004
res.msg="参数丢失"
return Response(res.dict)
dtoken = DownloadToken()
if dtoken.verify_token(downtoken,release_id):
app_obj = Apps.objects.filter(app_id=app_id,short=short).first()
if app_obj:
app_obj.count_hits = app_obj.count_hits+1
app_obj.save()
release_obj = AppReleaseInfo.objects.filter(app_id=app_obj,release_id=release_id).first()
if release_obj:
storage = Storage(app_obj.user_id)
if app_obj.type == 0:
apptype = '.apk'
download_url = storage.get_download_url(release_obj.release_id + apptype,600)
else:
apptype = '.ipa'
if isdownload :
download_url = storage.get_download_url(release_obj.release_id + apptype, 600)
else:
download_url = storage.get_download_url(release_obj.release_id + apptype,600,'plist')
res.data={"download_url":download_url}
return Response(res.dict)
else:
res.code = 1004
res.msg = "token校验失败"
return Response(res.dict)
res.code = 1006
res.msg = "该应用不存在"
return Response(res.dict)

@ -11,9 +11,9 @@ import binascii
import os,datetime
from api.utils.TokenManager import DownloadToken,generateNumericTokenOfLength
from api.utils.auth import ExpiringTokenAuthentication
from api.utils.app.apputils import delete_apps_icon_storage
from api.utils.response import BaseResponse
from django.middleware import csrf
from api.utils.storage.storage import Storage
def get_token(request):
token = csrf.get_token(request)
@ -158,7 +158,8 @@ class UserInfoView(APIView):
request.user.head_img = head_img
request.user.save()
if old_head_img != "" or old_head_img != '/files/imgs/head_img.jpeg':
delete_apps_icon_storage(os.path.basename(old_head_img),'imgs')
storage = Storage(request.user)
storage.delete_file(os.path.basename(old_head_img))
except Exception as e:
res.code = 1003

@ -32,7 +32,7 @@ from api.views.captcha import CaptchaView
# router.register("course/category", CourseCategoryView)
from django.views.static import serve
from fir_ser import settings
from api.views.download import DownloadView
from api.views.download import DownloadView,InstallView
urlpatterns = [
path('fly.admin/', admin.site.urls),
@ -48,4 +48,5 @@ urlpatterns = [
# media路径配置
re_path(r'files/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
re_path("download/(?P<filename>\w+\.\w+)$", DownloadView.as_view(),name="download"),
re_path("install/(?P<app_id>\w+)$", InstallView.as_view(), name="install"),
]

Loading…
Cancel
Save