@@ -39,10 +39,10 @@
暂无可以合并的应用
-
+
-
+
{{ comboapp.name }}
@@ -57,11 +57,11 @@
@@ -84,14 +84,7 @@
export default {
name: "FirAppInfoscombo"
- , mounted() {
-
- this.$store.dispatch('doappInfoIndex', [[31, 31], [31, 31]]);
-
- // this.getappiconFun();
- this.setData();
-
- }, data() {
+ , data() {
return {
searchKey: '',
currentapp: {},
@@ -196,9 +189,6 @@
this.getappiconFun();
}
},
- findByShort(e) {
- alert(111, e)
- },
getappiconFun() {
let type = "android";
if (this.currentapp.type === 0) {
@@ -228,6 +218,12 @@
return ftype
},
},
+ mounted() {
+ this.$store.dispatch('doappInfoIndex', [[44, 44], [44, 44]]);
+
+ // this.getappiconFun();
+ this.setData();
+ },
watch: {
'$store.state.currentapp': function () {
this.setData();
diff --git a/fir_client/src/components/FirAppInfosdevices.vue b/fir_client/src/components/FirAppInfosdevices.vue
new file mode 100644
index 0000000..20c5334
--- /dev/null
+++ b/fir_client/src/components/FirAppInfosdevices.vue
@@ -0,0 +1,89 @@
+
+
+
+
+
UDID列表及用户信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fir_client/src/components/FirAppInfossecurity.vue b/fir_client/src/components/FirAppInfossecurity.vue
new file mode 100644
index 0000000..af8c4b0
--- /dev/null
+++ b/fir_client/src/components/FirAppInfossecurity.vue
@@ -0,0 +1,246 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{passwordtip.msg}}
+
+ 修改
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fir_client/src/components/FirDownload.vue b/fir_client/src/components/FirDownload.vue
index 7afa4e9..7b024c2 100644
--- a/fir_client/src/components/FirDownload.vue
+++ b/fir_client/src/components/FirDownload.vue
@@ -58,13 +58,18 @@
-
@@ -158,36 +163,48 @@
agent: '',
wrong: false,
msg: '',
+ password:'',
dchoice:false,
downloadurl:"",
isdownload:false,
}
}, methods: {
download() {
- this.isdownload = true;
- getdownloadurl(res=>{
- if(res.code === 1000){
-
- if(this.currentappinfo.type === 1){
- let download_url = res.data.download_url;
- download_url = download_url.replace('http://localhost/download',getplisturl());
- this.downloadurl="itms-services://?action=download-manifest&url="+encodeURIComponent(download_url);
- }else{
- if(this.agent !== ''){
- this.downloadurl = res.data.download_url;
+ if( this.currentappinfo.app_id){
+ this.isdownload = true;
+ getdownloadurl(res=>{
+ if(res.code === 1000){
+
+ if(this.currentappinfo.type === 1){
+ let download_url = res.data.download_url;
+ download_url = download_url.replace('http://localhost/download',getplisturl());
+ this.downloadurl="itms-services://?action=download-manifest&url="+encodeURIComponent(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
- })
+ window.location.href=this.downloadurl;
+ }
+ else {
+ this.isdownload = false;
+ this.password='';
+ this.$message({
+ message:"密码错误,或者下载链接失效",
+ type: 'error',
+ });
+ }
+ }, {
+ 'data': {
+ 'token': this.mcurrentappinfo.download_token,
+ 'short': this.currentappinfo.short,
+ 'release_id': this.mcurrentappinfo.release_id,
+ 'password':this.password,
+ },
+ 'app_id': this.currentappinfo.app_id
+ })
+ }
},
qrcode() {
new QRCode('qrcode', {
diff --git a/fir_client/src/router/index.js b/fir_client/src/router/index.js
index cae7288..c48bad5 100644
--- a/fir_client/src/router/index.js
+++ b/fir_client/src/router/index.js
@@ -20,6 +20,8 @@ import FirAppBase from "@/components/FirAppBase";
import FirAppInfosBase from "@/components/FirAppInfosBase";
import FirAppInfostimeline from "@/components/FirAppInfostimeline";
import FirAppInfosbaseinfo from "@/components/FirAppInfosbaseinfo";
+import FirAppInfossecurity from "@/components/FirAppInfossecurity";
+import FirAppInfosdevices from "@/components/FirAppInfosdevices";
import FirAppInfoscombo from "@/components/FirAppInfoscombo";
import FirUserProfile from "@/components/FirUserProfileBase";
import FirUserProfileInfo from "@/components/FirUserProfileInfo";
@@ -63,6 +65,16 @@ const router = new VueRouter({
name: 'FirAppInfosbaseinfo',
component: FirAppInfosbaseinfo,
},
+ {
+ path: 'security',
+ name: 'FirAppInfossecurity',
+ component: FirAppInfossecurity
+ },
+ {
+ path: 'devices',
+ name: 'FirAppInfosdevices',
+ component: FirAppInfosdevices
+ },
{
path: 'combo',
name: 'FirAppInfoscombo',
diff --git a/fir_download/src/components/FirDownload.vue b/fir_download/src/components/FirDownload.vue
index e16a088..c323bf8 100644
--- a/fir_download/src/components/FirDownload.vue
+++ b/fir_download/src/components/FirDownload.vue
@@ -56,13 +56,18 @@
-
@@ -160,6 +165,7 @@
agent: '',
wrong: false,
msg: '',
+ password:'',
dchoice:false,
downloadurl:"",
isdownload:false,
@@ -167,32 +173,39 @@
}
}, methods: {
download() {
- this.isdownload = true;
- getdownloadurl(res=>{
- if(res.code === 1000){
-
- if(this.currentappinfo.type === 1){
- let download_url = res.data.download_url;
- download_url = download_url.replace('http://localhost/download',getplisturl());
- this.downloadurl="itms-services://?action=download-manifest&url="+encodeURIComponent(download_url);
- }else{
- if(this.agent !== ''){
- this.downloadurl = res.data.download_url;
+ if( this.currentappinfo.app_id) {
+
+ this.isdownload = true;
+ getdownloadurl(res => {
+ if (res.code === 1000) {
+
+ if (this.currentappinfo.type === 1) {
+ let download_url = res.data.download_url;
+ download_url = download_url.replace('http://localhost/download', getplisturl());
+ this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(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
- })
+ window.location.href = this.downloadurl;
+ } else {
+ this.isdownload = false;
+ alert("密码错误,或者下载链接失效")
+ }
+ }, {
+ 'data': {
+ 'token': this.mcurrentappinfo.download_token,
+ 'short': this.currentappinfo.short,
+ 'release_id': this.mcurrentappinfo.release_id,
+ 'password': this.password,
+ },
+ 'app_id': this.currentappinfo.app_id
+ })
+ }
},
- qrcode() {
+ qrcode(){
new QRCode('qrcode', {
width: 100,
height: 100,
@@ -285,11 +298,6 @@
}
else {
- // this.$message({
- // message: data.msg,
- // type: 'error',
- // duration:0
- // });
this.iserror = true;
}
}, params)
@@ -719,38 +727,6 @@
display: none
}
- .passwd form {
- text-align: center
- }
-
- .passwd form h4 {
- font-weight: 400;
- font-size: 18px
- }
-
- .passwd form button, .passwd form input {
- padding: 12px 20px;
- width: 300px;
- border: 1px solid #f8ba0b;
- border-radius: 5px;
- font-size: 16px
- }
-
- .passwd form button:focus, .passwd form input:focus {
- outline: 0
- }
-
- .passwd form input {
- color: #f8ba0b;
- text-align: center
- }
-
- .passwd form button {
- border-color: #f8ba0b;
- background-color: #f8ba0b;
- color: #fff;
- cursor: pointer
- }
.main .icon-container {
position: relative;
@@ -915,6 +891,14 @@
color: #fff
}
+ .main > header .actions input {
+ display: inline-block;
+ padding: 12px 46px;
+ width: 166px;
+ border: 1px solid #32b2a7;
+ border-radius: 40px;
+ font-size: 14px;
+ }
.main > header .actions button a{
color: #fff
}
diff --git a/fir_ser/api/migrations/0021_auto_20200410_1141.py b/fir_ser/api/migrations/0021_auto_20200410_1141.py
new file mode 100644
index 0000000..4b4e4ba
--- /dev/null
+++ b/fir_ser/api/migrations/0021_auto_20200410_1141.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.0.3 on 2020-04-10 11:41
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0020_auto_20200407_1157'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='apps',
+ name='password',
+ field=models.CharField(default='', help_text='默认 没有密码', max_length=32, verbose_name='访问密码'),
+ ),
+ migrations.AlterField(
+ model_name='appreleaseinfo',
+ name='binary_url',
+ field=models.CharField(blank=True, max_length=128, verbose_name='第三方下载URL'),
+ ),
+ migrations.AlterField(
+ model_name='token',
+ name='access_token',
+ field=models.CharField(max_length=64, unique=True),
+ ),
+ ]
diff --git a/fir_ser/api/migrations/0022_apps_isshow.py b/fir_ser/api/migrations/0022_apps_isshow.py
new file mode 100644
index 0000000..b4b69a1
--- /dev/null
+++ b/fir_ser/api/migrations/0022_apps_isshow.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.3 on 2020-04-10 17:15
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0021_auto_20200410_1141'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='apps',
+ name='isshow',
+ field=models.BigIntegerField(default=1, verbose_name='下载页可见'),
+ ),
+ ]
diff --git a/fir_ser/api/migrations/0023_appreleaseinfo_udid.py b/fir_ser/api/migrations/0023_appreleaseinfo_udid.py
new file mode 100644
index 0000000..ea9ea3c
--- /dev/null
+++ b/fir_ser/api/migrations/0023_appreleaseinfo_udid.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.3 on 2020-04-11 10:20
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0022_apps_isshow'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='appreleaseinfo',
+ name='udid',
+ field=models.TextField(blank=True, default=None, null=True, verbose_name='ios内测版 udid'),
+ ),
+ ]
diff --git a/fir_ser/api/models.py b/fir_ser/api/models.py
index c03661b..1695fa1 100644
--- a/fir_ser/api/models.py
+++ b/fir_ser/api/models.py
@@ -101,9 +101,10 @@ class Apps(models.Model):
bundle_id = models.CharField(max_length=64,blank=True,verbose_name="bundle id")
has_combo = models.OneToOneField(to="Apps", related_name='combo_app_info',
verbose_name="关联应用",on_delete=models.SET_NULL,null=True,blank=True)
- # icon_img = models.ImageField(upload_to="course/%Y-%m", verbose_name='图标')
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
count_hits = models.BigIntegerField(verbose_name="下载次数",default=0)
+ password = models.CharField(verbose_name="访问密码",default='',help_text='默认 没有密码',max_length=32)
+ isshow = models.BigIntegerField(verbose_name="下载页可见",default=1)
description = models.TextField('描述', blank=True, null=True, default=None, )
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
class Meta:
@@ -128,6 +129,7 @@ class AppReleaseInfo(models.Model):
binary_url = models.CharField(max_length=128,blank=True,verbose_name="第三方下载URL")
icon_url = models.CharField(max_length=128,blank=True,verbose_name="图标url")
changelog = models.TextField('更新日志', blank=True, null=True, default=None, )
+ udid = models.TextField('ios内测版 udid', blank=True, null=True, default='', )
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
diff --git a/fir_ser/api/utils/app/apputils.py b/fir_ser/api/utils/app/apputils.py
index ffb079c..bc65c11 100644
--- a/fir_ser/api/utils/app/apputils.py
+++ b/fir_ser/api/utils/app/apputils.py
@@ -151,7 +151,8 @@ def SaveAppInfos(app_file_name,user_obj,appinfo,bundle_id,app_img,short,size):
"minimum_os_version": appinfo.get("miniOSversion", None),
"binary_size": size,
"is_master": True,
- "changelog":appinfo.get("changelog",'')
+ "changelog":appinfo.get("changelog",''),
+ "udid":appinfo.get("udid",''),
}
AppReleaseInfo.objects.create(**release_data)
diff --git a/fir_ser/api/utils/serializer.py b/fir_ser/api/utils/serializer.py
index 1f65914..099bfd7 100644
--- a/fir_ser/api/utils/serializer.py
+++ b/fir_ser/api/utils/serializer.py
@@ -64,19 +64,81 @@ class AppsSerializer(serializers.ModelSerializer):
download_token = token_obj.make_token(master_release_obj.release_id,600,key=key)
datainfo["download_token"] = download_token
+ udid_lists = []
+ try:
+ udid_data = eval(master_release_obj.udid)
+ for udid in udid_data:
+ udid_lists.append({'udid':udid})
+ except Exception as e:
+ pass
+ datainfo["udid"] = udid_lists
return datainfo
else:
return {}
+
+class AppsShortSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = models.Apps
+ fields = ["app_id","name","short","has_combo","isshow","description","need_password",'master_release']
+
+ need_password=serializers.SerializerMethodField()
+
+ def get_need_password(self,obj):
+ if obj.password != '':
+ return True
+ return False
+ has_combo = serializers.SerializerMethodField()
+
+ def get_has_combo(self, obj):
+ if obj.has_combo:
+ obj.has_combo.has_combo = None
+ return AppsSerializer(obj.has_combo,context=self.context).data
+
+ master_release = serializers.SerializerMethodField()
+
+ def get_master_release(self, obj):
+ master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj, is_master=True).first()
+ if self.context.get("release_id", None) and self.context.get("release_id") != "undefined":
+ master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj,
+ release_id=self.context.get("release_id")).first()
+ if master_release_obj:
+
+ icon_url = ""
+ key=''
+ if self.context.get("key", None) and self.context.get("key") != "undefined":
+ key=self.context.get("key", '')
+ if self.context.get("storage", None) and self.context.get("storage") != "undefined":
+ storage = self.context.get("storage", None)
+ icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url),600,key=key)
+ datainfo = {
+ "app_version": master_release_obj.app_version,
+ "icon_url": icon_url,
+ "build_version": master_release_obj.build_version,
+ "release_type": master_release_obj.release_type,
+ "created_time": master_release_obj.created_time,
+ "binary_size": bytes2human(master_release_obj.binary_size),
+ "release_id": master_release_obj.release_id,
+ "changelog": master_release_obj.changelog,
+ "binary_url":master_release_obj.binary_url,
+ }
+
+ download_token = token_obj.make_token(master_release_obj.release_id,600,key=key)
+ 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_token','binary_url']
+ "is_master",'download_token','binary_url','udid']
download_token = serializers.SerializerMethodField()
size = serializers.SerializerMethodField()
type = serializers.SerializerMethodField()
@@ -84,8 +146,17 @@ class AppReleaseSerializer(serializers.ModelSerializer):
master_color = serializers.SerializerMethodField()
icon_url = serializers.SerializerMethodField()
binary_size= serializers.SerializerMethodField()
-
-
+ udid= serializers.SerializerMethodField()
+
+ def get_udid(self,obj):
+ udid_lists = []
+ try:
+ udid_data = eval(obj.udid)
+ for udid in udid_data:
+ udid_lists.append({'udid': udid})
+ except Exception as e:
+ pass
+ return udid_lists
def get_binary_size(self,obj):
return bytes2human(obj.binary_size)
diff --git a/fir_ser/api/utils/storage/caches.py b/fir_ser/api/utils/storage/caches.py
index 63ee5bd..cfc05b9 100644
--- a/fir_ser/api/utils/storage/caches.py
+++ b/fir_ser/api/utils/storage/caches.py
@@ -5,8 +5,8 @@
# date: 2020/4/7
from django.core.cache import cache
-from api.models import Apps,UserInfo
-import time
+from api.models import Apps,UserInfo,AppReleaseInfo
+import time,os
from django.utils import timezone
from fir_ser.settings import CACHE_KEY_TEMPLATE
from api.utils.storage.storage import Storage,LocalStorage
@@ -29,12 +29,22 @@ def get_download_url_by_cache(app_obj, filename, limit, isdownload=True,key=''):
return storage.get_download_url(filename, limit)
-def get_app_instance_by_cache(app_id, limit):
+def get_app_instance_by_cache(app_id,password, limit):
app_key="_".join([CACHE_KEY_TEMPLATE.get("app_instance_key"),app_id])
app_obj_cache = cache.get(app_key)
if not app_obj_cache:
- app_obj_cache = Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type').first()
+ app_obj_cache = Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type','password').first()
cache.set(app_key, app_obj_cache, limit)
+
+ app_password=app_obj_cache.get("password")
+
+ if app_password != '':
+ if password is None:
+ return None
+
+ if app_password.lower() != password.strip().lower():
+ return None
+
return app_obj_cache
@@ -55,6 +65,14 @@ def del_cache_response_by_short(short,app_id):
cache.delete("_".join([CACHE_KEY_TEMPLATE.get("app_instance_key"),app_id]))
+ key='ShortDownloadView'.lower()
+ master_release_dict = AppReleaseInfo.objects.filter(app_id__app_id=app_id,is_master=True).values('icon_url','release_id').first()
+ download_val = CACHE_KEY_TEMPLATE.get('download_url_key')
+ cache.delete("_".join([key, download_val, os.path.basename(master_release_dict.get("icon_url"))]))
+ cache.delete("_".join([key,download_val, master_release_dict.get('release_id')]))
+ cache.delete("_".join([key.lower(), CACHE_KEY_TEMPLATE.get("make_token_key"), master_release_dict.get('release_id')]))
+
+
def set_app_today_download_times(app_id):
now = timezone.now()
down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_today_times_key"),
diff --git a/fir_ser/api/views/apps.py b/fir_ser/api/views/apps.py
index 3fa1869..d639b71 100644
--- a/fir_ser/api/views/apps.py
+++ b/fir_ser/api/views/apps.py
@@ -167,6 +167,8 @@ class AppInfoView(APIView):
del_cache_response_by_short(apps_obj.short,apps_obj.app_id)
apps_obj.short = data.get("short", apps_obj.short)
apps_obj.name = data.get("name", apps_obj.name)
+ apps_obj.password = data.get("password", apps_obj.password)
+ apps_obj.isshow = data.get("isshow", apps_obj.isshow)
apps_obj.save()
except Exception as e:
res.code = 1005
diff --git a/fir_ser/api/views/download.py b/fir_ser/api/views/download.py
index af8136c..59aa354 100644
--- a/fir_ser/api/views/download.py
+++ b/fir_ser/api/views/download.py
@@ -15,7 +15,7 @@ from api.utils.storage.caches import get_app_instance_by_cache,get_download_url_
import os
from rest_framework_extensions.cache.decorators import cache_response
-from api.utils.serializer import AppsSerializer
+from api.utils.serializer import AppsShortSerializer
from api.models import Apps,AppReleaseInfo
from django.http import FileResponse
class DownloadView(APIView):
@@ -81,7 +81,12 @@ class ShortDownloadView(APIView):
res.msg="该应用不存在"
return Response(res.dict)
- app_serializer = AppsSerializer(app_obj,context={"key":"ShortDownloadView","release_id":release_id,"storage":Storage(app_obj.user_id)})
+ if not app_obj.isshow:
+ res.code=1004
+ res.msg="您没有权限访问该应用"
+ return Response(res.dict)
+
+ app_serializer = AppsShortSerializer(app_obj,context={"key":"ShortDownloadView","release_id":release_id,"storage":Storage(app_obj.user_id)})
res.data = app_serializer.data
return Response(res.dict)
@@ -101,6 +106,7 @@ class InstallView(APIView):
short = request.query_params.get("short",None)
release_id = request.query_params.get("release_id",None)
isdownload = request.query_params.get("isdownload",None)
+ password = request.query_params.get("password",None)
if not downtoken or not short or not release_id:
res.code=1004
@@ -109,15 +115,9 @@ class InstallView(APIView):
dtoken = DownloadToken()
if dtoken.verify_token(downtoken,release_id):
- # app_obj = Apps.objects.filter(app_id=app_id).values("pk",'user_id','type','short').first()
- app_obj = get_app_instance_by_cache(app_id,900)
+ app_obj = get_app_instance_by_cache(app_id,password,900)
if app_obj:
-
- # Apps.objects.filter(app_id=app_id).update(count_hits=F('count_hits') + 1)
- # UserInfo.objects.filter(pk=app_obj.get("user_id")).update(all_download_times=F('all_download_times') + 1)
set_app_download_by_cache(app_id)
- # release_obj = AppReleaseInfo.objects.filter(app_id=app_obj.get('pk')).values("release_id")
- # if release_obj:
if app_obj.get("type") == 0:
apptype = '.apk'
download_url = get_download_url_by_cache(app_obj,release_id + apptype,600)
diff --git a/fir_ser/api/views/uploads.py b/fir_ser/api/views/uploads.py
index 75213ee..f29c013 100644
--- a/fir_ser/api/views/uploads.py
+++ b/fir_ser/api/views/uploads.py
@@ -85,7 +85,8 @@ class AppAnalyseView(APIView):
"versioncode":data.get("version"),
"release_type":data.get("release_type"),
"miniOSversion":data.get("miniosversion"),
- "changelog":data.get("changelog",'')
+ "changelog":data.get("changelog",''),
+ "udid": data.get("udid", ''),
}
try: