新增用户存储设置

super_signature
nineven 5 years ago
parent 1027110786
commit cb32a2226e
  1. 12
      fir_client/src/components/FirApps.vue
  2. 397
      fir_client/src/components/FirUserProfileStorage.vue
  3. 7
      fir_client/src/restful/index.js
  4. 28
      fir_ser/api/migrations/0024_auto_20200413_1557.py
  5. 18
      fir_ser/api/migrations/0025_appstorage_updated_time.py
  6. 18
      fir_ser/api/migrations/0026_auto_20200414_1505.py
  7. 7
      fir_ser/api/models.py
  8. 22
      fir_ser/api/utils/serializer.py
  9. 95
      fir_ser/api/views/storage.py

@ -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) {

@ -1,19 +1,196 @@
<template>
<div>
<el-select v-model="use_storage_id" clearable filterable placeholder="请选择" @change="select_storage">
<el-option-group
v-for="storage_group in fstorage_lists"
:key="storage_group.group_name"
:label="storage_group.group_name">
<el-option
v-for="storage in storage_group.storage"
:key="storage.id"
:label="storage.name"
:value="storage.id">
</el-option>
</el-option-group>
</el-select>
<div style="text-align:center">
<el-dialog :title="title" :visible.sync="dialogstorageVisible" :destroy-on-close="true" :close-on-click-modal="false">
<el-form v-if="editstorageinfo.id !==-1" ref="storageinfoform" :model="editstorageinfo"
label-width="80px" style="margin:0 auto;">
<el-form-item label-width="100px" label="存储类型">
<el-select :disabled='disabled' v-model="editstorageinfo.storage_type" placeholder="存储类型"
style="margin-left: -100px">
<el-option v-for="st in storage_list" :key="st.id" :label="st.name" :value="st.id"></el-option>
</el-select>
</el-form-item>
<div v-if="editstorageinfo.storage_type">
<el-form-item label-width="110px" label="存储名称">
<el-input :disabled='disabled' v-model="editstorageinfo.name"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="key">
<el-input :disabled='disabled' v-model="editstorageinfo.access_key"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="secret">
<el-input :disabled='disabled' v-model="editstorageinfo.secret_key"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="bucket_name">
<el-input :disabled='disabled' v-model="editstorageinfo.bucket_name"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="下载域名">
<el-input :disabled='disabled' v-model="editstorageinfo.domain_name"></el-input>
</el-form-item>
<div v-if="editstorageinfo.storage_type === 2">
<el-form-item label-width="110px" label="sts_role_arn">
<el-input :disabled='disabled'
v-model="editstorageinfo.additionalparameter.sts_role_arn"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="endpoint">
<el-input :disabled='disabled' v-model="editstorageinfo.additionalparameter.endpoint"></el-input>
</el-form-item>
</div>
<el-form-item label-width="110px" label="备注">
<el-input :disabled='disabled' v-model="editstorageinfo.description"></el-input>
</el-form-item>
<el-button v-if="!disabled" @click="updateorcreate">保存</el-button>
<el-button v-if="!disabled" @click="dialogstorageVisible=false">取消</el-button>
</div>
</el-form>
</el-dialog>
<el-tabs v-model="activeName" @tab-click="handleClick" tab-position="right">
<el-tab-pane label="存储选择" name="chostorage">
<el-select v-model="use_storage_id" filterable :placeholder="selectlabel" @change="select_storage">
<el-option-group
v-for="storage_group in fstorage_lists"
:key="storage_group.group_name"
:label="storage_group.group_name">
<el-option
v-for="storage in storage_group.storages"
:key="storage.id"
:label="storage.name"
:value="storage.id">
</el-option>
</el-option-group>
</el-select>
<el-button style="margin-left: 10px" round type="info" icon="el-icon-thumb" @click="change_storage_info">保存</el-button>
<!-- <el-button-group style="margin-left: 10px">-->
<!-- <el-button round type="info" icon="el-icon-edit" @click="change_storage_info"></el-button>-->
<!-- <el-button round type="info" icon="el-icon-plus" @click="add_storage_info"></el-button>-->
<!-- <el-button round type="info" icon="el-icon-delete" @click="del_storage_info"></el-button>-->
<!-- </el-button-group>-->
<el-divider></el-divider>
<el-form v-if="storageinfo.id && storageinfo.id !==-1" ref="storageinfoform" :model="storageinfo"
label-width="80px" style="width: 39%;margin:0 auto;">
<el-form-item label-width="110px" label="存储类型">
<el-select :disabled='Sdisabled' v-model="storageinfo.storage_type" placeholder="存储类型"
style="margin-left: -60px">
<el-option v-for="st in storage_list" :key="st.id" :label="st.name" :value="st.id"></el-option>
</el-select>
</el-form-item>
<div v-if="storageinfo.storage_type">
<el-form-item label-width="110px" label="存储名称">
<el-input :disabled='Sdisabled' v-model="storageinfo.name"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="key">
<el-input :disabled='Sdisabled' v-model="storageinfo.access_key"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="secret">
<el-input :disabled='Sdisabled' v-model="storageinfo.secret_key"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="bucket_name">
<el-input :disabled='Sdisabled' v-model="storageinfo.bucket_name"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="下载域名">
<el-input :disabled='Sdisabled' v-model="storageinfo.domain_name"></el-input>
</el-form-item>
<div v-if="storageinfo.storage_type === 2">
<el-form-item label-width="110px" label="sts_role_arn">
<el-input :disabled='Sdisabled'
v-model="storageinfo.additionalparameter.sts_role_arn"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="endpoint">
<el-input :disabled='Sdisabled' v-model="storageinfo.additionalparameter.endpoint"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="备注">
<el-input :disabled='Sdisabled' v-model="storageinfo.description"></el-input>
</el-form-item>
</div>
</div>
</el-form>
</el-tab-pane>
<el-tab-pane label="存储管理" name="setstorage">
<el-table
:data="storage_info_lists"
border
stripe
style="width: 100%">
<el-table-column
fixed
prop="name"
label="存储名称"
width="180">
</el-table-column>
<el-table-column
prop="storage_type_display"
label="存储类型"
width="100">
</el-table-column>
<el-table-column
prop="domain_name"
label="下载域名"
width="160">
</el-table-column>
<el-table-column
prop="bucket_name"
label="bucket_name"
width="120">
</el-table-column>
<el-table-column
:formatter="formatter"
prop="updated_time"
label="修改时间"
width="170">
</el-table-column>
<el-table-column
prop="description"
label="备注"
width="160">
</el-table-column>
<el-table-column
fixed="right"
label="操作"
width="120">
<template slot-scope="scope" >
<div v-if="scope.row.id === org_storage_id">
<el-button v-if="scope.row.id === org_storage_id" @click="showstorage(scope.row)" type="success" size="small">使用中</el-button>
</div>
<div v-else>
<el-button @click="showstorage(scope.row)" type="text" size="small">查看</el-button>
<el-button @click="editstorage(scope.row)" type="text" size="small">编辑</el-button>
<el-button @click="del_storage_info(scope.row)" type="text" size="small">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="新增存储" name="addstorage" >
</el-tab-pane>
</el-tabs>
</div>
</template>
@ -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: {}
}
</script>

@ -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);
});
}

@ -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'),
),
]

@ -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='更新时间'),
),
]

@ -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='备注'),
),
]

@ -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 = '存储配置'

@ -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

@ -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)

Loading…
Cancel
Save