diff --git a/fir_client/src/components/FirApps.vue b/fir_client/src/components/FirApps.vue index 5864add..ad73c74 100644 --- a/fir_client/src/components/FirApps.vue +++ b/fir_client/src/components/FirApps.vue @@ -755,11 +755,15 @@ return ftype }, make_icon_url(icon_url) { - if (!icon_url.startsWith("http")) { - return location.origin + icon_url - } else { - return icon_url + if(icon_url){ + if (!icon_url.startsWith("http")) { + return location.origin + icon_url + } else { + return icon_url + } } + return icon_url + }, get_upload_text(is_new) { if (is_new) { diff --git a/fir_client/src/components/FirUserProfileStorage.vue b/fir_client/src/components/FirUserProfileStorage.vue index 54318ca..2221e17 100644 --- a/fir_client/src/components/FirUserProfileStorage.vue +++ b/fir_client/src/components/FirUserProfileStorage.vue @@ -1,19 +1,196 @@ @@ -25,39 +202,189 @@ name: "FirUserProfileStorage", data() { return { - fstorage_lists:[[]], - use_storage_id:null + fstorage_lists: [], + Sdisabled:true, + use_storage_id: 0, + org_storage_id:0, + title:'', + dialogstorageVisible:false, + editstorageinfo:{'additionalparameter':{}}, + selectlabel: "", + storageinfo: {'additionalparameter': {}}, + storage_list: [], + disabled: true, + isaddflag: false, + activeName: 'chostorage', + storage_info_lists: [], } }, methods: { - select_storage(a){ - // eslint-disable-next-line no-console - console.log(a) + deepCopy(source) { + let result={}; + for (let key in source) { + result[key] = typeof source[key]==='object'? this.deepCopy(source[key]): source[key]; + } + return result; + }, + showstorage(editstorageinfo){ + this.title='查看存储信息'; + this.disabled=true; + this.dialogstorageVisible=true; + this.editstorageinfo=this.deepCopy(editstorageinfo); + }, + editstorage(editstorageinfo){ + this.title='存储编辑'; + this.disabled=false; + this.dialogstorageVisible=true; + this.editstorageinfo=this.deepCopy(editstorageinfo); + this.isaddflag=false; + },add_storage_click(){ + this.title='新增存储'; + this.disabled=false; + this.dialogstorageVisible=true; + this.editstorageinfo={'additionalparameter':{}}; + this.isaddflag=true; + }, + // eslint-disable-next-line no-unused-vars + handleClick(tab, event) { + if(tab.name === 'addstorage'){ + this.add_storage_click() + } }, - format_storage(storage_lists){ + updateorcreate() { + let methods = "PUT"; + if (this.isaddflag) { + methods = "POST" + } + getStorageinfo(data => { + if (data.code === 1000) { + this.$message.success('操作成功'); + this.dialogstorageVisible=false; + if (this.isaddflag) { + this.activeName='setstorage'; + } + this.getstorageinfoFun(); + } + }, {"methods": methods, 'data': this.editstorageinfo}); + this.getstorageinfoFun(); + }, del_storage_info(sinfo) { - for(let key in storage_lists){ + this.$confirm('此操作可能会导致程序异常, 是否继续?', '警告', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + getStorageinfo(data => { + if (data.code === 1000) { + this.$message.success('删除成功'); + this.getstorageinfoFun(); + } + }, {"methods": 'DELETE', 'data': {'id': sinfo.id, 'tid': sinfo.storage_type}}) + }).catch(() => { + this.$message({ + type: 'info', + message: '已取消删除' + }); + }); + + }, + change_storage_info() { + this.$confirm('此操作将导致应用,图片,显示下载异常, 是否继续?', '警告', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + getStorageinfo(data => { + if (data.code === 1000) { + this.$message.success('修改成功'); + this.getstorageinfoFun(); + } + }, {"methods": 'PUT', 'data': {'use_storage_id':this.use_storage_id}}); + this.getstorageinfoFun(); + }).catch(() => { + this.$message({ + type: 'info', + message: '已取消操作' + }); + }); + }, + select_storage(a) { + this.disabled = true; + this.getstorageinfobyid(a); + }, + getstorageinfobyid(id) { + for (let i = 0; i < this.fstorage_lists.length; i++) { + let storages = this.fstorage_lists[i].storages; + for (let j = 0; j < storages.length; j++) { + if (id === storages[j].id) { + this.storageinfo = storages[j]; + break + } + } + } + + }, + format_storage(storage_data_lists) { + let storage_f = []; + let storage_lists = {}; + for (let key in storage_data_lists) { + let storage = storage_data_lists[key]; + let storage_type = storage.storage_type; + if (!storage_lists[storage_type]) { + storage_lists[storage_type] = []; + } + storage_lists[storage_type].unshift(storage); + } + for (let key in storage_lists) { let storage = storage_lists[key]; - if(storage[0].storage_type_display){ - this.fstorage_lists.unshift({'group_name':storage[0].storage_type_display,'storage':storage}) + if (storage[0].storage_type_display) { + storage_f.unshift({'group_name': storage[0].storage_type_display, 'storages': storage}) } + if (!this.selectlabel) { + for (let i = 0; i < storage.length; i++) { + if (this.use_storage_id === storage[i].id) { + this.selectlabel = storage[i].name; + break + } + } + } + } + + storage_f.unshift({'group_name': '默认存储', 'storages': [{'id': -1, 'name': '默认存储'}]}); + if (!this.selectlabel) { + this.selectlabel = "默认存储" } + this.fstorage_lists = storage_f.slice(); + this.getstorageinfobyid(this.use_storage_id) + }, getstorageinfoFun() { - // eslint-disable-next-line no-console - getStorageinfo(data=>{ - if(data.code === 1000){ - this.format_storage(data.data); - this.use_storage_id = data.data.storage; - }else { - this.$message.error('存储获取失败,'+data); - } - },{"methods":false}); - } + getStorageinfo(data => { + if (data.code === 1000) { + this.org_storage_id=this.use_storage_id = data.storage; + this.storage_list = data.storage_list; + this.storage_info_lists = data.data; + this.format_storage(data.data); + this.disabled=true; + this.isaddflag=false; + } else { + this.$message.error('存储获取失败,' + data); + } + }, {"methods": 'GET'}); + }, + // eslint-disable-next-line no-unused-vars + formatter(row, column) { + let stime = row.updated_time; + if (stime) { + stime = stime.split(".")[0].split("T"); + return stime[0] + " " + stime[1] + } else + return ''; + }, }, mounted() { this.$store.dispatch('douserInfoIndex', 2); this.getstorageinfoFun(); - } + }, filters: {} } diff --git a/fir_client/src/restful/index.js b/fir_client/src/restful/index.js index d019b32..4b40b10 100644 --- a/fir_client/src/restful/index.js +++ b/fir_client/src/restful/index.js @@ -1,6 +1,6 @@ import Axios from 'axios' import VueCookies from 'vue-cookies' - +import router from "../router"; const https = require('https'); const Base64 = require('js-base64').Base64; Axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; @@ -45,7 +45,7 @@ function getData(methods = true, url, params = {}, callBack, load, isCode = fals if (methods === "DELETE") { Axios - .delete(url, params) + .delete(url, {params:params}) .then(function (response) { if (isCode) { callBack(response.data); @@ -150,6 +150,9 @@ function getData(methods = true, url, params = {}, callBack, load, isCode = fals .catch(function (error) { // eslint-disable-next-line no-console console.log(error, error.response); + if(error.response && error.response.status === 403){ + router.push({name: 'FirLogin'}); + } callBack(null); }); } diff --git a/fir_ser/api/migrations/0024_auto_20200413_1557.py b/fir_ser/api/migrations/0024_auto_20200413_1557.py new file mode 100644 index 0000000..8ed2738 --- /dev/null +++ b/fir_ser/api/migrations/0024_auto_20200413_1557.py @@ -0,0 +1,28 @@ +# Generated by Django 3.0.3 on 2020-04-13 15:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0023_appreleaseinfo_udid'), + ] + + operations = [ + migrations.AlterField( + model_name='appreleaseinfo', + name='udid', + field=models.TextField(blank=True, default='', null=True, verbose_name='ios内测版 udid'), + ), + migrations.AlterField( + model_name='appstorage', + name='additionalparameters', + field=models.TextField(blank=True, default=None, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ', null=True, verbose_name='额外参数'), + ), + migrations.AlterField( + model_name='appstorage', + name='is_https', + field=models.BooleanField(default=True, verbose_name='是否支持https'), + ), + ] diff --git a/fir_ser/api/migrations/0025_appstorage_updated_time.py b/fir_ser/api/migrations/0025_appstorage_updated_time.py new file mode 100644 index 0000000..1b8e011 --- /dev/null +++ b/fir_ser/api/migrations/0025_appstorage_updated_time.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.3 on 2020-04-14 10:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0024_auto_20200413_1557'), + ] + + operations = [ + migrations.AddField( + model_name='appstorage', + name='updated_time', + field=models.DateTimeField(auto_now=True, verbose_name='更新时间'), + ), + ] diff --git a/fir_ser/api/migrations/0026_auto_20200414_1505.py b/fir_ser/api/migrations/0026_auto_20200414_1505.py new file mode 100644 index 0000000..423312f --- /dev/null +++ b/fir_ser/api/migrations/0026_auto_20200414_1505.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.3 on 2020-04-14 15:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0025_appstorage_updated_time'), + ] + + operations = [ + migrations.AlterField( + model_name='appstorage', + name='description', + field=models.TextField(blank=True, default='', null=True, verbose_name='备注'), + ), + ] diff --git a/fir_ser/api/models.py b/fir_ser/api/models.py index ae30924..909b748 100644 --- a/fir_ser/api/models.py +++ b/fir_ser/api/models.py @@ -152,10 +152,11 @@ class AppStorage(models.Model): bucket_name=models.CharField(max_length=128,blank=True, null=True, verbose_name="存储空间bucket_name") domain_name=models.CharField(max_length=128,blank=True, null=True, verbose_name="下载域名",help_text='fly-storage.dvcloud.xin,可以自定义端口') is_https = models.BooleanField(default=True, verbose_name="是否支持https") - additionalparameters = models.TextField(max_length=256,blank=True, null=True,verbose_name="额外参数", - help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ') + additionalparameters = models.TextField(blank=True, null=True,verbose_name="额外参数", + help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ', default=None) created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") - description = models.TextField('备注', blank=True, null=True, default=None, ) + updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间") + description = models.TextField('备注', blank=True, null=True, default='') class Meta: verbose_name = '存储配置' diff --git a/fir_ser/api/utils/serializer.py b/fir_ser/api/utils/serializer.py index 8c32a45..4bb331c 100644 --- a/fir_ser/api/utils/serializer.py +++ b/fir_ser/api/utils/serializer.py @@ -3,7 +3,7 @@ from api import models from api.utils.app.apputils import bytes2human from api.utils.TokenManager import DownloadToken from api.utils.storage.storage import Storage -import os +import os,json token_obj = DownloadToken() @@ -192,7 +192,23 @@ class AppReleaseSerializer(serializers.ModelSerializer): class StorageSerializer(serializers.ModelSerializer): class Meta: model = models.AppStorage - # depth = 1 exclude = ["user_id"] - storage_type_display= serializers.CharField(source="get_storage_type_display") + storage_type_display= serializers.CharField(source="get_storage_type_display",read_only=True) + additionalparameters=serializers.CharField(write_only=True) + additionalparameter=serializers.SerializerMethodField(read_only=True) + + def get_additionalparameter(self,obj): + infos={} + try: + infos = json.loads(obj.additionalparameters) + except Exception as e: + print(e) + return infos + + def create(self, validated_data): + if self.context.get("user_obj", None) and self.context.get("user_obj") != "undefined": + user_obj = self.context.get("user_obj", None) + storage_obj = models.AppStorage.objects.create(**validated_data,user_id=user_obj,) + return storage_obj + return None diff --git a/fir_ser/api/views/storage.py b/fir_ser/api/views/storage.py index 038dd33..001b5c0 100644 --- a/fir_ser/api/views/storage.py +++ b/fir_ser/api/views/storage.py @@ -8,40 +8,111 @@ from rest_framework.views import APIView from api.utils.response import BaseResponse from api.utils.auth import ExpiringTokenAuthentication from rest_framework.response import Response +import json from django.db.models import Sum import os from fir_ser import settings from api.utils.app.randomstrings import make_from_user_uuid from api.utils.storage.storage import Storage -from api.utils.storage.caches import del_cache_response_by_short,get_app_today_download_times -from api.models import Apps, AppReleaseInfo,AppStorage +from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times +from api.models import AppStorage,UserInfo from api.utils.serializer import StorageSerializer - - - class StorageView(APIView): authentication_classes = [ExpiringTokenAuthentication, ] + def get(self, request): res = BaseResponse() # [1,2] 表示七牛存储和阿里云存储 - storage_obj = AppStorage.objects.filter(user_id=request.user,storage_type__in=[1,2]) + storage_obj = AppStorage.objects.filter(user_id=request.user, storage_type__in=[1, 2]) if storage_obj: - storage_serializer = StorageSerializer(storage_obj,many=True) + storage_serializer = StorageSerializer(storage_obj, many=True) storage_data_lists = storage_serializer.data - storage_lists={} + storage_lists = {} for storage_data in storage_data_lists: storage_type = storage_data.get("storage_type") if not storage_lists.get(storage_type): - storage_lists[storage_type]=[] + storage_lists[storage_type] = [] storage_lists[storage_type].append(storage_data) - res.data=storage_lists + res.data = storage_data_lists use_storage_obj = request.user.storage if use_storage_obj: - res.storage=use_storage_obj.id + res.storage = use_storage_obj.id + else: + res.storage = -1 # 默认存储 + + res.storage_list = [] + storage_org_list = list(AppStorage.storage_choices) + for storage_t in storage_org_list: + if storage_t[0] in [0, 3]: continue + res.storage_list.append({'id': storage_t[0], 'name': storage_t[1]}) + + return Response(res.dict) + + def post(self, request): + res = BaseResponse() + data = request.data + try: + data['additionalparameters'] = json.dumps(data.get('additionalparameter', '')) + except Exception as e: + print(e) + + serializer = StorageSerializer(data=data, context={'user_obj': request.user}) + if serializer.is_valid(): + serializer.save() + res.msg = serializer.validated_data + else: - res.storage = None + res.msg = serializer.errors + res.code = 1005 + return Response(res.dict) + + def put(self, request): + res = BaseResponse() + data = request.data + + use_storage_id=data.get("use_storage_id",None) + if use_storage_id: + try: + if use_storage_id == -1: + UserInfo.objects.filter(pk=request.user.pk).update(storage=None) + else: + UserInfo.objects.filter(pk=request.user.pk).update(storage_id=use_storage_id) + except Exception as e: + print(e) + res.code=1006 + res.msg='修改失败' + return Response(res.dict) + + try: + data['additionalparameters'] = json.dumps(data.get('additionalparameter', '')) + except Exception as e: + print(e) + storage_id = data.get("id", None) + if storage_id: + storage_obj = AppStorage.objects.filter(id=storage_id, user_id=request.user).first() + serializer = StorageSerializer(instance=storage_obj, data=data, context={'user_obj': request.user}, + partial=True) + if serializer.is_valid(): + serializer.save() + res.msg = serializer.validated_data + else: + res.msg = serializer.errors + res.code = 1005 + else: + res.msg = '该存储不存在' + res.code = 1007 + return Response(res.dict) + + def delete(self, request): + res = BaseResponse() + storage_id = request.query_params.get("id", None) + if storage_id: + AppStorage.objects.filter(user_id=request.user, id=storage_id).delete() + else: + res.code = 1004 + res.msg = '该存储不存在' return Response(res.dict)