优化代码

super_signature
nineven 5 years ago
parent a4e9579236
commit ff81f62d95
  1. 15
      fir_client/src/App.vue
  2. 41
      fir_client/src/assets/icon/iconfont.css
  3. 87
      fir_client/src/assets/icon/iconfont.svg
  4. 50
      fir_client/src/components/FirAppInfosBase.vue
  5. 72
      fir_client/src/components/FirAppInfosbaseinfo.vue
  6. 18
      fir_client/src/components/FirAppInfoscombo.vue
  7. 43
      fir_client/src/components/FirAppInfosdevices.vue
  8. 209
      fir_client/src/components/FirAppInfossecurity.vue
  9. 23
      fir_client/src/components/FirApps.vue
  10. 190
      fir_client/src/components/FirDownload.vue
  11. 16
      fir_client/src/components/FirHeader.vue
  12. 8
      fir_client/src/components/FirLogin.vue
  13. 459
      fir_client/src/components/FirSuperSignBase.vue
  14. 84
      fir_client/src/components/FirUserProfileBase.vue
  15. 16
      fir_client/src/components/FirUserProfileChangePwd.vue
  16. 43
      fir_client/src/components/FirUserProfileInfo.vue
  17. 208
      fir_client/src/components/FirUserProfileStorage.vue
  18. 1
      fir_client/src/main.js
  19. 155
      fir_client/src/restful/index.js
  20. 4
      fir_client/src/router/index.js
  21. 130
      fir_client/src/utils/index.js
  22. 2
      fir_ser/api/admin.py
  23. 97
      fir_ser/api/migrations/0001_initial.py
  24. 1
      fir_ser/api/migrations/0002_auto_20200503_1120.py
  25. 8
      fir_ser/api/migrations/0003_apptodeveloper.py
  26. 1
      fir_ser/api/migrations/0004_auto_20200504_2054.py
  27. 1
      fir_ser/api/migrations/0005_apptodeveloper_release_file.py
  28. 5
      fir_ser/api/migrations/0006_udidsyncdeveloper.py
  29. 2
      fir_ser/api/models.py
  30. 21
      fir_ser/api/urls.py
  31. 20
      fir_ser/api/utils/TokenManager.py
  32. 1
      fir_ser/api/utils/ali/__init__.py
  33. 1
      fir_ser/api/utils/ali/api.py
  34. 1
      fir_ser/api/utils/ali/client/__init__.py
  35. 1
      fir_ser/api/utils/ali/client/api/__init__.py
  36. 1
      fir_ser/api/utils/ali/client/basic.py
  37. 1
      fir_ser/api/utils/ali/pay/__init__.py
  38. 1
      fir_ser/api/utils/ali/pay/api/base.py
  39. 4
      fir_ser/api/utils/ali/pay/basic.py
  40. 1
      fir_ser/api/utils/ali/yun/api/base.py
  41. 13
      fir_ser/api/utils/ali/yun/api/sms.py
  42. 13
      fir_ser/api/utils/ali/yun/api/vod.py
  43. 4
      fir_ser/api/utils/ali/yun/basic.py
  44. 30
      fir_ser/api/utils/app/apputils.py
  45. 16
      fir_ser/api/utils/app/dadf.py
  46. 28
      fir_ser/api/utils/app/firApi.py
  47. 102
      fir_ser/api/utils/app/iossignapi.py
  48. 13
      fir_ser/api/utils/app/randomstrings.py
  49. 97
      fir_ser/api/utils/app/raqc.py
  50. 80
      fir_ser/api/utils/app/shellcmds.py
  51. 150
      fir_ser/api/utils/app/supersignutils.py
  52. 9
      fir_ser/api/utils/auth.py
  53. 3
      fir_ser/api/utils/captcha_verify.py
  54. 7
      fir_ser/api/utils/crontab/sync_cache.py
  55. 2
      fir_ser/api/utils/geetest.py
  56. 10
      fir_ser/api/utils/middlewares.py
  57. 6
      fir_ser/api/utils/permission.py
  58. 12
      fir_ser/api/utils/response.py
  59. 99
      fir_ser/api/utils/serializer.py
  60. 41
      fir_ser/api/utils/storage/aliyunApi.py
  61. 104
      fir_ser/api/utils/storage/caches.py
  62. 20
      fir_ser/api/utils/storage/localApi.py
  63. 24
      fir_ser/api/utils/storage/qiniuApi.py
  64. 12
      fir_ser/api/utils/storage/storage.py
  65. 19
      fir_ser/api/utils/utils.py
  66. 32
      fir_ser/api/views/apps.py
  67. 97
      fir_ser/api/views/download.py
  68. 55
      fir_ser/api/views/login.py
  69. 2
      fir_ser/api/views/logout.py
  70. 22
      fir_ser/api/views/receiveudids.py
  71. 12
      fir_ser/api/views/storage.py
  72. 116
      fir_ser/api/views/supersign.py
  73. 111
      fir_ser/api/views/uploads.py
  74. 74
      fir_ser/fir_ser/settings.py
  75. 7
      fir_ser/fir_ser/urls.py
  76. 16
      fir_ser/tests/postudid.py

@ -9,8 +9,7 @@
export default { export default {
name: 'app', name: 'app',
data() { data() {
return { return {}
}
}, },
} }
</script> </script>
@ -20,13 +19,12 @@
background-color: rgba(0, 166, 224, 0.18) background-color: rgba(0, 166, 224, 0.18)
} }
@font-face {font-family: "iconfont"; @font-face {
font-family: "iconfont";
src: url('./assets/icon/iconfont.eot?t=1583637102320'); /* IE9 */ src: url('./assets/icon/iconfont.eot?t=1583637102320'); /* IE9 */
src: url('./assets/icon/iconfont.eot?t=1583637102320#iefix') format('embedded-opentype'), /* IE6-IE8 */ src: url('./assets/icon/iconfont.eot?t=1583637102320#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAnUAAsAAAAAEXwAAAmIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEIAqUYJBKATYCJAMoCxYABCAFhG0HdhuGDlGUL1aT7CuMW3giIDU2lBZVYzMmA6BYbBoB4AIAvsWyNCR1ZYRAPDyt/e/cmdn1b4KYdG+eSCaJRMWjWPVE6ZTyQkZL4P/W2j938EFdZvf2bG4F1UgXqyQeKfBIqpGQb4i2eQ/W/4P6Ek9oYwayNWYT2liwtS7KBWzNL+pBXQarNpcN/6uINB8EdIMjCcASCSSx4cAb7oGJPvjzf6maMe0OLEmbbAtQ1TLH+t2bjwpcoLGH1RZY9/OCWElqEp69Ctt/lUoZgKMJ9DZKJTpb39oLSoVQBWoeMPQUKGtmZQQOra7u2bKID6DSppeMC3hP7x//HA0lSZWJNS/fr5uFyp+QiaT/uZpYwYv1OWFuR8Z+oBDfe93f5Fy5n9R9H1g8BBYZNWVZ128wWubBX4gsc00C/+npXSCHRbkuqBVJ6GSNo/zjETVVPQL/ONPxMyIeNT9HHoWfyzwSPzeo8DQ7IF5OsxdGGZpzMGqgeQOjCpoJxHejmz7ZYhE4AvIjgLIWhPY8ORu1xKf7mSXfEqJWz1lFqu4IsUVclojNFtvZeZZJWCxfTwc225MLw+IOJVu9jIhlZydks0WD2YzVCGJDzZv3bRWtVSPgFM6ZTJDKjCPGrSIdax2dlWgymUleOEnitJKXpPyEKz9ri1IZTMalepIwQ/od1OvB5hq3QpDBcnCLkASgX+Ot37xvI9/Ep9QGC7EF1DMQNJgws3VoBmqIDgCbNXYuVd01lKFvR5CqnITxPpi1Z23gbKCzVCYzT3meaFLvhr5kmfWJDrV+iz8KDo/ogiAUbGoo8SKbLBDTGVnfLmB0BpiGzuEVMxCPpJitnaqi7QPc/I2nEGN6Yb7eUj2voN2qcKHuJxEIVUb7HLspkHcwNKgtsk9XrLzLL2qnl/syr6WbOyffau0FeKUntEq8bGeo+bLsHFVv2IggXAm3BxcRKD4qQJAKpPFED97cegA2kUtJkufhEa5hguf0l6KbAjfRsqUoyisV/sajng+9Tg8sp/2sVPRImnYco2IPWCUbqfgT1lSrrW/7VfTgedn+s9KD1yN30pCRKrXQnuutQZutHvvpsYD3WcPOT9ADl+8K2mVNPnAp9cSF3FNUNnVr4DitOXmXd5BOI2x9VwM0UXRJJ6U6MWENSmG19tlu9tF0g83WkJw35hw1brVGEXTtxk4RtKzrdEcwaG7N+s0ANrPfcth3vHWoM7SOzosxLcPNKMmLbqN7xpoDCR7Zwo26aAOV2mziKs4ZG1WmpTzlGUXJPpWdjSaDmSD1S9EsUryx0/OqplwYy9vjrrPyxLZUyHbAlg4UBYchLJdPRqKr5WY1GnenBYElwhrjZsE0UWXitVtXau4B6TbsEETKTYgqW7ca11skHotAqCLSqu8TzTldome82Wsp5a2lPn03qYZV0HrRfaYtuR2xJ6W3pQhPi8Xyezqa3c8TyNnMNv1zOy+QUBFrb8+Yo3hUiDsBt4OTRPQOeXLy11deWJbq1+OgVrJp8JITpcISj+p5aa9SJ5TKi/o2VKD37G/xu1ERehnQt/bKk+LfZZ2Li48XXAy/KLjDXTbqabKD0+DFjk5YidPrAw8b+ADh3wm7wHd0BAD7RC6YL3I63Np/w+1uHZyLbhdOOgWY4JsQi8aE33JgNDJJFCsKnToP+Ain5hLZJ+oMIeJY0aRZzy41NiRiiRkNlwIzZVR8UKZ6gjrOx1Oy55plBcn64P+UtFEhJJwsTRaRKlKkLQ6TIVFajgW4FybDoZ1loaLkI+ACamn7vt5/X1BiF1y1/8m85UFdNdyaAG6A7phsAKgEUNljkEgZGhJqDY7/TQBeHCUBQ7bM3HwgbX2hUHhqbn3VDsIVYcAoomY1TISKHcKariNO2PbaZgyX5N6oC/OHfNjxXzabV+91hR2d90zbk6bWotfUxzuvZ/mWE2AIgaUsOMde5snf/NxBElNVPnB045As1kLdjhRM0wCJH8X384+4FiQpzJ3tlufDTZydm1/k+xI80DKzs7INNcWemo9FflMbU70a5MXSzpiaiJeyfPP74Jjso8dKNQbLzDuiJKZjVebQuSV4UtxHuc94mSgx1kfuDXSn54cWlI/IC901zzN/UFheSAz85UPeQ4W6cPeJ5Z7Qz3V1Yf4DxUwcjVMOHNy/Z7VCcnVNu+RhrCZm2Pgc/PekHiDmSxhpaVX/Zpb3ybTr7gmq/SQPHuhYh85ZyzAgS9bhdbCcmeKbiAdODfLT8OYfiitWlDYqpvArls3WTlgMAt2/dHlh2PKgTf9C3xZ6SfMPf4H/e/DeeBU9YTHXud+QEcczVOuLHD+8pR7Q4ItaA4rCDaqSE1PLB/c/6xOQwt8fF5DmMMYhIFW6P8A/ZWWSDlR+AvKkAZJcuA2ThltOqtHilt0hhX74CCiuz12fJrwJOm/kar23PmgzaH21LlvtP7SQMKjJ4X3Ge4emTB16l/FuniAh5KR716vKe+sOOlsSWpJUK/6+4R1UkQDelaH4e4fnCqZB8Dwv3HAbkMo7II0h+zH2kPQAT7diZzA60R6o3IB2E8hUwxCdENuicNkw3pQ1YR3AhGA9UOqmhVWC7/HngiboCBZbg4KDzga9uu/nfkayyrXNtb5N0LO3U5vStQ1TJl+Jq2M/00nrlp1baILFTn7eSQjGzoIaSRi7V5FYhGUuwcaARMOYt59wXsE8J7+YWJonyFWLkc/AlG4gigJdJjGTQJ1iCbNXk56FOQWmJZOoT+UzxdQWBqaOatItGSBI3E3MxD40KfmrXQpS5vyRCZc+X53Qn98Zz0aZ+yj0f0oB601pJcIT/LFKmMNKINMsffEGFomXauqjNqtKllBO4+/UP+993doltuQfXLtU0pPGBnrW2o4u+P30yuA4vdY6Qe/t07D9YAFHIkqHvfYUeph1RU+m/aBns24EEAD/Rq8s+xcelTUkEMB7JTjY42BnMOokDk8JeBZNLyFmhvio0Caos9puTM95priqjCj9mOOZGMpKz2zmGrAPc+tYh5+nswWBQhRHvKheOR72eAjyc8SFZ4R0pyD4izMyqL5102eIF9TO4GBThIR9FjJtiZ8xg/ChkAXq1tt3w2hzPKZwI736/P0wDo+ZPZIlXSYD3aD2sXrdF5A3j5ZNUJ0UFHXkEF5IverEPDJNIP7+xVywGYJ0ziWSfsUy1NEorjp9+1rvrS37se5DXLePFDlKVFFHE2100cegueWb5QgzqyRdljFPtoQhvCSjo0cKVVaMkK2o4rlyAAA=') format('woff2'),
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAnUAAsAAAAAEXwAAAmIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEIAqUYJBKATYCJAMoCxYABCAFhG0HdhuGDlGUL1aT7CuMW3giIDU2lBZVYzMmA6BYbBoB4AIAvsWyNCR1ZYRAPDyt/e/cmdn1b4KYdG+eSCaJRMWjWPVE6ZTyQkZL4P/W2j938EFdZvf2bG4F1UgXqyQeKfBIqpGQb4i2eQ/W/4P6Ek9oYwayNWYT2liwtS7KBWzNL+pBXQarNpcN/6uINB8EdIMjCcASCSSx4cAb7oGJPvjzf6maMe0OLEmbbAtQ1TLH+t2bjwpcoLGH1RZY9/OCWElqEp69Ctt/lUoZgKMJ9DZKJTpb39oLSoVQBWoeMPQUKGtmZQQOra7u2bKID6DSppeMC3hP7x//HA0lSZWJNS/fr5uFyp+QiaT/uZpYwYv1OWFuR8Z+oBDfe93f5Fy5n9R9H1g8BBYZNWVZ128wWubBX4gsc00C/+npXSCHRbkuqBVJ6GSNo/zjETVVPQL/ONPxMyIeNT9HHoWfyzwSPzeo8DQ7IF5OsxdGGZpzMGqgeQOjCpoJxHejmz7ZYhE4AvIjgLIWhPY8ORu1xKf7mSXfEqJWz1lFqu4IsUVclojNFtvZeZZJWCxfTwc225MLw+IOJVu9jIhlZydks0WD2YzVCGJDzZv3bRWtVSPgFM6ZTJDKjCPGrSIdax2dlWgymUleOEnitJKXpPyEKz9ri1IZTMalepIwQ/od1OvB5hq3QpDBcnCLkASgX+Ot37xvI9/Ep9QGC7EF1DMQNJgws3VoBmqIDgCbNXYuVd01lKFvR5CqnITxPpi1Z23gbKCzVCYzT3meaFLvhr5kmfWJDrV+iz8KDo/ogiAUbGoo8SKbLBDTGVnfLmB0BpiGzuEVMxCPpJitnaqi7QPc/I2nEGN6Yb7eUj2voN2qcKHuJxEIVUb7HLspkHcwNKgtsk9XrLzLL2qnl/syr6WbOyffau0FeKUntEq8bGeo+bLsHFVv2IggXAm3BxcRKD4qQJAKpPFED97cegA2kUtJkufhEa5hguf0l6KbAjfRsqUoyisV/sajng+9Tg8sp/2sVPRImnYco2IPWCUbqfgT1lSrrW/7VfTgedn+s9KD1yN30pCRKrXQnuutQZutHvvpsYD3WcPOT9ADl+8K2mVNPnAp9cSF3FNUNnVr4DitOXmXd5BOI2x9VwM0UXRJJ6U6MWENSmG19tlu9tF0g83WkJw35hw1brVGEXTtxk4RtKzrdEcwaG7N+s0ANrPfcth3vHWoM7SOzosxLcPNKMmLbqN7xpoDCR7Zwo26aAOV2mziKs4ZG1WmpTzlGUXJPpWdjSaDmSD1S9EsUryx0/OqplwYy9vjrrPyxLZUyHbAlg4UBYchLJdPRqKr5WY1GnenBYElwhrjZsE0UWXitVtXau4B6TbsEETKTYgqW7ca11skHotAqCLSqu8TzTldome82Wsp5a2lPn03qYZV0HrRfaYtuR2xJ6W3pQhPi8Xyezqa3c8TyNnMNv1zOy+QUBFrb8+Yo3hUiDsBt4OTRPQOeXLy11deWJbq1+OgVrJp8JITpcISj+p5aa9SJ5TKi/o2VKD37G/xu1ERehnQt/bKk+LfZZ2Li48XXAy/KLjDXTbqabKD0+DFjk5YidPrAw8b+ADh3wm7wHd0BAD7RC6YL3I63Np/w+1uHZyLbhdOOgWY4JsQi8aE33JgNDJJFCsKnToP+Ain5hLZJ+oMIeJY0aRZzy41NiRiiRkNlwIzZVR8UKZ6gjrOx1Oy55plBcn64P+UtFEhJJwsTRaRKlKkLQ6TIVFajgW4FybDoZ1loaLkI+ACamn7vt5/X1BiF1y1/8m85UFdNdyaAG6A7phsAKgEUNljkEgZGhJqDY7/TQBeHCUBQ7bM3HwgbX2hUHhqbn3VDsIVYcAoomY1TISKHcKariNO2PbaZgyX5N6oC/OHfNjxXzabV+91hR2d90zbk6bWotfUxzuvZ/mWE2AIgaUsOMde5snf/NxBElNVPnB045As1kLdjhRM0wCJH8X384+4FiQpzJ3tlufDTZydm1/k+xI80DKzs7INNcWemo9FflMbU70a5MXSzpiaiJeyfPP74Jjso8dKNQbLzDuiJKZjVebQuSV4UtxHuc94mSgx1kfuDXSn54cWlI/IC901zzN/UFheSAz85UPeQ4W6cPeJ5Z7Qz3V1Yf4DxUwcjVMOHNy/Z7VCcnVNu+RhrCZm2Pgc/PekHiDmSxhpaVX/Zpb3ybTr7gmq/SQPHuhYh85ZyzAgS9bhdbCcmeKbiAdODfLT8OYfiitWlDYqpvArls3WTlgMAt2/dHlh2PKgTf9C3xZ6SfMPf4H/e/DeeBU9YTHXud+QEcczVOuLHD+8pR7Q4ItaA4rCDaqSE1PLB/c/6xOQwt8fF5DmMMYhIFW6P8A/ZWWSDlR+AvKkAZJcuA2ThltOqtHilt0hhX74CCiuz12fJrwJOm/kar23PmgzaH21LlvtP7SQMKjJ4X3Ge4emTB16l/FuniAh5KR716vKe+sOOlsSWpJUK/6+4R1UkQDelaH4e4fnCqZB8Dwv3HAbkMo7II0h+zH2kPQAT7diZzA60R6o3IB2E8hUwxCdENuicNkw3pQ1YR3AhGA9UOqmhVWC7/HngiboCBZbg4KDzga9uu/nfkayyrXNtb5N0LO3U5vStQ1TJl+Jq2M/00nrlp1baILFTn7eSQjGzoIaSRi7V5FYhGUuwcaARMOYt59wXsE8J7+YWJonyFWLkc/AlG4gigJdJjGTQJ1iCbNXk56FOQWmJZOoT+UzxdQWBqaOatItGSBI3E3MxD40KfmrXQpS5vyRCZc+X53Qn98Zz0aZ+yj0f0oB601pJcIT/LFKmMNKINMsffEGFomXauqjNqtKllBO4+/UP+993doltuQfXLtU0pPGBnrW2o4u+P30yuA4vdY6Qe/t07D9YAFHIkqHvfYUeph1RU+m/aBns24EEAD/Rq8s+xcelTUkEMB7JTjY42BnMOokDk8JeBZNLyFmhvio0Caos9puTM95priqjCj9mOOZGMpKz2zmGrAPc+tYh5+nswWBQhRHvKheOR72eAjyc8SFZ4R0pyD4izMyqL5102eIF9TO4GBThIR9FjJtiZ8xg/ChkAXq1tt3w2hzPKZwI736/P0wDo+ZPZIlXSYD3aD2sXrdF5A3j5ZNUJ0UFHXkEF5IverEPDJNIP7+xVywGYJ0ziWSfsUy1NEorjp9+1rvrS37se5DXLePFDlKVFFHE2100cegueWb5QgzqyRdljFPtoQhvCSjo0cKVVaMkK2o4rlyAAA=') format('woff2'),
url('./assets/icon/iconfont.woff?t=1583637102320') format('woff'), url('./assets/icon/iconfont.woff?t=1583637102320') format('woff'),
url('./assets/icon/iconfont.ttf?t=1583637102320') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('./assets/icon/iconfont.ttf?t=1583637102320') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('./assets/icon/iconfont.svg?t=1583637102320#iconfont') format('svg'); /* iOS 4.1- */
url('./assets/icon/iconfont.svg?t=1583637102320#iconfont') format('svg'); /* iOS 4.1- */
} }
.iconfont { .iconfont {
@ -74,7 +72,4 @@
} }
</style> </style>

@ -1,53 +1,52 @@
@font-face {font-family: "iconfont"; @font-face {
src: url('iconfont.eot?t=1583637102320'); /* IE9 */ font-family: "iconfont";
src: url('iconfont.eot?t=1583637102320#iefix') format('embedded-opentype'), /* IE6-IE8 */ src: url('iconfont.eot?t=1583637102320'); /* IE9 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAnUAAsAAAAAEXwAAAmIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEIAqUYJBKATYCJAMoCxYABCAFhG0HdhuGDlGUL1aT7CuMW3giIDU2lBZVYzMmA6BYbBoB4AIAvsWyNCR1ZYRAPDyt/e/cmdn1b4KYdG+eSCaJRMWjWPVE6ZTyQkZL4P/W2j938EFdZvf2bG4F1UgXqyQeKfBIqpGQb4i2eQ/W/4P6Ek9oYwayNWYT2liwtS7KBWzNL+pBXQarNpcN/6uINB8EdIMjCcASCSSx4cAb7oGJPvjzf6maMe0OLEmbbAtQ1TLH+t2bjwpcoLGH1RZY9/OCWElqEp69Ctt/lUoZgKMJ9DZKJTpb39oLSoVQBWoeMPQUKGtmZQQOra7u2bKID6DSppeMC3hP7x//HA0lSZWJNS/fr5uFyp+QiaT/uZpYwYv1OWFuR8Z+oBDfe93f5Fy5n9R9H1g8BBYZNWVZ128wWubBX4gsc00C/+npXSCHRbkuqBVJ6GSNo/zjETVVPQL/ONPxMyIeNT9HHoWfyzwSPzeo8DQ7IF5OsxdGGZpzMGqgeQOjCpoJxHejmz7ZYhE4AvIjgLIWhPY8ORu1xKf7mSXfEqJWz1lFqu4IsUVclojNFtvZeZZJWCxfTwc225MLw+IOJVu9jIhlZydks0WD2YzVCGJDzZv3bRWtVSPgFM6ZTJDKjCPGrSIdax2dlWgymUleOEnitJKXpPyEKz9ri1IZTMalepIwQ/od1OvB5hq3QpDBcnCLkASgX+Ot37xvI9/Ep9QGC7EF1DMQNJgws3VoBmqIDgCbNXYuVd01lKFvR5CqnITxPpi1Z23gbKCzVCYzT3meaFLvhr5kmfWJDrV+iz8KDo/ogiAUbGoo8SKbLBDTGVnfLmB0BpiGzuEVMxCPpJitnaqi7QPc/I2nEGN6Yb7eUj2voN2qcKHuJxEIVUb7HLspkHcwNKgtsk9XrLzLL2qnl/syr6WbOyffau0FeKUntEq8bGeo+bLsHFVv2IggXAm3BxcRKD4qQJAKpPFED97cegA2kUtJkufhEa5hguf0l6KbAjfRsqUoyisV/sajng+9Tg8sp/2sVPRImnYco2IPWCUbqfgT1lSrrW/7VfTgedn+s9KD1yN30pCRKrXQnuutQZutHvvpsYD3WcPOT9ADl+8K2mVNPnAp9cSF3FNUNnVr4DitOXmXd5BOI2x9VwM0UXRJJ6U6MWENSmG19tlu9tF0g83WkJw35hw1brVGEXTtxk4RtKzrdEcwaG7N+s0ANrPfcth3vHWoM7SOzosxLcPNKMmLbqN7xpoDCR7Zwo26aAOV2mziKs4ZG1WmpTzlGUXJPpWdjSaDmSD1S9EsUryx0/OqplwYy9vjrrPyxLZUyHbAlg4UBYchLJdPRqKr5WY1GnenBYElwhrjZsE0UWXitVtXau4B6TbsEETKTYgqW7ca11skHotAqCLSqu8TzTldome82Wsp5a2lPn03qYZV0HrRfaYtuR2xJ6W3pQhPi8Xyezqa3c8TyNnMNv1zOy+QUBFrb8+Yo3hUiDsBt4OTRPQOeXLy11deWJbq1+OgVrJp8JITpcISj+p5aa9SJ5TKi/o2VKD37G/xu1ERehnQt/bKk+LfZZ2Li48XXAy/KLjDXTbqabKD0+DFjk5YidPrAw8b+ADh3wm7wHd0BAD7RC6YL3I63Np/w+1uHZyLbhdOOgWY4JsQi8aE33JgNDJJFCsKnToP+Ain5hLZJ+oMIeJY0aRZzy41NiRiiRkNlwIzZVR8UKZ6gjrOx1Oy55plBcn64P+UtFEhJJwsTRaRKlKkLQ6TIVFajgW4FybDoZ1loaLkI+ACamn7vt5/X1BiF1y1/8m85UFdNdyaAG6A7phsAKgEUNljkEgZGhJqDY7/TQBeHCUBQ7bM3HwgbX2hUHhqbn3VDsIVYcAoomY1TISKHcKariNO2PbaZgyX5N6oC/OHfNjxXzabV+91hR2d90zbk6bWotfUxzuvZ/mWE2AIgaUsOMde5snf/NxBElNVPnB045As1kLdjhRM0wCJH8X384+4FiQpzJ3tlufDTZydm1/k+xI80DKzs7INNcWemo9FflMbU70a5MXSzpiaiJeyfPP74Jjso8dKNQbLzDuiJKZjVebQuSV4UtxHuc94mSgx1kfuDXSn54cWlI/IC901zzN/UFheSAz85UPeQ4W6cPeJ5Z7Qz3V1Yf4DxUwcjVMOHNy/Z7VCcnVNu+RhrCZm2Pgc/PekHiDmSxhpaVX/Zpb3ybTr7gmq/SQPHuhYh85ZyzAgS9bhdbCcmeKbiAdODfLT8OYfiitWlDYqpvArls3WTlgMAt2/dHlh2PKgTf9C3xZ6SfMPf4H/e/DeeBU9YTHXud+QEcczVOuLHD+8pR7Q4ItaA4rCDaqSE1PLB/c/6xOQwt8fF5DmMMYhIFW6P8A/ZWWSDlR+AvKkAZJcuA2ThltOqtHilt0hhX74CCiuz12fJrwJOm/kar23PmgzaH21LlvtP7SQMKjJ4X3Ge4emTB16l/FuniAh5KR716vKe+sOOlsSWpJUK/6+4R1UkQDelaH4e4fnCqZB8Dwv3HAbkMo7II0h+zH2kPQAT7diZzA60R6o3IB2E8hUwxCdENuicNkw3pQ1YR3AhGA9UOqmhVWC7/HngiboCBZbg4KDzga9uu/nfkayyrXNtb5N0LO3U5vStQ1TJl+Jq2M/00nrlp1baILFTn7eSQjGzoIaSRi7V5FYhGUuwcaARMOYt59wXsE8J7+YWJonyFWLkc/AlG4gigJdJjGTQJ1iCbNXk56FOQWmJZOoT+UzxdQWBqaOatItGSBI3E3MxD40KfmrXQpS5vyRCZc+X53Qn98Zz0aZ+yj0f0oB601pJcIT/LFKmMNKINMsffEGFomXauqjNqtKllBO4+/UP+993doltuQfXLtU0pPGBnrW2o4u+P30yuA4vdY6Qe/t07D9YAFHIkqHvfYUeph1RU+m/aBns24EEAD/Rq8s+xcelTUkEMB7JTjY42BnMOokDk8JeBZNLyFmhvio0Caos9puTM95priqjCj9mOOZGMpKz2zmGrAPc+tYh5+nswWBQhRHvKheOR72eAjyc8SFZ4R0pyD4izMyqL5102eIF9TO4GBThIR9FjJtiZ8xg/ChkAXq1tt3w2hzPKZwI736/P0wDo+ZPZIlXSYD3aD2sXrdF5A3j5ZNUJ0UFHXkEF5IverEPDJNIP7+xVywGYJ0ziWSfsUy1NEorjp9+1rvrS37se5DXLePFDlKVFFHE2100cegueWb5QgzqyRdljFPtoQhvCSjo0cKVVaMkK2o4rlyAAA=') format('woff2'), src: url('iconfont.eot?t=1583637102320#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAnUAAsAAAAAEXwAAAmIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEIAqUYJBKATYCJAMoCxYABCAFhG0HdhuGDlGUL1aT7CuMW3giIDU2lBZVYzMmA6BYbBoB4AIAvsWyNCR1ZYRAPDyt/e/cmdn1b4KYdG+eSCaJRMWjWPVE6ZTyQkZL4P/W2j938EFdZvf2bG4F1UgXqyQeKfBIqpGQb4i2eQ/W/4P6Ek9oYwayNWYT2liwtS7KBWzNL+pBXQarNpcN/6uINB8EdIMjCcASCSSx4cAb7oGJPvjzf6maMe0OLEmbbAtQ1TLH+t2bjwpcoLGH1RZY9/OCWElqEp69Ctt/lUoZgKMJ9DZKJTpb39oLSoVQBWoeMPQUKGtmZQQOra7u2bKID6DSppeMC3hP7x//HA0lSZWJNS/fr5uFyp+QiaT/uZpYwYv1OWFuR8Z+oBDfe93f5Fy5n9R9H1g8BBYZNWVZ128wWubBX4gsc00C/+npXSCHRbkuqBVJ6GSNo/zjETVVPQL/ONPxMyIeNT9HHoWfyzwSPzeo8DQ7IF5OsxdGGZpzMGqgeQOjCpoJxHejmz7ZYhE4AvIjgLIWhPY8ORu1xKf7mSXfEqJWz1lFqu4IsUVclojNFtvZeZZJWCxfTwc225MLw+IOJVu9jIhlZydks0WD2YzVCGJDzZv3bRWtVSPgFM6ZTJDKjCPGrSIdax2dlWgymUleOEnitJKXpPyEKz9ri1IZTMalepIwQ/od1OvB5hq3QpDBcnCLkASgX+Ot37xvI9/Ep9QGC7EF1DMQNJgws3VoBmqIDgCbNXYuVd01lKFvR5CqnITxPpi1Z23gbKCzVCYzT3meaFLvhr5kmfWJDrV+iz8KDo/ogiAUbGoo8SKbLBDTGVnfLmB0BpiGzuEVMxCPpJitnaqi7QPc/I2nEGN6Yb7eUj2voN2qcKHuJxEIVUb7HLspkHcwNKgtsk9XrLzLL2qnl/syr6WbOyffau0FeKUntEq8bGeo+bLsHFVv2IggXAm3BxcRKD4qQJAKpPFED97cegA2kUtJkufhEa5hguf0l6KbAjfRsqUoyisV/sajng+9Tg8sp/2sVPRImnYco2IPWCUbqfgT1lSrrW/7VfTgedn+s9KD1yN30pCRKrXQnuutQZutHvvpsYD3WcPOT9ADl+8K2mVNPnAp9cSF3FNUNnVr4DitOXmXd5BOI2x9VwM0UXRJJ6U6MWENSmG19tlu9tF0g83WkJw35hw1brVGEXTtxk4RtKzrdEcwaG7N+s0ANrPfcth3vHWoM7SOzosxLcPNKMmLbqN7xpoDCR7Zwo26aAOV2mziKs4ZG1WmpTzlGUXJPpWdjSaDmSD1S9EsUryx0/OqplwYy9vjrrPyxLZUyHbAlg4UBYchLJdPRqKr5WY1GnenBYElwhrjZsE0UWXitVtXau4B6TbsEETKTYgqW7ca11skHotAqCLSqu8TzTldome82Wsp5a2lPn03qYZV0HrRfaYtuR2xJ6W3pQhPi8Xyezqa3c8TyNnMNv1zOy+QUBFrb8+Yo3hUiDsBt4OTRPQOeXLy11deWJbq1+OgVrJp8JITpcISj+p5aa9SJ5TKi/o2VKD37G/xu1ERehnQt/bKk+LfZZ2Li48XXAy/KLjDXTbqabKD0+DFjk5YidPrAw8b+ADh3wm7wHd0BAD7RC6YL3I63Np/w+1uHZyLbhdOOgWY4JsQi8aE33JgNDJJFCsKnToP+Ain5hLZJ+oMIeJY0aRZzy41NiRiiRkNlwIzZVR8UKZ6gjrOx1Oy55plBcn64P+UtFEhJJwsTRaRKlKkLQ6TIVFajgW4FybDoZ1loaLkI+ACamn7vt5/X1BiF1y1/8m85UFdNdyaAG6A7phsAKgEUNljkEgZGhJqDY7/TQBeHCUBQ7bM3HwgbX2hUHhqbn3VDsIVYcAoomY1TISKHcKariNO2PbaZgyX5N6oC/OHfNjxXzabV+91hR2d90zbk6bWotfUxzuvZ/mWE2AIgaUsOMde5snf/NxBElNVPnB045As1kLdjhRM0wCJH8X384+4FiQpzJ3tlufDTZydm1/k+xI80DKzs7INNcWemo9FflMbU70a5MXSzpiaiJeyfPP74Jjso8dKNQbLzDuiJKZjVebQuSV4UtxHuc94mSgx1kfuDXSn54cWlI/IC901zzN/UFheSAz85UPeQ4W6cPeJ5Z7Qz3V1Yf4DxUwcjVMOHNy/Z7VCcnVNu+RhrCZm2Pgc/PekHiDmSxhpaVX/Zpb3ybTr7gmq/SQPHuhYh85ZyzAgS9bhdbCcmeKbiAdODfLT8OYfiitWlDYqpvArls3WTlgMAt2/dHlh2PKgTf9C3xZ6SfMPf4H/e/DeeBU9YTHXud+QEcczVOuLHD+8pR7Q4ItaA4rCDaqSE1PLB/c/6xOQwt8fF5DmMMYhIFW6P8A/ZWWSDlR+AvKkAZJcuA2ThltOqtHilt0hhX74CCiuz12fJrwJOm/kar23PmgzaH21LlvtP7SQMKjJ4X3Ge4emTB16l/FuniAh5KR716vKe+sOOlsSWpJUK/6+4R1UkQDelaH4e4fnCqZB8Dwv3HAbkMo7II0h+zH2kPQAT7diZzA60R6o3IB2E8hUwxCdENuicNkw3pQ1YR3AhGA9UOqmhVWC7/HngiboCBZbg4KDzga9uu/nfkayyrXNtb5N0LO3U5vStQ1TJl+Jq2M/00nrlp1baILFTn7eSQjGzoIaSRi7V5FYhGUuwcaARMOYt59wXsE8J7+YWJonyFWLkc/AlG4gigJdJjGTQJ1iCbNXk56FOQWmJZOoT+UzxdQWBqaOatItGSBI3E3MxD40KfmrXQpS5vyRCZc+X53Qn98Zz0aZ+yj0f0oB601pJcIT/LFKmMNKINMsffEGFomXauqjNqtKllBO4+/UP+993doltuQfXLtU0pPGBnrW2o4u+P30yuA4vdY6Qe/t07D9YAFHIkqHvfYUeph1RU+m/aBns24EEAD/Rq8s+xcelTUkEMB7JTjY42BnMOokDk8JeBZNLyFmhvio0Caos9puTM95priqjCj9mOOZGMpKz2zmGrAPc+tYh5+nswWBQhRHvKheOR72eAjyc8SFZ4R0pyD4izMyqL5102eIF9TO4GBThIR9FjJtiZ8xg/ChkAXq1tt3w2hzPKZwI736/P0wDo+ZPZIlXSYD3aD2sXrdF5A3j5ZNUJ0UFHXkEF5IverEPDJNIP7+xVywGYJ0ziWSfsUy1NEorjp9+1rvrS37se5DXLePFDlKVFFHE2100cegueWb5QgzqyRdljFPtoQhvCSjo0cKVVaMkK2o4rlyAAA=') format('woff2'),
url('iconfont.woff?t=1583637102320') format('woff'), url('iconfont.woff?t=1583637102320') format('woff'),
url('iconfont.ttf?t=1583637102320') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('iconfont.ttf?t=1583637102320') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('iconfont.svg?t=1583637102320#iconfont') format('svg'); /* iOS 4.1- */
url('iconfont.svg?t=1583637102320#iconfont') format('svg'); /* iOS 4.1- */
} }
.iconfont { .iconfont {
font-family: "iconfont" !important; font-family: "iconfont" !important;
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-android:before { .icon-android:before {
content: "\e61d"; content: "\e61d";
} }
.icon-android1:before { .icon-android1:before {
content: "\e616"; content: "\e616";
} }
.icon-android2:before { .icon-android2:before {
content: "\e62a"; content: "\e62a";
} }
.icon-ios:before { .icon-ios:before {
content: "\e60c"; content: "\e60c";
} }
.icon-IOS:before { .icon-IOS:before {
content: "\e68c"; content: "\e68c";
} }
.icon-ios1:before { .icon-ios1:before {
content: "\e601"; content: "\e601";
} }
.icon-ios2:before { .icon-ios2:before {
content: "\e64b"; content: "\e64b";
} }
.icon-Android:before { .icon-Android:before {
content: "\e6d4"; content: "\e6d4";
} }
.icon-android3:before { .icon-android3:before {
content: "\e625"; content: "\e625";
} }

@ -4,50 +4,67 @@
2013-9-30: Created. 2013-9-30: Created.
--> -->
<svg> <svg>
<metadata> <metadata>
Created by iconfont Created by iconfont
</metadata> </metadata>
<defs> <defs>
<font id="iconfont" horiz-adv-x="1024" > <font id="iconfont" horiz-adv-x="1024">
<font-face <font-face
font-family="iconfont" font-family="iconfont"
font-weight="500" font-weight="500"
font-stretch="normal" font-stretch="normal"
units-per-em="1024" units-per-em="1024"
ascent="896" ascent="896"
descent="-128" descent="-128"
/> />
<missing-glyph /> <missing-glyph/>
<glyph glyph-name="android" unicode="&#58909;" d="M269.401218 547.905l484.587674 0 0-11.106965c0-120.589472 0.023536-241.183038-0.011256-361.76944-0.011256-40.771589-21.756513-62.327534-62.705134-62.342884-10.184967 0-20.37198 0-29.858028 0 0-43.198871 0.467651-85.178985-0.171915-127.141702-0.397043-26.024723-22.889313-47.623647-48.671513-48.568159-27.686573-1.013073-52.970422 18.175965-53.951773 44.760436-1.579985 42.982954-0.425695 86.064145-0.425695 130.026402l-92.891643 0c0-17.075911 0.033769-34.169217-0.005117-51.256384-0.055259-25.179472 0.483001-50.374294-0.428765-75.523067-0.896416-24.611537-20.249183-44.734854-44.115754-47.749514-25.325805-3.202948-49.012274 11.464099-56.531528 35.426861-1.660826 5.300726-2.638083 11.033287-2.675946 16.571421-0.234337 35.778878-0.174985 71.555709-0.064468 107.33561 0.013303 4.910846 0.836041 9.815553 1.417279 16.121166-12.051477 0-23.86657-0.073678-35.68678 0.011256-34.978652 0.254803-57.743122 22.928199-57.767682 58.021461-0.100284 122.571616-0.039909 245.152443-0.042979 367.729176L269.400195 547.905 269.401218 547.905zM754.197646 583.671599 268.922311 583.671599c4.508687 83.888596 52.172243 136.038326 123.015731 173.068707-7.217379 10.940167-14.230096 21.587668-21.263279 32.217772-5.119601 7.730055-10.30674 15.407921-15.398712 23.150256-3.591805 5.460362-9.344832 11.614525-1.36509 17.062608 8.616238 5.885034 12.135388-2.347464 15.941064-7.959276 9.094122-13.428847 18.064424-26.946722 27.064402-40.440038 11.086499-16.617469 11.078313-16.613376 30.132274-11.05887 60.601216 17.662265 120.804367 16.659425 180.590008-3.89061 2.139733-0.738827 4.331655-1.331321 7.135514-2.183735 12.395308 18.558681 24.680099 36.96182 36.96489 55.358819 1.471514 2.206248 2.910283 4.427846 4.428869 6.598278 3.459798 4.948709 7.856945 7.618515 13.384845 3.53757 5.008061-3.693112 4.154623-8.404414 0.994654-13.125949-10.67513-15.95232-21.285792-31.954783-31.911804-47.940872-2.371-3.571339-4.705162-7.167237-7.42204-11.304464 70.458725-36.700877 118.544907-88.950891 122.990149-173.090197L754.197646 583.671599zM641.381208 678.031687c0.150426 14.033621-11.603269 25.974581-25.713638 26.131147-14.242376 0.159636-25.844621-11.30651-25.957185-25.65224-0.116657-14.520715 11.002588-25.810852 25.501814-25.904996C629.645932 652.518616 641.236921 663.776008 641.381208 678.031687L641.381208 678.031687zM433.369663 678.65488c-0.187265 14.328333-11.883655 25.780153-26.066679 25.512047-14.080693-0.260943-25.824155-12.32777-25.576515-26.275433 0.251733-14.231119 11.936867-25.453718 26.327622-25.300222C422.521594 652.744767 433.556928 664.105512 433.369663 678.65488L433.369663 678.65488zM892.258025 385.416256c-0.004093-36.07359 0.095167-72.149227-0.028653-108.219747-0.11154-31.752168-21.937638-54.680367-51.753711-54.658877-29.79049 0.017396-51.8059 23.100114-51.836599 54.654784-0.067538 73.140811-0.149403 146.276505 0.061398 219.415268 0.075725 26.923186 19.805068 48.538483 45.833885 51.248198 27.095102 2.819209 50.834782-13.987572 56.574506-40.425711 1.105171-5.102205 1.090844-10.510378 1.105171-15.782451 0.089028-35.413558 0.045025-70.821999 0.040932-106.234533L892.258025 385.416256zM234.306932 385.412163c0-37.7293 0.35918-75.465762-0.132006-113.184829-0.302899-23.12672-16.584724-42.608423-38.748513-48.26526-21.668509-5.526877-45.432749 3.454682-56.523341 23.153326-4.52199 8.035-7.7935 17.987676-7.869225 27.101241-0.624217 74.130348-0.546446 148.266835-0.252757 222.399229 0.116657 29.218462 23.174815 51.633984 51.857065 51.633984 28.801976-0.004093 51.323922-22.078855 51.64831-51.639101 0.414439-37.065174 0.102331-74.132394 0.102331-111.199615-0.028653 0-0.055259 0-0.084934 0L234.306932 385.411139zM234.306932 385.412163" horiz-adv-x="1024" />
<glyph glyph-name="android" unicode="&#58909;"
<glyph glyph-name="android1" unicode="&#58902;" d="M391.428571 620q9.142857 0 15.714286 6.571429T413.714286 642.285714t-6.571429 15.714286T391.428571 664.571429t-15.428571-6.571429-6.285714-15.714286 6.285714-15.714285 15.428571-6.571429z m241.142858 0q9.142857 0 15.428571 6.571429t6.285714 15.714285-6.285714 15.714286-15.428571 6.571429-15.714286-6.571429T610.285714 642.285714t6.571429-15.714285T632.571429 620zM168.571429 514.857143q24 0 41.142857-17.142857t17.142857-41.142857v-245.714286q0-24.571429-16.857143-41.714286t-41.428571-17.142857-41.714286 17.142857-17.142857 41.714286V456.571429q0 24 17.142857 41.142857t41.714286 17.142857z m605.714285-10.857143v-380.571429q0-26.285714-18.285714-44.571428t-44-18.285714h-42.857143v-129.714286q0-24.571429-17.142857-41.714286t-41.714286-17.142857-41.714285 17.142857-17.142858 41.714286v129.714286H472.571429v-129.714286q0-24.571429-17.142858-41.714286t-41.714285-17.142857q-24 0-41.142857 17.142857t-17.142858 41.714286l-0.571428 129.714286h-42.285714q-26.285714 0-44.571429 18.285714t-18.285714 44.571428V504h524.571428zM641.714286 735.428571q61.142857-31.428571 97.714285-87.714285t36.571429-123.142857H247.428571q0 66.857143 36.571429 123.142857T382.285714 735.428571l-40.571428 74.857143q-4 7.428571 2.857143 11.428572 7.428571 3.428571 11.428571-3.428572l41.142857-75.428571q54.285714 24 114.857143 24t114.857143-24l41.142857 75.428571q4 6.857143 11.428571 3.428572 6.857143-4 2.857143-11.428572z m272.571428-278.857142v-245.714286q0-24.571429-17.142857-41.714286t-41.714286-17.142857q-24 0-41.142857 17.142857t-17.142857 41.714286V456.571429q0 24.571429 17.142857 41.428571t41.142857 16.857143q24.571429 0 41.714286-16.857143t17.142857-41.428571z" horiz-adv-x="1024" /> d="M269.401218 547.905l484.587674 0 0-11.106965c0-120.589472 0.023536-241.183038-0.011256-361.76944-0.011256-40.771589-21.756513-62.327534-62.705134-62.342884-10.184967 0-20.37198 0-29.858028 0 0-43.198871 0.467651-85.178985-0.171915-127.141702-0.397043-26.024723-22.889313-47.623647-48.671513-48.568159-27.686573-1.013073-52.970422 18.175965-53.951773 44.760436-1.579985 42.982954-0.425695 86.064145-0.425695 130.026402l-92.891643 0c0-17.075911 0.033769-34.169217-0.005117-51.256384-0.055259-25.179472 0.483001-50.374294-0.428765-75.523067-0.896416-24.611537-20.249183-44.734854-44.115754-47.749514-25.325805-3.202948-49.012274 11.464099-56.531528 35.426861-1.660826 5.300726-2.638083 11.033287-2.675946 16.571421-0.234337 35.778878-0.174985 71.555709-0.064468 107.33561 0.013303 4.910846 0.836041 9.815553 1.417279 16.121166-12.051477 0-23.86657-0.073678-35.68678 0.011256-34.978652 0.254803-57.743122 22.928199-57.767682 58.021461-0.100284 122.571616-0.039909 245.152443-0.042979 367.729176L269.400195 547.905 269.401218 547.905zM754.197646 583.671599 268.922311 583.671599c4.508687 83.888596 52.172243 136.038326 123.015731 173.068707-7.217379 10.940167-14.230096 21.587668-21.263279 32.217772-5.119601 7.730055-10.30674 15.407921-15.398712 23.150256-3.591805 5.460362-9.344832 11.614525-1.36509 17.062608 8.616238 5.885034 12.135388-2.347464 15.941064-7.959276 9.094122-13.428847 18.064424-26.946722 27.064402-40.440038 11.086499-16.617469 11.078313-16.613376 30.132274-11.05887 60.601216 17.662265 120.804367 16.659425 180.590008-3.89061 2.139733-0.738827 4.331655-1.331321 7.135514-2.183735 12.395308 18.558681 24.680099 36.96182 36.96489 55.358819 1.471514 2.206248 2.910283 4.427846 4.428869 6.598278 3.459798 4.948709 7.856945 7.618515 13.384845 3.53757 5.008061-3.693112 4.154623-8.404414 0.994654-13.125949-10.67513-15.95232-21.285792-31.954783-31.911804-47.940872-2.371-3.571339-4.705162-7.167237-7.42204-11.304464 70.458725-36.700877 118.544907-88.950891 122.990149-173.090197L754.197646 583.671599zM641.381208 678.031687c0.150426 14.033621-11.603269 25.974581-25.713638 26.131147-14.242376 0.159636-25.844621-11.30651-25.957185-25.65224-0.116657-14.520715 11.002588-25.810852 25.501814-25.904996C629.645932 652.518616 641.236921 663.776008 641.381208 678.031687L641.381208 678.031687zM433.369663 678.65488c-0.187265 14.328333-11.883655 25.780153-26.066679 25.512047-14.080693-0.260943-25.824155-12.32777-25.576515-26.275433 0.251733-14.231119 11.936867-25.453718 26.327622-25.300222C422.521594 652.744767 433.556928 664.105512 433.369663 678.65488L433.369663 678.65488zM892.258025 385.416256c-0.004093-36.07359 0.095167-72.149227-0.028653-108.219747-0.11154-31.752168-21.937638-54.680367-51.753711-54.658877-29.79049 0.017396-51.8059 23.100114-51.836599 54.654784-0.067538 73.140811-0.149403 146.276505 0.061398 219.415268 0.075725 26.923186 19.805068 48.538483 45.833885 51.248198 27.095102 2.819209 50.834782-13.987572 56.574506-40.425711 1.105171-5.102205 1.090844-10.510378 1.105171-15.782451 0.089028-35.413558 0.045025-70.821999 0.040932-106.234533L892.258025 385.416256zM234.306932 385.412163c0-37.7293 0.35918-75.465762-0.132006-113.184829-0.302899-23.12672-16.584724-42.608423-38.748513-48.26526-21.668509-5.526877-45.432749 3.454682-56.523341 23.153326-4.52199 8.035-7.7935 17.987676-7.869225 27.101241-0.624217 74.130348-0.546446 148.266835-0.252757 222.399229 0.116657 29.218462 23.174815 51.633984 51.857065 51.633984 28.801976-0.004093 51.323922-22.078855 51.64831-51.639101 0.414439-37.065174 0.102331-74.132394 0.102331-111.199615-0.028653 0-0.055259 0-0.084934 0L234.306932 385.411139zM234.306932 385.412163"
horiz-adv-x="1024"/>
<glyph glyph-name="android2" unicode="&#58922;" d="M256 128c0-25.6 17.066667-42.666667 42.666667-42.666667h42.666666v-149.333333c0-34.133333 29.866667-64 64-64s64 29.866667 64 64V85.333333h85.333334v-149.333333c0-34.133333 29.866667-64 64-64s64 29.866667 64 64V85.333333h42.666666c25.6 0 42.666667 17.066667 42.666667 42.666667V554.666667H256v-426.666667zM149.333333 554.666667C115.2 554.666667 85.333333 524.8 85.333333 490.666667v-298.666667c0-34.133333 29.866667-64 64-64S213.333333 157.866667 213.333333 192v298.666667C213.333333 524.8 183.466667 554.666667 149.333333 554.666667z m725.333334 0c-34.133333 0-64-29.866667-64-64v-298.666667c0-34.133333 29.866667-64 64-64s64 29.866667 64 64v298.666667c0 34.133333-29.866667 64-64 64z m-213.333334 247.466666L716.8 857.6c8.533333 8.533333 8.533333 21.333333 0 29.866667-8.533333 8.533333-21.333333 8.533333-29.866667 0l-64-64C593.066667 844.8 554.666667 853.333333 512 853.333333s-81.066667-8.533333-115.2-25.6L337.066667 891.733333c-8.533333 4.266667-25.6 4.266667-34.133334 0-4.266667-8.533333-4.266667-25.6 0-34.133333l55.466667-55.466667C298.666667 755.2 256 682.666667 256 597.333333h512c0 85.333333-42.666667 162.133333-106.666667 204.8zM426.666667 682.666667H384V725.333333h42.666667v-42.666666z m213.333333 0h-42.666667V725.333333h42.666667v-42.666666z" horiz-adv-x="1024" />
<glyph glyph-name="android1" unicode="&#58902;"
<glyph glyph-name="ios" unicode="&#58892;" d="M521.996 659.402c13.596 0.316 26.587 2.344 38.944 5.874l1.477-1.023c25.485 8.525 47.394 21.707 65.751 38.675l-25.33-22.506c28.822 15.94 52.712 37.447 70.922 63.249l-36.429-39.535c28.139 24 50.335 54.116 64.645 88.349l-34.464-58.168c22.406 27.513 39.057 60.636 47.571 96.894l-25.474-60.785c14.141 25.287 23.872 54.935 27.305 86.475l-11.137-47.132c6.314 18.235 10.235 39.273 10.832 61.141-0.92-14.951-0.492-7.646-0.492-0.24 0 7.406-0.428 14.711-1.261 21.894-114.436-13.762-202.632-110.063-202.632-226.963 0-1.99 0.026-3.974 0.076-5.952zM813.027 279.983c-9.291 23.371-14.678 50.452-14.678 78.791 0 2.616 0.046 5.222 0.137 7.816 0.877 22.699 5.309 44.464 12.755 64.776 8.765 26.429 27.096 55.391 50.856 78.871 1.828 9.48 42.301 41.542 89.752 59.323-84.33 32.038-144.712 69.372-214.043 76.759 0.404 0.843-15.633 2.529-32.046 2.637l-53.878-0.333-15.629-4.312-11.857-3.773-15.091-5.389-10.779-8.623-17.785-7.006-14.552-5.928-10.24-3.773-12.396-3.773h-7.006c-2.507-0.304-5.41-0.478-8.354-0.478s-5.847 0.174-8.699 0.511c-2.079-0.302-4.891-0.455-7.739-0.455-2.848 0-5.659 0.153-8.427 0.452l-5.585-0.030-11.857 3.234-8.623 3.234-12.396 3.234-20.48 8.084-8.084 2.695-14.552 5.389-9.701 3.234-13.474 4.312h-10.24l-14.013 2.695h-10.779l-12.935 3.773c-35.215-0.199-68.68-7.463-99.123-20.442-100.455-45.409-170.936-147.27-170.936-265.593 0-6.498 0.213-12.947 0.631-19.339l-0.046-53.025c0-4.312 0-19.402 3.773-29.103s0-10.779 3.234-16.168 3.234-17.246 5.389-25.869 3.234-11.318 4.851-16.707 4.312-16.168 7.006-24.253 4.312-11.857 6.467-17.785l8.084-22.636 7.545-17.246c3.234-7.006 5.928-14.552 9.162-21.558l8.084-16.168 10.779-21.019 9.162-15.629 11.318-19.402 21.558-32.337 10.24-13.474 12.396-15.629 10.779-12.396 12.396-13.474 11.318-10.779 12.396-11.318 11.318-8.623 12.396-9.162 11.318-6.467 11.857-6.467 10.779-3.773 11.857-3.773 14.013-4.312h12.396c17.291 0.666 33.606 3.944 48.855 9.45 35.686 19.327 84.485 32.203 136.187 33.26-11.243-0.381-6.541-0.215-1.8-0.215 4.741 0 9.443-0.166 14.101-0.492l7.996 0.035 14.552-3.234 9.162-2.695 11.318-3.773 9.701-3.773 14.013-5.928 12.396-5.389 8.084-2.695 10.779-3.773h45.811c39.742 3.516 74.688 21.631 99.914 48.874 71.609 68.094 126.848 162.124 151.674 267.874-5.067-48.749 17.64 18.78 26.966 90.511-106.339-115.262-156.75-58.206-177.238 11.642z" horiz-adv-x="1024" /> d="M391.428571 620q9.142857 0 15.714286 6.571429T413.714286 642.285714t-6.571429 15.714286T391.428571 664.571429t-15.428571-6.571429-6.285714-15.714286 6.285714-15.714285 15.428571-6.571429z m241.142858 0q9.142857 0 15.428571 6.571429t6.285714 15.714285-6.285714 15.714286-15.428571 6.571429-15.714286-6.571429T610.285714 642.285714t6.571429-15.714285T632.571429 620zM168.571429 514.857143q24 0 41.142857-17.142857t17.142857-41.142857v-245.714286q0-24.571429-16.857143-41.714286t-41.428571-17.142857-41.714286 17.142857-17.142857 41.714286V456.571429q0 24 17.142857 41.142857t41.714286 17.142857z m605.714285-10.857143v-380.571429q0-26.285714-18.285714-44.571428t-44-18.285714h-42.857143v-129.714286q0-24.571429-17.142857-41.714286t-41.714286-17.142857-41.714285 17.142857-17.142858 41.714286v129.714286H472.571429v-129.714286q0-24.571429-17.142858-41.714286t-41.714285-17.142857q-24 0-41.142857 17.142857t-17.142858 41.714286l-0.571428 129.714286h-42.285714q-26.285714 0-44.571429 18.285714t-18.285714 44.571428V504h524.571428zM641.714286 735.428571q61.142857-31.428571 97.714285-87.714285t36.571429-123.142857H247.428571q0 66.857143 36.571429 123.142857T382.285714 735.428571l-40.571428 74.857143q-4 7.428571 2.857143 11.428572 7.428571 3.428571 11.428571-3.428572l41.142857-75.428571q54.285714 24 114.857143 24t114.857143-24l41.142857 75.428571q4 6.857143 11.428571 3.428572 6.857143-4 2.857143-11.428572z m272.571428-278.857142v-245.714286q0-24.571429-17.142857-41.714286t-41.714286-17.142857q-24 0-41.142857 17.142857t-17.142857 41.714286V456.571429q0 24.571429 17.142857 41.428571t41.142857 16.857143q24.571429 0 41.714286-16.857143t17.142857-41.428571z"
horiz-adv-x="1024"/>
<glyph glyph-name="IOS" unicode="&#59020;" d="M737.007 358.636c-1.092 104.007 84.833 153.888 88.595 156.316-48.181 70.512-123.305 80.221-150.126 81.435-63.958 6.432-124.761-37.622-157.165-37.622-32.404 0-82.405 36.652-135.441 35.681-69.663-1.092-133.863-40.535-169.787-102.915-72.453-125.732-18.569-311.903 52.065-413.727 34.467-49.881 75.609-105.828 129.616-103.887 51.943 2.063 71.604 33.618 134.47 33.618s80.464-33.618 135.563-32.646c55.948 1.092 91.387 50.851 125.611 100.852 39.564 57.89 55.948 113.959 56.798 116.63-1.214 0.729-109.105 41.991-110.197 166.267zM633.605 663.742c28.641 34.71 47.938 83.012 42.72 131.072-41.264-1.699-91.265-27.428-120.878-62.138-26.457-30.826-49.881-79.978-43.569-127.067 45.997-3.641 93.085 23.423 121.727 58.132z" horiz-adv-x="1024" />
<glyph glyph-name="android2" unicode="&#58922;"
<glyph glyph-name="ios1" unicode="&#58881;" d="M615.913 712.238c31.803 40.968 55.898 98.81 47.218 157.832-52.08-3.61-112.838-36.802-148.25-79.991-32.36-39.164-58.954-97.353-48.607-153.876 56.94-1.805 115.545 32.15 149.639 76.035zM896.859 156.8c-22.776-50.481-33.677-73.117-62.98-117.835-40.97-62.496-98.603-140.266-170.055-140.822-63.467-0.694-79.854 41.386-165.957 40.9s-104.156-41.733-167.693-41.107c-71.451 0.695-126.03 70.827-166.929 133.32-114.364 174.568-126.376 379.48-55.897 488.498 50.203 77.354 129.294 122.558 203.661 122.558 75.688 0 123.253-41.593 185.956-41.593 60.758 0 97.768 41.663 185.26 41.663 66.245 0 136.447-36.109 186.441-98.603-163.805-89.922-137.278-324.275 28.192-387.047v0.068h0.001z" horiz-adv-x="1024" /> d="M256 128c0-25.6 17.066667-42.666667 42.666667-42.666667h42.666666v-149.333333c0-34.133333 29.866667-64 64-64s64 29.866667 64 64V85.333333h85.333334v-149.333333c0-34.133333 29.866667-64 64-64s64 29.866667 64 64V85.333333h42.666666c25.6 0 42.666667 17.066667 42.666667 42.666667V554.666667H256v-426.666667zM149.333333 554.666667C115.2 554.666667 85.333333 524.8 85.333333 490.666667v-298.666667c0-34.133333 29.866667-64 64-64S213.333333 157.866667 213.333333 192v298.666667C213.333333 524.8 183.466667 554.666667 149.333333 554.666667z m725.333334 0c-34.133333 0-64-29.866667-64-64v-298.666667c0-34.133333 29.866667-64 64-64s64 29.866667 64 64v298.666667c0 34.133333-29.866667 64-64 64z m-213.333334 247.466666L716.8 857.6c8.533333 8.533333 8.533333 21.333333 0 29.866667-8.533333 8.533333-21.333333 8.533333-29.866667 0l-64-64C593.066667 844.8 554.666667 853.333333 512 853.333333s-81.066667-8.533333-115.2-25.6L337.066667 891.733333c-8.533333 4.266667-25.6 4.266667-34.133334 0-4.266667-8.533333-4.266667-25.6 0-34.133333l55.466667-55.466667C298.666667 755.2 256 682.666667 256 597.333333h512c0 85.333333-42.666667 162.133333-106.666667 204.8zM426.666667 682.666667H384V725.333333h42.666667v-42.666666z m213.333333 0h-42.666667V725.333333h42.666667v-42.666666z"
horiz-adv-x="1024"/>
<glyph glyph-name="ios2" unicode="&#58955;" d="M812.2 345.2c-7.2 96.1 56.4 156.8 116.4 199-56.4 50.6-105.4 99.5-209.1 104.5-83.6 3.4-121.8-43.8-200-45.5-72.7-1.7-67.3 52.3-218.2 37.1C170.5 626.8 55.9 505.4 65 335.1c9.1-183.8 147.3-438.3 276.3-438.3 90.9 1.7 112.7 42.1 187.3 42.1 92.7 0 114.5-50.6 187.3-40.5C841.4-84.7 959.5 99 959.5 158c-69.1 33.8-138.2 91.1-147.3 187.2z m-105.4 526C534.1 849.3 485 702.6 494.1 635.2c132.7-6.7 232.7 123.1 212.7 236z" horiz-adv-x="1024" />
<glyph glyph-name="ios" unicode="&#58892;"
<glyph glyph-name="Android" unicode="&#59092;" d="M512 192.7c-41.8 0-75.6 34-75.6 75.6V499.7c0 41.6 33.8 75.6 75.6 75.6 20.2 0 39.1-7.8 53.5-22.1 14.3-14.3 22.1-33.3 22.1-53.5v-231.5c0-20.2-7.8-39.1-22.1-53.5-14.4-14-33.3-22-53.5-22M243.1 400c-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.4 30.6 0 55.2 24.8 55.2 55.4V344.9c0 30.3-24.8 55.1-55.2 55.1m593-11.4H297.3V409c0 83.4 45.5 160.9 119.9 206.9l-28.9 52.5c-3.6 6.1-4.4 14.1-2.4 21.2 2.2 7.1 7.1 13.4 13.6 16.8 4.1 2.4 8.8 3.6 13.4 3.6 10.2 0 19.7-5.6 24.6-14.6l30.4-55.2c31.4 11.4 64.4 17.3 98.7 17.3 34.8 0 68.1-5.8 99.4-17.5l30.1 55.4c4.9 9 14.3 14.6 24.6 14.6 4.6 0 9.2-1.2 13.4-3.4 6.8-3.6 11.7-9.7 13.6-17 2.2-7.3 1.2-14.8-2.4-21.4l-28.9-52.8c74.4-46 119.9-123.5 119.9-206.9v-19.9h-0.2zM633.8 442.7l38.7 70.5c1.9 3.6 0.7 8.5-2.9 10.5-3.9 1.9-8.5 0.7-10.5-3.2l-38.9-71.2c-32.8 14.6-69.5 22.9-108.2 22.6-38.7 0-75.4-8-107.9-22.6l-38.9 71c-1.9 3.6-6.8 5.1-10.5 3.2s-5.1-6.8-3.2-10.5l38.7-70.5C314.3 403.4 263 329 263 243.4h498c-0.3 85.8-51.3 160.2-127.2 199.3M398.5 333.8c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9s-9.3-20.9-20.9-20.9m226.8 0c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9s-9.5-20.9-20.9-20.9M419.3 66c-41.6 0-75.6 33.8-75.6 75.6V243.7h-19.9c-21.2 0-41.1 8.3-56.2 23.1-15.1 15.1-23.3 34.8-23.1 56.2V702h535.1v-379c0-43.8-35.5-79.3-79.3-79.3h-19.9v-102.1c0-41.6-33.8-75.6-75.6-75.6-20.2 0-39.1 7.8-53.5 22.1-14.3 14.3-22.1 33.3-22.1 53.5V243.7h-34v-102.1c-0.3-41.6-34.4-75.6-75.9-75.6M189 307.7c0-32.6 26.3-59.1 59.1-59.1h40.1V126c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.4V248.8h74.6v-122.5c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V248.8H624c32.6 0 59.1 26.5 59.1 59.1V666.8H188.8l0.2-359.1z m570.6 6.8c-41.6 0-75.6 33.8-75.6 75.6V621.5c0 41.8 33.8 75.6 75.6 75.6s75.6-33.8 75.6-75.6V390c0-41.7-33.8-75.5-75.6-75.5M512 554.9c-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V499.7c0 30.4-24.6 55.2-55.2 55.2M188.2 542.2c-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V487c-0.1 30.4-24.9 55.2-55.2 55.2m445.6 207.9l38.7 70.5c1.9 3.6 0.7 8.3-2.9 10.5-3.6 1.9-8.5 0.7-10.5-3.2l-38.9-71.2c-32.8 14.6-69.5 22.9-108.4 22.9-38.7 0-75.4-8-107.9-22.6L365 828c-1.9 3.6-6.8 5.1-10.5 3.2-3.6-1.9-5.1-6.8-3.2-10.5l38.7-70.5c-75.9-39.1-127.2-113.5-127.2-199.1h497.9c0 85.4-51 159.8-126.9 199m-235.3-109c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9 0-11.4-9.3-20.9-20.9-20.9m226.8 0c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9 0-11.4-9.5-20.9-20.9-20.9M264.7 531.7v-358.9c0-32.6 26.3-59.1 59.1-59.1h40.1v-122.5c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.4V114H549v-122.5c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V114h40.4c32.6 0 59.1 26.3 59.1 59.1V532l-494.2-0.3zM891 487c0 30.6-24.8 55.2-55.2 55.2-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V487z" horiz-adv-x="1024" /> d="M521.996 659.402c13.596 0.316 26.587 2.344 38.944 5.874l1.477-1.023c25.485 8.525 47.394 21.707 65.751 38.675l-25.33-22.506c28.822 15.94 52.712 37.447 70.922 63.249l-36.429-39.535c28.139 24 50.335 54.116 64.645 88.349l-34.464-58.168c22.406 27.513 39.057 60.636 47.571 96.894l-25.474-60.785c14.141 25.287 23.872 54.935 27.305 86.475l-11.137-47.132c6.314 18.235 10.235 39.273 10.832 61.141-0.92-14.951-0.492-7.646-0.492-0.24 0 7.406-0.428 14.711-1.261 21.894-114.436-13.762-202.632-110.063-202.632-226.963 0-1.99 0.026-3.974 0.076-5.952zM813.027 279.983c-9.291 23.371-14.678 50.452-14.678 78.791 0 2.616 0.046 5.222 0.137 7.816 0.877 22.699 5.309 44.464 12.755 64.776 8.765 26.429 27.096 55.391 50.856 78.871 1.828 9.48 42.301 41.542 89.752 59.323-84.33 32.038-144.712 69.372-214.043 76.759 0.404 0.843-15.633 2.529-32.046 2.637l-53.878-0.333-15.629-4.312-11.857-3.773-15.091-5.389-10.779-8.623-17.785-7.006-14.552-5.928-10.24-3.773-12.396-3.773h-7.006c-2.507-0.304-5.41-0.478-8.354-0.478s-5.847 0.174-8.699 0.511c-2.079-0.302-4.891-0.455-7.739-0.455-2.848 0-5.659 0.153-8.427 0.452l-5.585-0.030-11.857 3.234-8.623 3.234-12.396 3.234-20.48 8.084-8.084 2.695-14.552 5.389-9.701 3.234-13.474 4.312h-10.24l-14.013 2.695h-10.779l-12.935 3.773c-35.215-0.199-68.68-7.463-99.123-20.442-100.455-45.409-170.936-147.27-170.936-265.593 0-6.498 0.213-12.947 0.631-19.339l-0.046-53.025c0-4.312 0-19.402 3.773-29.103s0-10.779 3.234-16.168 3.234-17.246 5.389-25.869 3.234-11.318 4.851-16.707 4.312-16.168 7.006-24.253 4.312-11.857 6.467-17.785l8.084-22.636 7.545-17.246c3.234-7.006 5.928-14.552 9.162-21.558l8.084-16.168 10.779-21.019 9.162-15.629 11.318-19.402 21.558-32.337 10.24-13.474 12.396-15.629 10.779-12.396 12.396-13.474 11.318-10.779 12.396-11.318 11.318-8.623 12.396-9.162 11.318-6.467 11.857-6.467 10.779-3.773 11.857-3.773 14.013-4.312h12.396c17.291 0.666 33.606 3.944 48.855 9.45 35.686 19.327 84.485 32.203 136.187 33.26-11.243-0.381-6.541-0.215-1.8-0.215 4.741 0 9.443-0.166 14.101-0.492l7.996 0.035 14.552-3.234 9.162-2.695 11.318-3.773 9.701-3.773 14.013-5.928 12.396-5.389 8.084-2.695 10.779-3.773h45.811c39.742 3.516 74.688 21.631 99.914 48.874 71.609 68.094 126.848 162.124 151.674 267.874-5.067-48.749 17.64 18.78 26.966 90.511-106.339-115.262-156.75-58.206-177.238 11.642z"
horiz-adv-x="1024"/>
<glyph glyph-name="android3" unicode="&#58917;" d="M633.472 667.434667h-40.533333v40.533333h40.533333m-202.496-40.533333h-40.490667v40.533333h40.533334m223.914666 74.453333l53.034667 53.077334a20.778667 20.778667 0 0 1 0 28.757333 20.778667 20.778667 0 0 1-28.757333 0L619.306667 804.266667a244.650667 244.650667 0 0 1-107.349334 25.130666c-38.826667 0-75.306667-9.344-107.690666-25.514666L343.893333 864.256a20.309333 20.309333 0 0 1-28.373333 0 20.053333 20.053333 0 0 1 0-28.757333L368.64 782.421333C308.266667 737.877333 269.013333 667.434667 269.013333 586.453333h485.973334c0 80.981333-40.533333 151.850667-100.053334 195.968m201.301334-236.501333a60.757333 60.757333 0 0 1-60.757334-60.714667v-283.477333a60.757333 60.757333 0 0 1 60.757334-60.757333 60.757333 60.757333 0 0 1 60.714666 60.757333V485.205333a60.757333 60.757333 0 0 1-60.714666 60.714667m-688.469334 0a60.757333 60.757333 0 0 1-60.757333-60.714667v-283.477333a60.757333 60.757333 0 0 1 60.757333-60.757333 60.757333 60.757333 0 0 1 60.714667 60.757333V485.205333a60.757333 60.757333 0 0 1-60.714667 60.714667m101.205334-404.949333a40.533333 40.533333 0 0 1 40.533333-40.533334h40.490667v-141.696a60.757333 60.757333 0 0 1 60.714666-60.757333 60.757333 60.757333 0 0 1 60.757334 60.757333v141.738667h80.981333v-141.738667a60.757333 60.757333 0 0 1 60.757333-60.757333 60.757333 60.757333 0 0 1 60.757334 60.757333v141.738667h40.490666a40.533333 40.533333 0 0 1 40.533334 40.490667V545.92H268.970667z" horiz-adv-x="1024" />
<glyph glyph-name="IOS" unicode="&#59020;"
d="M737.007 358.636c-1.092 104.007 84.833 153.888 88.595 156.316-48.181 70.512-123.305 80.221-150.126 81.435-63.958 6.432-124.761-37.622-157.165-37.622-32.404 0-82.405 36.652-135.441 35.681-69.663-1.092-133.863-40.535-169.787-102.915-72.453-125.732-18.569-311.903 52.065-413.727 34.467-49.881 75.609-105.828 129.616-103.887 51.943 2.063 71.604 33.618 134.47 33.618s80.464-33.618 135.563-32.646c55.948 1.092 91.387 50.851 125.611 100.852 39.564 57.89 55.948 113.959 56.798 116.63-1.214 0.729-109.105 41.991-110.197 166.267zM633.605 663.742c28.641 34.71 47.938 83.012 42.72 131.072-41.264-1.699-91.265-27.428-120.878-62.138-26.457-30.826-49.881-79.978-43.569-127.067 45.997-3.641 93.085 23.423 121.727 58.132z"
horiz-adv-x="1024"/>
</font> <glyph glyph-name="ios1" unicode="&#58881;"
</defs></svg> d="M615.913 712.238c31.803 40.968 55.898 98.81 47.218 157.832-52.08-3.61-112.838-36.802-148.25-79.991-32.36-39.164-58.954-97.353-48.607-153.876 56.94-1.805 115.545 32.15 149.639 76.035zM896.859 156.8c-22.776-50.481-33.677-73.117-62.98-117.835-40.97-62.496-98.603-140.266-170.055-140.822-63.467-0.694-79.854 41.386-165.957 40.9s-104.156-41.733-167.693-41.107c-71.451 0.695-126.03 70.827-166.929 133.32-114.364 174.568-126.376 379.48-55.897 488.498 50.203 77.354 129.294 122.558 203.661 122.558 75.688 0 123.253-41.593 185.956-41.593 60.758 0 97.768 41.663 185.26 41.663 66.245 0 136.447-36.109 186.441-98.603-163.805-89.922-137.278-324.275 28.192-387.047v0.068h0.001z"
horiz-adv-x="1024"/>
<glyph glyph-name="ios2" unicode="&#58955;"
d="M812.2 345.2c-7.2 96.1 56.4 156.8 116.4 199-56.4 50.6-105.4 99.5-209.1 104.5-83.6 3.4-121.8-43.8-200-45.5-72.7-1.7-67.3 52.3-218.2 37.1C170.5 626.8 55.9 505.4 65 335.1c9.1-183.8 147.3-438.3 276.3-438.3 90.9 1.7 112.7 42.1 187.3 42.1 92.7 0 114.5-50.6 187.3-40.5C841.4-84.7 959.5 99 959.5 158c-69.1 33.8-138.2 91.1-147.3 187.2z m-105.4 526C534.1 849.3 485 702.6 494.1 635.2c132.7-6.7 232.7 123.1 212.7 236z"
horiz-adv-x="1024"/>
<glyph glyph-name="Android" unicode="&#59092;"
d="M512 192.7c-41.8 0-75.6 34-75.6 75.6V499.7c0 41.6 33.8 75.6 75.6 75.6 20.2 0 39.1-7.8 53.5-22.1 14.3-14.3 22.1-33.3 22.1-53.5v-231.5c0-20.2-7.8-39.1-22.1-53.5-14.4-14-33.3-22-53.5-22M243.1 400c-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.4 30.6 0 55.2 24.8 55.2 55.4V344.9c0 30.3-24.8 55.1-55.2 55.1m593-11.4H297.3V409c0 83.4 45.5 160.9 119.9 206.9l-28.9 52.5c-3.6 6.1-4.4 14.1-2.4 21.2 2.2 7.1 7.1 13.4 13.6 16.8 4.1 2.4 8.8 3.6 13.4 3.6 10.2 0 19.7-5.6 24.6-14.6l30.4-55.2c31.4 11.4 64.4 17.3 98.7 17.3 34.8 0 68.1-5.8 99.4-17.5l30.1 55.4c4.9 9 14.3 14.6 24.6 14.6 4.6 0 9.2-1.2 13.4-3.4 6.8-3.6 11.7-9.7 13.6-17 2.2-7.3 1.2-14.8-2.4-21.4l-28.9-52.8c74.4-46 119.9-123.5 119.9-206.9v-19.9h-0.2zM633.8 442.7l38.7 70.5c1.9 3.6 0.7 8.5-2.9 10.5-3.9 1.9-8.5 0.7-10.5-3.2l-38.9-71.2c-32.8 14.6-69.5 22.9-108.2 22.6-38.7 0-75.4-8-107.9-22.6l-38.9 71c-1.9 3.6-6.8 5.1-10.5 3.2s-5.1-6.8-3.2-10.5l38.7-70.5C314.3 403.4 263 329 263 243.4h498c-0.3 85.8-51.3 160.2-127.2 199.3M398.5 333.8c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9s-9.3-20.9-20.9-20.9m226.8 0c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9s-9.5-20.9-20.9-20.9M419.3 66c-41.6 0-75.6 33.8-75.6 75.6V243.7h-19.9c-21.2 0-41.1 8.3-56.2 23.1-15.1 15.1-23.3 34.8-23.1 56.2V702h535.1v-379c0-43.8-35.5-79.3-79.3-79.3h-19.9v-102.1c0-41.6-33.8-75.6-75.6-75.6-20.2 0-39.1 7.8-53.5 22.1-14.3 14.3-22.1 33.3-22.1 53.5V243.7h-34v-102.1c-0.3-41.6-34.4-75.6-75.9-75.6M189 307.7c0-32.6 26.3-59.1 59.1-59.1h40.1V126c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.4V248.8h74.6v-122.5c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V248.8H624c32.6 0 59.1 26.5 59.1 59.1V666.8H188.8l0.2-359.1z m570.6 6.8c-41.6 0-75.6 33.8-75.6 75.6V621.5c0 41.8 33.8 75.6 75.6 75.6s75.6-33.8 75.6-75.6V390c0-41.7-33.8-75.5-75.6-75.5M512 554.9c-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V499.7c0 30.4-24.6 55.2-55.2 55.2M188.2 542.2c-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V487c-0.1 30.4-24.9 55.2-55.2 55.2m445.6 207.9l38.7 70.5c1.9 3.6 0.7 8.3-2.9 10.5-3.6 1.9-8.5 0.7-10.5-3.2l-38.9-71.2c-32.8 14.6-69.5 22.9-108.4 22.9-38.7 0-75.4-8-107.9-22.6L365 828c-1.9 3.6-6.8 5.1-10.5 3.2-3.6-1.9-5.1-6.8-3.2-10.5l38.7-70.5c-75.9-39.1-127.2-113.5-127.2-199.1h497.9c0 85.4-51 159.8-126.9 199m-235.3-109c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9 0-11.4-9.3-20.9-20.9-20.9m226.8 0c-11.4 0-20.9 9.2-20.9 20.9 0 11.4 9.2 20.9 20.9 20.9 11.4 0 20.9-9.5 20.9-20.9 0-11.4-9.5-20.9-20.9-20.9M264.7 531.7v-358.9c0-32.6 26.3-59.1 59.1-59.1h40.1v-122.5c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.4V114H549v-122.5c0-30.4 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V114h40.4c32.6 0 59.1 26.3 59.1 59.1V532l-494.2-0.3zM891 487c0 30.6-24.8 55.2-55.2 55.2-30.6 0-55.2-24.8-55.2-55.2v-231.5c0-30.6 24.8-55.2 55.2-55.2 30.6 0 55.2 24.8 55.2 55.2V487z"
horiz-adv-x="1024"/>
<glyph glyph-name="android3" unicode="&#58917;"
d="M633.472 667.434667h-40.533333v40.533333h40.533333m-202.496-40.533333h-40.490667v40.533333h40.533334m223.914666 74.453333l53.034667 53.077334a20.778667 20.778667 0 0 1 0 28.757333 20.778667 20.778667 0 0 1-28.757333 0L619.306667 804.266667a244.650667 244.650667 0 0 1-107.349334 25.130666c-38.826667 0-75.306667-9.344-107.690666-25.514666L343.893333 864.256a20.309333 20.309333 0 0 1-28.373333 0 20.053333 20.053333 0 0 1 0-28.757333L368.64 782.421333C308.266667 737.877333 269.013333 667.434667 269.013333 586.453333h485.973334c0 80.981333-40.533333 151.850667-100.053334 195.968m201.301334-236.501333a60.757333 60.757333 0 0 1-60.757334-60.714667v-283.477333a60.757333 60.757333 0 0 1 60.757334-60.757333 60.757333 60.757333 0 0 1 60.714666 60.757333V485.205333a60.757333 60.757333 0 0 1-60.714666 60.714667m-688.469334 0a60.757333 60.757333 0 0 1-60.757333-60.714667v-283.477333a60.757333 60.757333 0 0 1 60.757333-60.757333 60.757333 60.757333 0 0 1 60.714667 60.757333V485.205333a60.757333 60.757333 0 0 1-60.714667 60.714667m101.205334-404.949333a40.533333 40.533333 0 0 1 40.533333-40.533334h40.490667v-141.696a60.757333 60.757333 0 0 1 60.714666-60.757333 60.757333 60.757333 0 0 1 60.757334 60.757333v141.738667h80.981333v-141.738667a60.757333 60.757333 0 0 1 60.757333-60.757333 60.757333 60.757333 0 0 1 60.757334 60.757333v141.738667h40.490666a40.533333 40.533333 0 0 1 40.533334 40.490667V545.92H268.970667z"
horiz-adv-x="1024"/>
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@ -2,7 +2,7 @@
<el-main> <el-main>
<div class="page-app app-info"> <div class="page-app app-info">
<div class="banner"> <div class="banner">
<div class="middle-wrapper" > <div class="middle-wrapper">
<div @click="defaulttimeline"> <div @click="defaulttimeline">
<img :src="icon_url" class="appicon" style="width:100px; height:100px"> <img :src="icon_url" class="appicon" style="width:100px; height:100px">
</div> </div>
@ -70,7 +70,7 @@
name: "FirAppInfosBase", name: "FirAppInfosBase",
data() { data() {
return { return {
icon_url:"", icon_url: "",
appinfos: {}, appinfos: {},
master_release: {}, master_release: {},
allapp: [], allapp: [],
@ -80,41 +80,45 @@
} }
}, },
methods: { methods: {
setfunactive(item,index){ setfunactive(item, index) {
for (let key in this.$refs) { for (let key in this.$refs) {
if(key === item){ if (key === item) {
this.$refs[key].classList.add('active'); this.$refs[key].classList.add('active');
this.$store.dispatch('doappInfoIndex', [[index, index], [index, index]]); this.$store.dispatch('doappInfoIndex', [[index, index], [index, index]]);
}else { } else {
this.$refs[key].classList.remove('active'); this.$refs[key].classList.remove('active');
} }
} }
}, },
appDownload() { appDownload() {
this.$router.push({name: 'FirDownload', params: { short: this.appinfos.short }}) this.$router.push({name: 'FirDownload', params: {short: this.appinfos.short}})
}, },
defaulttimeline() { defaulttimeline() {
this.setfunactive('timeline',5); this.setfunactive('timeline', 5);
this.$router.push({name: 'FirAppInfostimeline'}); this.$router.push({name: 'FirAppInfostimeline'});
}, },
baseinfo() { baseinfo() {
this.setfunactive('baseinfo',18); this.setfunactive('baseinfo', 18);
this.$router.push({name: 'FirAppInfosbaseinfo'}); this.$router.push({name: 'FirAppInfosbaseinfo'});
}, },
security(){ security() {
this.setfunactive('security',31); this.setfunactive('security', 31);
this.$router.push({name: 'FirAppInfossecurity'}); this.$router.push({name: 'FirAppInfossecurity'});
}, },
combo() { combo() {
this.setfunactive('combo',44); this.setfunactive('combo', 44);
this.$router.push({name: 'FirAppInfoscombo'}); this.$router.push({name: 'FirAppInfoscombo'});
}, },
devices(){ devices() {
this.setfunactive('devices',57); this.setfunactive('devices', 57);
if(this.appinfos.issupersign){ if (this.appinfos.issupersign) {
this.$router.push({"name":'FirSuperSignBase', params: {act: "useddevices"},query:{bundleid:this.appinfos.bundle_id}}) this.$router.push({
}else { "name": 'FirSuperSignBase',
params: {act: "useddevices"},
query: {bundleid: this.appinfos.bundle_id}
})
} else {
this.$router.push({name: 'FirAppInfosdevices'}); this.$router.push({name: 'FirAppInfosdevices'});
} }
}, },
@ -131,15 +135,13 @@
return ftype return ftype
}, },
}, },
computed: { computed: {}, mounted() {
}, mounted() {
getappinfos(data => { getappinfos(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.appinfos = data.data; this.appinfos = data.data;
this.master_release = data.data.master_release; this.master_release = data.data.master_release;
this.$store.dispatch("getUser",data.userinfo); this.$store.dispatch("getUser", data.userinfo);
this.appinfos["icon_url"] = this.master_release.icon_url; this.appinfos["icon_url"] = this.master_release.icon_url;
this.$store.dispatch('doucurrentapp', this.appinfos); this.$store.dispatch('doucurrentapp', this.appinfos);
} else if (data.code === 1003) { } else if (data.code === 1003) {
@ -151,12 +153,12 @@
}, { }, {
"app_id": this.$route.params.id "app_id": this.$route.params.id
}); });
if(this.$store.state.currentapp.master_release){ if (this.$store.state.currentapp.master_release) {
this.icon_url = this.$store.state.currentapp.master_release.icon_url this.icon_url = this.$store.state.currentapp.master_release.icon_url
} }
},watch:{ }, watch: {
'$store.state.currentapp.master_release.icon_url':function () { '$store.state.currentapp.master_release.icon_url': function () {
this.icon_url = this.$store.state.currentapp.master_release.icon_url this.icon_url = this.$store.state.currentapp.master_release.icon_url
} }
} }

@ -59,7 +59,7 @@
<script> <script>
import {deleteapp, getappinfos, getapppicurl, uploadimgs, updateapp, getuploadurl} from "../restful" import {deleteapp, getappinfos, getapppicurl, uploadimgs, updateapp, getuploadurl} from "../restful"
import { uploadaliyunoss, uploadlocalstorage, uploadqiniuoss} from "../utils"; import {uploadaliyunoss, uploadlocalstorage, uploadqiniuoss} from "../utils";
export default { export default {
name: "FirAppInfosbaseinfo", name: "FirAppInfosbaseinfo",
@ -67,12 +67,12 @@
return { return {
currentapp: {}, currentapp: {},
imageUrl: "", imageUrl: "",
uploadconf:{}, uploadconf: {},
uploadprocess:0 uploadprocess: 0
} }
}, },
methods: { methods: {
updateimgs(certinfo){ updateimgs(certinfo) {
uploadimgs(data => { uploadimgs(data => {
if (data.code === 1000) { if (data.code === 1000) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
@ -80,38 +80,38 @@
this.$message.success('上传成功'); this.$message.success('上传成功');
this.updateinfo(); this.updateinfo();
}else { } else {
this.$message.error('更新失败'); this.$message.error('更新失败');
} }
},{'methods':'PUT','data':{'certinfo':certinfo}}); }, {'methods': 'PUT', 'data': {'certinfo': certinfo}});
}, },
uploadtostorage(file,certinfo){ uploadtostorage(file, certinfo) {
if(certinfo.storage === 1){ if (certinfo.storage === 1) {
// eslint-disable-next-line no-unused-vars,no-unreachable // eslint-disable-next-line no-unused-vars,no-unreachable
uploadqiniuoss(file,certinfo,this,res=>{ uploadqiniuoss(file, certinfo, this, res => {
this.updateimgs(certinfo); this.updateimgs(certinfo);
},process=>{ }, process => {
this.uploadprocess = process; this.uploadprocess = process;
}) })
}else if(certinfo.storage === 2){ } else if (certinfo.storage === 2) {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
uploadaliyunoss(file,certinfo,this,res=>{ uploadaliyunoss(file, certinfo, this, res => {
this.updateimgs(certinfo); this.updateimgs(certinfo);
},process=>{ }, process => {
this.uploadprocess = process; this.uploadprocess = process;
}); });
}else { } else {
// //
certinfo.upload_url = getuploadurl(); certinfo.upload_url = getuploadurl();
// eslint-disable-next-line no-unused-vars,no-unreachable // eslint-disable-next-line no-unused-vars,no-unreachable
uploadlocalstorage(file,certinfo,this,res=>{ uploadlocalstorage(file, certinfo, this, res => {
this.updateimgs(certinfo); this.updateimgs(certinfo);
},process=>{ }, process => {
this.uploadprocess = process; this.uploadprocess = process;
}) })
} }
@ -146,13 +146,13 @@
}); });
// alert('APP',this.delapp.name) // alert('APP',this.delapp.name)
}, },
updateinfo(){ updateinfo() {
getappinfos(data => { getappinfos(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.appinfos = data.data; this.appinfos = data.data;
this.master_release = data.data.master_release; this.master_release = data.data.master_release;
this.$store.dispatch("getUser",data.userinfo); this.$store.dispatch("getUser", data.userinfo);
this.appinfos["icon_url"] = this.master_release.icon_url; this.appinfos["icon_url"] = this.master_release.icon_url;
this.$store.dispatch('doucurrentapp', this.appinfos); this.$store.dispatch('doucurrentapp', this.appinfos);
@ -170,8 +170,8 @@
updateapp(data => { updateapp(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.$message.success('数据更新成功'); this.$message.success('数据更新成功');
}else { } else {
this.$message.error('操作失败,'+data.msg); this.$message.error('操作失败,' + data.msg);
} }
}, { }, {
"app_id": this.currentapp.app_id, "app_id": this.currentapp.app_id,
@ -184,19 +184,21 @@
}, },
beforeAvatarUpload(file) { beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2; const isLt2M = file.size / 1024 / 1024 < 2;
if(file.type === 'image/jpeg' || file.type === 'image/png'|| file.type === 'image/jpg'){ if (file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg') {
if (isLt2M) { if (isLt2M) {
uploadimgs(data => { uploadimgs(data => {
if (data.code === 1000) { if (data.code === 1000) {
let certinfo=data.data; let certinfo = data.data;
this.uploadtostorage(file,certinfo); this.uploadtostorage(file, certinfo);
} }
},{'methods':'GET','data':{'app_id':this.currentapp.app_id,'upload_key':file.name,'ftype':'app'}}); }, {
} 'methods': 'GET',
else{ 'data': {'app_id': this.currentapp.app_id, 'upload_key': file.name, 'ftype': 'app'}
});
} else {
this.$message.error('上传应用图片大小不能超过 2MB!'); this.$message.error('上传应用图片大小不能超过 2MB!');
} }
}else { } else {
this.$message.error('上传应用图片只能是 JPG/PNG/JPEG 格式!'); this.$message.error('上传应用图片只能是 JPG/PNG/JPEG 格式!');
} }
@ -205,7 +207,7 @@
}, },
mounted() { mounted() {
this.$store.dispatch('doappInfoIndex', [[18, 18], [18, 18]]); this.$store.dispatch('doappInfoIndex', [[18, 18], [18, 18]]);
if(!this.currentapp.app_id){ if (!this.currentapp.app_id) {
this.currentapp = this.$store.state.currentapp; this.currentapp = this.$store.state.currentapp;
} }
this.uploadconf = { this.uploadconf = {
@ -216,12 +218,12 @@
'$store.state.currentapp': function () { '$store.state.currentapp': function () {
this.currentapp = this.$store.state.currentapp; this.currentapp = this.$store.state.currentapp;
} }
},computed:{ }, computed: {
getuppicurl(){ getuppicurl() {
return getapppicurl(this.currentapp.app_id) return getapppicurl(this.currentapp.app_id)
}
} }
} }
}
</script> </script>
<style scoped> <style scoped>

@ -93,7 +93,7 @@
hmaster_release: {}, hmaster_release: {},
comboapplists: [], comboapplists: [],
orgapplists: [], orgapplists: [],
comboapp:{"master_release":""} comboapp: {"master_release": ""}
} }
}, methods: { }, methods: {
searchapps() { searchapps() {
@ -202,11 +202,11 @@
} else { } else {
this.$router.push({name: 'FirLogin'}); this.$router.push({name: 'FirLogin'});
} }
}, {"type": type,"page":1,"size":999,"act":'combo'}); }, {"type": type, "page": 1, "size": 999, "act": 'combo'});
} }
}, filters: { }, filters: {
geticon_url(app){ geticon_url(app) {
return app.icon_url return app.icon_url
}, },
getapptype: function (type) { getapptype: function (type) {
let ftype = ''; let ftype = '';
@ -218,12 +218,12 @@
return ftype return ftype
}, },
}, },
mounted() { mounted() {
this.$store.dispatch('doappInfoIndex', [[44, 44], [44, 44]]); this.$store.dispatch('doappInfoIndex', [[44, 44], [44, 44]]);
// this.getappiconFun(); // this.getappiconFun();
this.setData(); this.setData();
}, },
watch: { watch: {
'$store.state.currentapp': function () { '$store.state.currentapp': function () {
this.setData(); this.setData();

@ -3,23 +3,23 @@
<div style="margin-top: 20px;width: 90%;margin-left: 8%"> <div style="margin-top: 20px;width: 90%;margin-left: 8%">
<h2>UDID列表及用户信息</h2> <h2>UDID列表及用户信息</h2>
<el-table <el-table
:data="udidlists" :data="udidlists"
stripe stripe
style="width: 100%"> style="width: 100%">
<el-table-column width="180" <el-table-column width="180"
prop="model" prop="model"
label="设备型号"> label="设备型号">
</el-table-column> </el-table-column>
<el-table-column width="180" <el-table-column width="180"
prop="version" prop="version"
label="系统版本"> label="系统版本">
</el-table-column> </el-table-column>
<el-table-column width="380" <el-table-column width="380"
prop="udid" prop="udid"
label="UDID"> label="UDID">
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
@ -35,12 +35,10 @@
udidlists: [] udidlists: []
} }
}, },
methods: { methods: {},
},
mounted() { mounted() {
this.$store.dispatch('doappInfoIndex', [[57, 57], [57, 57]]); this.$store.dispatch('doappInfoIndex', [[57, 57], [57, 57]]);
if(!this.currentapp.app_id){ if (!this.currentapp.app_id) {
this.currentapp = this.$store.state.currentapp; this.currentapp = this.$store.state.currentapp;
this.udidlists = this.currentapp.master_release.udid; this.udidlists = this.currentapp.master_release.udid;
} }
@ -50,8 +48,7 @@
this.currentapp = this.$store.state.currentapp; this.currentapp = this.$store.state.currentapp;
this.udidlists = this.currentapp.master_release.udid; this.udidlists = this.currentapp.master_release.udid;
} }
},computed:{ }, computed: {}
}
} }
</script> </script>

@ -20,13 +20,13 @@
</el-form-item> </el-form-item>
<el-form-item label-width="160px" label="是否开启访问密码" > <el-form-item label-width="160px" label="是否开启访问密码">
<el-tooltip placement="top"> <el-tooltip placement="top">
<div slot="content"> <div slot="content">
{{passwordtip.msg}}<br> {{passwordtip.msg}}<br>
<div v-if="passwordtip.val === 'on'"> <div v-if="passwordtip.val === 'on'">
<el-link icon="el-icon-edit" :underline="false" @click="setaccesspassword">修改</el-link> <el-link icon="el-icon-edit" :underline="false" @click="setaccesspassword">修改</el-link>
</div> </div>
</div> </div>
<el-switch <el-switch
@ -54,7 +54,9 @@
inactive-value="off"> inactive-value="off">
</el-switch> </el-switch>
</el-tooltip> </el-tooltip>
<el-button @click="clean_app" v-if="currentapp.issupersign === 0 && currentapp.count !== 0" style="margin-left: 20px" size="small" type="info" plain>清理开发者账户脏数据</el-button> <el-button @click="clean_app" v-if="currentapp.issupersign === 0 && currentapp.count !== 0"
style="margin-left: 20px" size="small" type="info" plain>清理开发者账户脏数据
</el-button>
</el-form-item> </el-form-item>
@ -66,7 +68,7 @@
</template> </template>
<script> <script>
import { updateapp, } from "../restful" import {updateapp,} from "../restful"
import {deepCopy} from "../utils"; import {deepCopy} from "../utils";
export default { export default {
@ -75,31 +77,31 @@
return { return {
currentapp: {}, currentapp: {},
orgcurrentapp: {}, orgcurrentapp: {},
downtip:{'msg':''}, downtip: {'msg': ''},
supersign:{'msg':''}, supersign: {'msg': ''},
passwordtip:{'msg':''}, passwordtip: {'msg': ''},
passwordflag:false, passwordflag: false,
showdownloadflag:false, showdownloadflag: false,
showsupersignflag:false, showsupersignflag: false,
clecount:0 clecount: 0
} }
}, },
methods: { methods: {
clean_app(){ clean_app() {
this.saveappinfo({"clean":true}); this.saveappinfo({"clean": true});
this.currentapp.count = 0; this.currentapp.count = 0;
}, },
saveappinfo(data) { saveappinfo(data) {
updateapp(data => { updateapp(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.$message.success('数据更新成功'); this.$message.success('数据更新成功');
}else { } else {
this.$message.error('操作失败,'+data.msg); this.$message.error('操作失败,' + data.msg);
this.currentapp=deepCopy(this.orgcurrentapp); this.currentapp = deepCopy(this.orgcurrentapp);
this.passwordflag=false; this.passwordflag = false;
this.showdownloadflag=false; this.showdownloadflag = false;
this.showsupersignflag=false; this.showsupersignflag = false;
this.setbuttondefault(this.currentapp); this.setbuttondefault(this.currentapp);
} }
@ -108,57 +110,57 @@
"data": data "data": data
}); });
}, },
setbuttondefaltpass(currentapp){ setbuttondefaltpass(currentapp) {
if(currentapp.password === ''){ if (currentapp.password === '') {
this.passwordtip.val='off'; this.passwordtip.val = 'off';
this.showpasswordevent("off"); this.showpasswordevent("off");
}else { } else {
this.passwordtip.val='on'; this.passwordtip.val = 'on';
this.showpasswordevent("on"); this.showpasswordevent("on");
} }
this.passwordflag=true; this.passwordflag = true;
}, },
setbuttondefaltshow(currentapp){ setbuttondefaltshow(currentapp) {
if(currentapp.isshow === 1){ if (currentapp.isshow === 1) {
this.showdownloadevent("on"); this.showdownloadevent("on");
this.downtip.val='on'; this.downtip.val = 'on';
}else { } else {
this.showdownloadevent("off"); this.showdownloadevent("off");
this.downtip.val='off'; this.downtip.val = 'off';
} }
this.showdownloadflag=true; this.showdownloadflag = true;
}, },
setbuttonsignshow(currentapp){ setbuttonsignshow(currentapp) {
if(currentapp.issupersign === 1){ if (currentapp.issupersign === 1) {
this.supersignevent("on"); this.supersignevent("on");
this.supersign.val='on'; this.supersign.val = 'on';
}else { } else {
this.supersignevent("off"); this.supersignevent("off");
this.supersign.val='off'; this.supersign.val = 'off';
} }
this.showsupersignflag=true; this.showsupersignflag = true;
}, },
setbuttondefault(currentapp){ setbuttondefault(currentapp) {
this.setbuttondefaltpass(currentapp); this.setbuttondefaltpass(currentapp);
this.setbuttondefaltshow(currentapp); this.setbuttondefaltshow(currentapp);
this.setbuttonsignshow(currentapp); this.setbuttonsignshow(currentapp);
}, },
passwordswitch(state){ passwordswitch(state) {
this.passwordflag=false; this.passwordflag = false;
this.showpasswordevent(state); this.showpasswordevent(state);
this.passwordtip.val=state; this.passwordtip.val = state;
this.passwordflag=true; this.passwordflag = true;
}, },
setaccesspassword(){ setaccesspassword() {
this.$prompt('', '请设置访问密码', { this.$prompt('', '请设置访问密码', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
closeOnClickModal:false, closeOnClickModal: false,
inputValue:`${this.currentapp.password}`, inputValue: `${this.currentapp.password}`,
}).then(({ value }) => { }).then(({value}) => {
value = value.replace(/\s+/g,""); value = value.replace(/\s+/g, "");
if(this.currentapp.password === value ) { if (this.currentapp.password === value) {
if(value === ''){ if (value === '') {
this.$message({ this.$message({
type: 'success', type: 'success',
message: '访问密码未变' message: '访问密码未变'
@ -166,103 +168,103 @@
this.passwordflag = false; this.passwordflag = false;
this.setbuttondefaltpass(this.currentapp); this.setbuttondefaltpass(this.currentapp);
return return
}else { } else {
return return
} }
} }
this.saveappinfo({ this.saveappinfo({
"password": value, "password": value,
});
if (value === '') {
this.passwordswitch("off");
this.$message({
type: 'success',
message: '设置成功,取消密码访问'
}); });
if(value === ''){ } else {
this.passwordswitch("off"); this.passwordtip.msg = '访问密码:' + value;
this.$message({ this.$message({
type: 'success', type: 'success',
message: '设置成功,取消密码访问' message: '设置成功,访问密码是: ' + value
}); });
}else { }
this.passwordtip.msg='访问密码:' + value; this.currentapp.password = value;
this.$message({ this.$store.dispatch('doucurrentapp', this.currentapp)
type: 'success',
message: '设置成功,访问密码是: ' + value
});
}
this.currentapp.password=value;
this.$store.dispatch('doucurrentapp', this.currentapp)
}).catch(() => { }).catch(() => {
if(this.currentapp.password === ''){ if (this.currentapp.password === '') {
this.passwordswitch("off") this.passwordswitch("off")
} }
}); });
}, },
showdownloadevent(newval){ showdownloadevent(newval) {
if(newval === "on"){ if (newval === "on") {
if(this.showdownloadflag){ if (this.showdownloadflag) {
this.saveappinfo({ this.saveappinfo({
"isshow": 1, "isshow": 1,
}); });
this.currentapp.isshow=1; this.currentapp.isshow = 1;
} }
this.downtip.msg='下载页对所有人可见'; this.downtip.msg = '下载页对所有人可见';
}else { } else {
if(this.showdownloadflag){ if (this.showdownloadflag) {
this.saveappinfo({ this.saveappinfo({
"isshow": 0, "isshow": 0,
}); });
this.currentapp.isshow=0; this.currentapp.isshow = 0;
} }
this.downtip.msg = '下载页不可见' this.downtip.msg = '下载页不可见'
} }
}, },
supersignevent(newval){ supersignevent(newval) {
if(newval === "on"){ if (newval === "on") {
if(this.showsupersignflag){ if (this.showsupersignflag) {
this.saveappinfo({ this.saveappinfo({
"issupersign": 1, "issupersign": 1,
}); });
this.currentapp.issupersign=1; this.currentapp.issupersign = 1;
} }
this.supersign.msg='已经开启超级签名'; this.supersign.msg = '已经开启超级签名';
}else { } else {
if(this.showsupersignflag){ if (this.showsupersignflag) {
this.saveappinfo({ this.saveappinfo({
"issupersign": 0, "issupersign": 0,
}); });
this.currentapp.issupersign=0; this.currentapp.issupersign = 0;
} }
this.supersign.msg = '关闭' this.supersign.msg = '关闭'
} }
}, },
showpasswordevent(newval){ showpasswordevent(newval) {
if(newval === "on"){ if (newval === "on") {
if(this.passwordflag){ if (this.passwordflag) {
this.setaccesspassword() this.setaccesspassword()
}else { } else {
this.passwordtip.msg='访问密码:' + this.currentapp.password ; this.passwordtip.msg = '访问密码:' + this.currentapp.password;
} }
}else { } else {
if(this.passwordflag){ if (this.passwordflag) {
this.saveappinfo({ this.saveappinfo({
"password": '', "password": '',
}); });
} }
this.currentapp.password=''; this.currentapp.password = '';
this.$store.dispatch('doucurrentapp', this.currentapp); this.$store.dispatch('doucurrentapp', this.currentapp);
this.passwordtip.msg='无访问密码' this.passwordtip.msg = '无访问密码'
} }
}, },
appinit(){ appinit() {
this.currentapp = this.$store.state.currentapp; this.currentapp = this.$store.state.currentapp;
this.passwordflag=false; this.passwordflag = false;
this.showdownloadflag=false; this.showdownloadflag = false;
this.showsupersignflag=false; this.showsupersignflag = false;
this.setbuttondefault(this.currentapp); this.setbuttondefault(this.currentapp);
this.orgcurrentapp=deepCopy(this.currentapp) this.orgcurrentapp = deepCopy(this.currentapp)
} }
}, },
mounted() { mounted() {
this.$store.dispatch('doappInfoIndex', [[31, 31], [31, 31]]); this.$store.dispatch('doappInfoIndex', [[31, 31], [31, 31]]);
if(!this.currentapp.app_id){ if (!this.currentapp.app_id) {
this.appinit(); this.appinit();
} }
}, },
@ -270,8 +272,7 @@
'$store.state.currentapp': function () { '$store.state.currentapp': function () {
this.appinit(); this.appinit();
}, },
},computed:{ }, computed: {}
}
} }
</script> </script>

@ -14,8 +14,8 @@
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="willDeleteApp = false"> </el-button> <el-button @click="willDeleteApp = false"> </el-button>
<!-- <el-button v-if="delapp.issupersign" type="danger" @click="$router.push({name: 'FirAppInfossecurity', params: {id: delapp.app_id}})"> </el-button>--> <!-- <el-button v-if="delapp.issupersign" type="danger" @click="$router.push({name: 'FirAppInfossecurity', params: {id: delapp.app_id}})"> </el-button>-->
<el-button type="danger" @click="delApp"> </el-button> <el-button type="danger" @click="delApp"> </el-button>
</span> </span>
</el-dialog> </el-dialog>
@ -371,8 +371,9 @@
<i class="icon-eye el-icon-view"></i> 预览 <i class="icon-eye el-icon-view"></i> 预览
</el-button> </el-button>
<el-button v-if="r.issupersign" @click="DeleteApp(r)" class="btn btn-remove" icon="el-icon-loading" <el-button v-if="r.issupersign" @click="DeleteApp(r)" class="btn btn-remove"
circle></el-button> icon="el-icon-loading"
circle></el-button>
<el-button v-else @click="DeleteApp(r)" class="btn btn-remove" icon="el-icon-delete" <el-button v-else @click="DeleteApp(r)" class="btn btn-remove" icon="el-icon-delete"
circle></el-button> circle></el-button>
@ -717,17 +718,6 @@
getDelappTitle() { getDelappTitle() {
return `删除应用 ${this.delapp.name}` return `删除应用 ${this.delapp.name}`
}, },
getBH: function () {
let sch = this.$refs.appmain.scrollHeight;
if (sch === 0 || sch < window.innerHeight) {
sch = window.innerHeight;
} else {
sch += 280;
}
return sch;
}
}, },
filters: { filters: {
getiOStype: function (type) { getiOStype: function (type) {
@ -760,7 +750,7 @@
return ftype return ftype
}, },
make_icon_url(icon_url) { make_icon_url(icon_url) {
if(icon_url){ if (icon_url) {
if (!icon_url.startsWith("http")) { if (!icon_url.startsWith("http")) {
return location.origin + icon_url return location.origin + icon_url
} else { } else {
@ -781,7 +771,6 @@
}, mounted() { }, mounted() {
this.$store.dispatch('doucurrentapp', {}); this.$store.dispatch('doucurrentapp', {});
this.getappsFun({}); this.getappsFun({});
// window.addEventListener('scroll',this.auto_load);
}, },
destroyed() { destroyed() {
window.removeEventListener('scroll', this.auto_load, false); window.removeEventListener('scroll', this.auto_load, false);

@ -17,7 +17,7 @@
<span class="pattern right"><img src="../assets/download_pattern_right.png"></span> <span class="pattern right"><img src="../assets/download_pattern_right.png"></span>
</div> </div>
<el-container class="out-container"> <el-container class="out-container">
<div class="main"> <div class="main">
<header> <header>
@ -31,12 +31,15 @@
<span id="qrcode" class="qrcode"> <span id="qrcode" class="qrcode">
</span> </span>
</div> </div>
<p v-if="currentappinfo.issupersign" class="scan-tips wrapper icon-warp" >超级签</p> <p v-if="currentappinfo.issupersign" class="scan-tips wrapper icon-warp">超级签</p>
<p v-else class="scan-tips wrapper icon-warp" >{{ mcurrentappinfo.release_type|getiOStype }}</p> <p v-else class="scan-tips wrapper icon-warp">{{
mcurrentappinfo.release_type|getiOStype }}</p>
<h1 class="name wrapper"> <h1 class="name wrapper">
<span class="icon-warp" style="margin-left:0px"> <span class="icon-warp" style="margin-left:0px">
<i v-if="currentappinfo.type === 0 && agent !== ''" class="iconfont icon-android2"/> <i v-if="currentappinfo.type === 0 && agent !== ''"
<i v-if="currentappinfo.type === 1 && agent !== ''" class="iconfont icon-ios"/> class="iconfont icon-android2"/>
<i v-if="currentappinfo.type === 1 && agent !== ''"
class="iconfont icon-ios"/>
{{ currentappinfo.name }} {{ currentappinfo.name }}
</span> </span>
@ -46,7 +49,8 @@
class="text-black">{{ full_url }}</span></p> class="text-black">{{ full_url }}</span></p>
<div class="release-info"> <div class="release-info">
<p>{{ mcurrentappinfo.app_version }}Build {{ mcurrentappinfo.build_version }}- {{ mcurrentappinfo.binary_size }}</p> <p>{{ mcurrentappinfo.app_version }}Build {{ mcurrentappinfo.build_version }}-
{{ mcurrentappinfo.binary_size }}</p>
<p>更新于{{ mcurrentappinfo.created_time |formatTime}}</p> <p>更新于{{ mcurrentappinfo.created_time |formatTime}}</p>
<p class="version" v-if="mcurrentappinfo.changelog && agent === ''"> <p class="version" v-if="mcurrentappinfo.changelog && agent === ''">
更新日志{{ mcurrentappinfo.changelog }} 更新日志{{ mcurrentappinfo.changelog }}
@ -59,15 +63,24 @@
</el-button> </el-button>
<button type="button" v-else-if="wrong">{{ msg }}</button> <button type="button" v-else-if="wrong">{{ msg }}</button>
<div v-else > <div v-else>
<button v-if="isdownload" disabled="" class="loading" style="min-width: 42px; width: 42px; padding: 21px 0; border-top-color: transparent; border-left-color: transparent;">&nbsp;</button> <button v-if="isdownload" disabled="" class="loading"
style="min-width: 42px; width: 42px; padding: 21px 0; border-top-color: transparent; border-left-color: transparent;">
&nbsp;
</button>
<div v-else> <div v-else>
<div v-if="currentappinfo.need_password" style="margin:0 auto; width:166px"> <div v-if="currentappinfo.need_password"
<el-input prefix-icon="el-icon-lock" clearable="true" placeholder="请输入密码" v-model="password" icon="el-icon-loadings" type="primary" :underline="false"> </el-input> style="margin:0 auto; width:166px">
<el-input prefix-icon="el-icon-lock" clearable="true"
placeholder="请输入密码" v-model="password"
icon="el-icon-loadings" type="primary"
:underline="false"></el-input>
</div> </div>
<el-divider v-if="currentappinfo.need_password"></el-divider> <el-divider v-if="currentappinfo.need_password"></el-divider>
<button @click="download" > <button @click="download">
<el-link icon="el-icon-loadings" type="primary" :underline="false"> 下载安装 </el-link> <el-link icon="el-icon-loadings" type="primary" :underline="false">
下载安装
</el-link>
</button> </button>
</div> </div>
@ -131,7 +144,7 @@
<div class="release-info"> <div class="release-info">
<div class="info" v-if="mcurrentappinfo.changelog"> <div class="info" v-if="mcurrentappinfo.changelog">
<h3>更新日志</h3> <h3>更新日志</h3>
{{ mcurrentappinfo.changelog }} {{ mcurrentappinfo.changelog }}
</div> </div>
</div> </div>
@ -149,7 +162,7 @@
<script> <script>
import QRCode from 'qrcodejs2' import QRCode from 'qrcodejs2'
import {getShortAppinfo,getdownloadurl} from '../restful' import {getShortAppinfo, getdownloadurl} from '../restful'
export default { export default {
name: "FirDownload", name: "FirDownload",
@ -159,56 +172,55 @@
iscomboappinfo: {}, iscomboappinfo: {},
mcurrentappinfo: {}, mcurrentappinfo: {},
miscomboappinfo: {}, miscomboappinfo: {},
tmpinfo:{}, tmpinfo: {},
full_url:"", full_url: "",
agent: '', agent: '',
wrong: false, wrong: false,
msg: '', msg: '',
password:'', password: '',
dchoice:false, dchoice: false,
downloadurl:"", downloadurl: "",
isdownload:false, isdownload: false,
udid:"", udid: "",
} }
}, methods: { }, methods: {
download() { download() {
if( this.currentappinfo.app_id){ if (this.currentappinfo.app_id) {
this.isdownload = true; this.isdownload = true;
getdownloadurl(res=>{ getdownloadurl(res => {
if(res.code === 1000){ if (res.code === 1000) {
if(res.data.download_url === ""){ if (res.data.download_url === "") {
window.location.href=this.full_url; window.location.href = this.full_url;
return return
} }
if(this.currentappinfo.type === 1){ if (this.currentappinfo.type === 1) {
if(this.currentappinfo.issupersign){ if (this.currentappinfo.issupersign) {
if(this.$route.query.udid && this.udid === this.$route.query.udid){ if (this.$route.query.udid && this.udid === this.$route.query.udid) {
if(this.agent !== ''){ if (this.agent !== '') {
let download_url = res.data.download_url; let download_url = res.data.download_url;
this.downloadurl="itms-services://?action=download-manifest&url="+encodeURIComponent(download_url); this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url);
} }
}else { } else {
if(this.agent !== ''){ if (this.agent !== '') {
this.downloadurl = res.data.download_url; this.downloadurl = res.data.download_url;
} }
} }
}else { } else {
let download_url = res.data.download_url; let download_url = res.data.download_url;
this.downloadurl="itms-services://?action=download-manifest&url="+encodeURIComponent(download_url); this.downloadurl = "itms-services://?action=download-manifest&url=" + encodeURIComponent(download_url);
} }
}else{ } else {
if(this.agent !== ''){ if (this.agent !== '') {
this.downloadurl = res.data.download_url; this.downloadurl = res.data.download_url;
} }
} }
window.location.href=this.downloadurl; window.location.href = this.downloadurl;
} } else {
else {
this.isdownload = false; this.isdownload = false;
this.password=''; this.password = '';
this.$message({ this.$message({
message:"密码错误,或者下载链接失效", message: "密码错误,或者下载链接失效",
type: 'error', type: 'error',
}); });
} }
@ -217,8 +229,8 @@
'token': this.mcurrentappinfo.download_token, 'token': this.mcurrentappinfo.download_token,
'short': this.currentappinfo.short, 'short': this.currentappinfo.short,
'release_id': this.mcurrentappinfo.release_id, 'release_id': this.mcurrentappinfo.release_id,
'password':this.password, 'password': this.password,
'udid':this.udid, 'udid': this.udid,
}, },
'app_id': this.currentappinfo.app_id 'app_id': this.currentappinfo.app_id
}) })
@ -232,77 +244,77 @@
}) })
}, },
getDownloadTokenFun() { getDownloadTokenFun() {
let params={ "short": this.$route.params.short ,"time":new Date().getTime()}; let params = {"short": this.$route.params.short, "time": new Date().getTime()};
if(this.$route.query.release_id){ if (this.$route.query.release_id) {
params["release_id"]=this.$route.query.release_id params["release_id"] = this.$route.query.release_id
} }
if(this.$route.query.udid){ if (this.$route.query.udid) {
params["udid"]=this.$route.query.udid params["udid"] = this.$route.query.udid
}else { } else {
params["udid"]="" params["udid"] = ""
} }
getShortAppinfo(data => { getShortAppinfo(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.udid = data.udid; this.udid = data.udid;
if(!data.data.master_release.release_id){ if (!data.data.master_release.release_id) {
this.$message({ this.$message({
message:"该 release 版本不存在,请检查", message: "该 release 版本不存在,请检查",
type: 'error', type: 'error',
duration:0 duration: 0
}); });
return return
} }
if(this.agent === "android"){ if (this.agent === "android") {
// iOS // iOS
if(data.data.type === 1){ if (data.data.type === 1) {
if(data.data.has_combo){ if (data.data.has_combo) {
if(!params.release_id){ if (!params.release_id) {
this.currentappinfo = data.data.has_combo; this.currentappinfo = data.data.has_combo;
this.mcurrentappinfo = data.data.has_combo.master_release; this.mcurrentappinfo = data.data.has_combo.master_release;
}else { } else {
this.wrong = true; this.wrong = true;
this.msg = '该 release 版本只能在苹果设备使用'; this.msg = '该 release 版本只能在苹果设备使用';
} }
this.iscomboappinfo = data.data; this.iscomboappinfo = data.data;
this.miscomboappinfo = data.data.master_release; this.miscomboappinfo = data.data.master_release;
}else { } else {
this.wrong = true; this.wrong = true;
this.msg = '苹果应用不支持安卓设备'; this.msg = '苹果应用不支持安卓设备';
this.dchoice=true; this.dchoice = true;
} }
}else { } else {
this.dchoice=true; this.dchoice = true;
} }
}else if(this.agent === "apple"){ } else if (this.agent === "apple") {
if(data.data.type === 0){ if (data.data.type === 0) {
if(data.data.has_combo){ if (data.data.has_combo) {
if(!params.release_id){ if (!params.release_id) {
this.currentappinfo = data.data.has_combo; this.currentappinfo = data.data.has_combo;
this.mcurrentappinfo = data.data.has_combo.master_release; this.mcurrentappinfo = data.data.has_combo.master_release;
}else { } else {
this.wrong = true; this.wrong = true;
this.msg = '该 release 版本只能在安卓设备使用'; this.msg = '该 release 版本只能在安卓设备使用';
} }
this.iscomboappinfo = data.data; this.iscomboappinfo = data.data;
this.miscomboappinfo = data.data.master_release; this.miscomboappinfo = data.data.master_release;
}else { } else {
this.wrong = true; this.wrong = true;
this.msg = '安卓应用不支持苹果设备'; this.msg = '安卓应用不支持苹果设备';
this.dchoice=true; this.dchoice = true;
} }
}else { } else {
this.dchoice=true; this.dchoice = true;
} }
}else { } else {
this.dchoice=true; this.dchoice = true;
} }
if(this.dchoice){ if (this.dchoice) {
this.currentappinfo = data.data; this.currentappinfo = data.data;
this.mcurrentappinfo = data.data.master_release; this.mcurrentappinfo = data.data.master_release;
if (this.currentappinfo.has_combo) { if (this.currentappinfo.has_combo) {
@ -311,20 +323,19 @@
} }
} }
if(this.agent !== ''){ if (this.agent !== '') {
this.miscomboappinfo={}; this.miscomboappinfo = {};
this.iscomboappinfo = {}; this.iscomboappinfo = {};
} }
document.title = this.currentappinfo.name+'下载'; document.title = this.currentappinfo.name + '下载';
if(this.mcurrentappinfo.binary_url && this.agent !=='' && this.wrong === false){ if (this.mcurrentappinfo.binary_url && this.agent !== '' && this.wrong === false) {
window.location.href=this.mcurrentappinfo.binary_url window.location.href = this.mcurrentappinfo.binary_url
} }
} } else {
else {
this.$message({ this.$message({
message: data.msg, message: data.msg,
type: 'error', type: 'error',
duration:0 duration: 0
}); });
} }
}, params) }, params)
@ -376,20 +387,20 @@
this.getDownloadTokenFun(); this.getDownloadTokenFun();
this.full_url = location.href.split("?")[0]; this.full_url = location.href.split("?")[0];
this.qrcode(); this.qrcode();
},filters:{ }, filters: {
getiOStype: function (type) { getiOStype: function (type) {
let ftype = ''; let ftype = '';
if (type === 1) { if (type === 1) {
ftype = '内测版' ftype = '内测版'
} else if(type === 2) { } else if (type === 2) {
ftype = '企业版' ftype = '企业版'
} }
return ftype return ftype
}, },
formatTime:function (stime) { formatTime: function (stime) {
if(stime){ if (stime) {
stime = stime.split(".")[0].split("T"); stime = stime.split(".")[0].split("T");
return stime[0]+" "+stime[1] return stime[0] + " " + stime[1]
} }
} }
} }
@ -950,7 +961,7 @@
color: #fff color: #fff
} }
.main > header .actions button a{ .main > header .actions button a {
color: #fff color: #fff
} }
@ -1406,7 +1417,6 @@
} }
.app_bottom_fixed img { .app_bottom_fixed img {
width: 100%; width: 100%;
max-height: 80px max-height: 80px

@ -15,7 +15,9 @@
</el-col> </el-col>
<el-col :span="2" :push="4"> <el-col :span="2" :push="4">
<div class="block"><el-avatar :size="66" :src="$store.state.userinfo.head_img"></el-avatar></div> <div class="block">
<el-avatar :size="66" :src="$store.state.userinfo.head_img"></el-avatar>
</div>
</el-col> </el-col>
<el-col :span="4" :push="4"> <el-col :span="4" :push="4">
<el-dropdown style="padding-top: 12px;" @command="handleCommand"> <el-dropdown style="padding-top: 12px;" @command="handleCommand">
@ -44,7 +46,8 @@
</template> </template>
<script> <script>
import {logout} from '../restful' import {logout} from '../restful'
export default { export default {
name: "FirHeader", name: "FirHeader",
data() { data() {
@ -58,14 +61,13 @@ import {logout} from '../restful'
this.$router.push({name: 'FirUserProfileInfo'}) this.$router.push({name: 'FirUserProfileInfo'})
} else if (command === 'chpasswd') { } else if (command === 'chpasswd') {
this.$router.push({name: 'FirUserProfileChangePwd'}) this.$router.push({name: 'FirUserProfileChangePwd'})
}else if (command === 'storage') { } else if (command === 'storage') {
this.$router.push({name: 'FirUserProfileStorage'}) this.$router.push({name: 'FirUserProfileStorage'})
}else if (command === 'supersign') { } else if (command === 'supersign') {
this.$store.dispatch('doucurrentapp', {}); this.$store.dispatch('doucurrentapp', {});
this.$router.push({"name":'FirSuperSignBase', params: {act: "iosdeveloper"}}) this.$router.push({"name": 'FirSuperSignBase', params: {act: "iosdeveloper"}})
} } else if (command === 'exit') {
else if(command === 'exit'){
logout(data => { logout(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.$message.success("退出成功"); this.$message.success("退出成功");

@ -30,9 +30,9 @@
<el-button type="danger" @click="onSubmit">登录</el-button> <el-button type="danger" @click="onSubmit">登录</el-button>
</el-form-item> </el-form-item>
<!-- <el-form-item>--> <!-- <el-form-item>-->
<!-- <el-button type="primary" @click="onRegister" plain>注册</el-button>--> <!-- <el-button type="primary" @click="onRegister" plain>注册</el-button>-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
</el-form> </el-form>
@ -74,7 +74,7 @@
this.$cookies.set("token", data['token']); this.$cookies.set("token", data['token']);
this.$cookies.set("username", data.userinfo.username); this.$cookies.set("username", data.userinfo.username);
this.$cookies.set("first_name", data.userinfo.first_name); this.$cookies.set("first_name", data.userinfo.first_name);
this.$store.dispatch("get_user",data.userinfo); this.$store.dispatch("get_user", data.userinfo);
set_auth_token(); set_auth_token();
this.$router.push({name: 'FirApps'}) this.$router.push({name: 'FirApps'})
} else { } else {

@ -1,31 +1,39 @@
<template> <template>
<el-main> <el-main>
<el-dialog :title="title" :visible.sync="dialogaddDeveloperVisible" :destroy-on-close="true" :close-on-click-modal="false" style="text-align:center"> <el-dialog :title="title" :visible.sync="dialogaddDeveloperVisible" :destroy-on-close="true"
:close-on-click-modal="false" style="text-align:center">
<el-form ref="storageinfoform" :model="editdeveloperinfo" <el-form ref="storageinfoform" :model="editdeveloperinfo"
label-width="80px" style="margin:0 auto;"> label-width="80px" style="margin:0 auto;">
<el-form-item label-width="110px" label="APP_ID"> <el-form-item label-width="110px" label="APP_ID">
<el-input :disabled='isedit' v-model="editdeveloperinfo.email" ></el-input> <el-input :disabled='isedit' v-model="editdeveloperinfo.email"></el-input>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="password"> <el-form-item label-width="110px" label="password">
<el-input v-model="editdeveloperinfo.password" :placeholder="placeholder"></el-input> <el-input v-model="editdeveloperinfo.password" :placeholder="placeholder"></el-input>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="设备数量"> <el-form-item label-width="110px" label="设备数量">
<el-input v-model="editdeveloperinfo.usable_number"></el-input> <el-input v-model="editdeveloperinfo.usable_number"></el-input>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="备注"> <el-form-item label-width="110px" label="备注">
<el-input v-model="editdeveloperinfo.description"></el-input> <el-input v-model="editdeveloperinfo.description"></el-input>
</el-form-item> </el-form-item>
<div style="" > <div style="">
<el-button v-if="isedit && editdeveloperinfo.is_actived" @click="syncdevices">同步设备信息</el-button> <el-button v-if="isedit && editdeveloperinfo.is_actived" size="small" @click="syncdevices">同步设备信息
<el-button v-if="isedit && editdeveloperinfo.is_actived && !editdeveloperinfo.certid" @click="isocertcert">手动创建证书</el-button> </el-button>
<el-button @click="updateorcreate">保存</el-button> <el-button v-if="isedit && editdeveloperinfo.is_actived && !editdeveloperinfo.certid" size="small"
<el-button @click="canceledit">取消</el-button> @click="isocertcert">手动创建证书
</div> </el-button>
<el-button v-if="isedit && editdeveloperinfo.is_actived" type="danger" size="small"
@click="activedeveloperFun(editdeveloperinfo,'checkauth')">开发者账户激活检测
</el-button>
<el-button @click="updateorcreate">保存</el-button>
<el-button @click="canceledit">取消</el-button>
</div>
</el-form> </el-form>
@ -37,28 +45,40 @@
:visible.sync="codeactiveVisible" :visible.sync="codeactiveVisible"
width="30%" width="30%"
center> center>
<div>
<el-input
placeholder="一般为6位数字"
v-model="authcode">
</el-input>
</div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="codeactiveVisible = false"> </el-button> <el-button @click="codeactiveVisible = false"> </el-button>
<el-button type="primary" @click="codeactiveVisible = false"> </el-button> <el-button type="primary" @click="inputcode"> </el-button>
</span> </span>
</el-dialog> </el-dialog>
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick" tab-position="top"> <el-tabs v-model="activeName" type="border-card" @tab-click="handleClick" tab-position="top">
<el-tab-pane label="开发者账户" name="iosdeveloper"> <el-tab-pane label="开发者账户" name="iosdeveloper">
<el-input <el-input
style="width: 30%;margin-right: 30px;margin-bottom: 10px" style="width: 30%;margin-right: 30px;margin-bottom: 10px"
v-model="appidseach" v-model="appidseach"
clearable clearable
placeholder="输入用户APPID" /> placeholder="输入用户APPID"/>
<el-button type="primary" icon="el-icon-search" @click="handleCurrentChange(pagination.currentPage)">搜索</el-button> <el-button type="primary" icon="el-icon-search" @click="handleCurrentChange(pagination.currentPage)">
搜索
</el-button>
<div style="width: 40%;margin-right: 30px;float:right"> <div style="width: 40%;margin-right: 30px;float:right">
<el-link :underline="false">总设备量{{ developer_used_info.all_usable_number}} 已经使用平台{{ developer_used_info.all_use_number}} 其他{{developer_used_info.other_used_sum}} 还剩{{developer_used_info.all_usable_number- developer_used_info.flyapp_used_sum}} 可用</el-link> <el-link :underline="false">总设备量{{ developer_used_info.all_usable_number}} 已经使用平台{{
developer_used_info.all_use_number}} 其他{{developer_used_info.other_used_sum}}
还剩{{developer_used_info.all_usable_number- developer_used_info.flyapp_used_sum}} 可用
</el-link>
<el-progress <el-progress
type="line" type="line"
:color="developer_usedColor" :color="developer_usedColor"
:text-inside="true" :stroke-width="18" :percentage="percentage" status="success"></el-progress> :text-inside="true" :stroke-width="18" :percentage="percentage"
status="success"></el-progress>
</div> </div>
<el-table <el-table
@ -76,7 +96,9 @@
<el-popover trigger="hover" placement="top"> <el-popover trigger="hover" placement="top">
<p>开发者账户已使用设备数: {{ scope.row.developer_used_number }}</p> <p>开发者账户已使用设备数: {{ scope.row.developer_used_number }}</p>
<p>开发者账户可用设备数: {{ 100-scope.row.developer_used_number }}</p> <p>开发者账户可用设备数: {{ 100-scope.row.developer_used_number }}</p>
<p>由于您设置可用设备数: {{ scope.row.usable_number}} ,所以现在可用设备数: {{ scope.row.usable_number-scope.row.developer_used_number > 0 ?scope.row.usable_number-scope.row.developer_used_number :0 }}</p> <p>由于您设置可用设备数: {{ scope.row.usable_number}} ,所以现在可用设备数: {{
scope.row.usable_number-scope.row.developer_used_number > 0
?scope.row.usable_number-scope.row.developer_used_number :0 }}</p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<el-tag size="medium">{{ scope.row.email }}</el-tag> <el-tag size="medium">{{ scope.row.email }}</el-tag>
@ -89,21 +111,43 @@
prop="is_actived" prop="is_actived"
label="是否激活" label="是否激活"
width="110"> width="110">
<template slot-scope="scope" > <template slot-scope="scope">
<el-button v-if="scope.row.is_actived === true" type="success" size="small">已激活</el-button> <el-button v-if="scope.row.is_actived === true" type="success" size="small">已激活</el-button>
<el-button v-else type="danger" size="small" @click="activedeveloperFun(scope.row)">点击激活</el-button> <el-button v-else type="danger" size="small"
@click="activedeveloperFun(scope.row,'preactive')">点击激活
</el-button>
</template>
</el-table-column>
<el-table-column
prop="certid"
label="账户状态"
width="100">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
<p v-if="!scope.row.certid && scope.row.is_actived === true">开发证书不可用请在编辑中手动创建开发者证书</p>
<p v-if="!scope.row.certid && scope.row.is_actived !== true">请先激活开发者账户</p>
<p v-if="scope.row.certid && scope.row.is_actived === true">账户已经启用</p>
<div slot="reference" class="name-wrapper">
<el-button v-if="scope.row.certid " type="success" size="small">可用</el-button>
<el-button v-else type="danger" size="small">不可用</el-button>
</div>
</el-popover>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="usable_number" prop="usable_number"
label="可用设备数" label="可用设备"
width="100"> width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover trigger="hover" placement="top"> <el-popover trigger="hover" placement="top">
<p>可用设备数: {{ scope.row.usable_number-scope.row.developer_used_number > 0 ?scope.row.usable_number-scope.row.developer_used_number :0}}</p> <p>可用设备数: {{ scope.row.usable_number-scope.row.developer_used_number > 0
?scope.row.usable_number-scope.row.developer_used_number :0}}</p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<el-tag size="medium"> {{ scope.row.usable_number-scope.row.developer_used_number > 0 ?scope.row.usable_number-scope.row.developer_used_number :0 }}</el-tag> <el-tag size="medium"> {{ scope.row.usable_number-scope.row.developer_used_number >
0 ?scope.row.usable_number-scope.row.developer_used_number :0 }}
</el-tag>
</div> </div>
</el-popover> </el-popover>
</template> </template>
@ -111,8 +155,8 @@
<el-table-column <el-table-column
prop="use_number" prop="use_number"
label="已消耗设备数" label="设备消耗"
width="120"> width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover trigger="hover" placement="top"> <el-popover trigger="hover" placement="top">
<p>开发者账户已使用设备数本平台: {{ scope.row.use_number }}</p> <p>开发者账户已使用设备数本平台: {{ scope.row.use_number }}</p>
@ -133,21 +177,23 @@
<el-table-column <el-table-column
prop="description" prop="description"
label="备注" label="备注"
> >
</el-table-column> </el-table-column>
<el-table-column <el-table-column
fixed="right" fixed="right"
label="操作" label="操作"
width="150"> width="150">
<template slot-scope="scope" > <template slot-scope="scope">
<el-button <el-button
size="mini" size="mini"
@click="handleEditDeveloper(scope.row)">编辑</el-button> @click="handleEditDeveloper(scope.row)">编辑
</el-button>
<el-button <el-button
size="mini" size="mini"
type="danger" type="danger"
@click="handleDeleteDeveloper(scope.row)">删除</el-button> @click="handleDeleteDeveloper(scope.row)">删除
</el-button>
</template> </template>
</el-table-column> </el-table-column>
@ -155,24 +201,50 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="添加开发者" name="adddeveloper">添加开发者</el-tab-pane> <el-tab-pane label="添加开发者" name="adddeveloper" style="text-align:center">
<el-form ref="storageinfoform" :model="editdeveloperinfo"
label-width="80px" style="margin:0 auto;">
<el-form-item label-width="110px" label="APP_ID">
<el-input :disabled='isedit' v-model="editdeveloperinfo.email"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="password">
<el-input v-model="editdeveloperinfo.password" :placeholder="placeholder"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="设备数量">
<el-input v-model="editdeveloperinfo.usable_number"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="备注">
<el-input v-model="editdeveloperinfo.description"></el-input>
</el-form-item>
<div style="">
<el-button @click="updateorcreate">添加</el-button>
<el-button @click="canceledit">取消</el-button>
</div>
</el-form>
</el-tab-pane>
<el-tab-pane label="设备消耗" name="useddevices"> <el-tab-pane label="设备消耗" name="useddevices">
<el-input <el-input
style="width: 30%;margin-right: 30px;margin-bottom: 10px" style="width: 30%;margin-right: 30px;margin-bottom: 10px"
v-model="udidsearch" v-model="udidsearch"
clearable clearable
placeholder="输入UDID" /> placeholder="输入UDID"/>
<el-input <el-input
style="width: 20%;margin-right: 30px;margin-bottom: 10px" style="width: 20%;margin-right: 30px;margin-bottom: 10px"
v-model="Bundleidsearch" v-model="Bundleidsearch"
clearable clearable
placeholder="输入BundleID" /> placeholder="输入BundleID"/>
<el-input <el-input
style="width: 20%;margin-right: 30px;margin-bottom: 10px" style="width: 20%;margin-right: 30px;margin-bottom: 10px"
v-model="appidseach" v-model="appidseach"
clearable clearable
placeholder="输入用户APPID" /> placeholder="输入用户APPID"/>
<el-button type="primary" icon="el-icon-search" @click="handleCurrentChange(pagination.currentPage)">搜索</el-button> <el-button type="primary" icon="el-icon-search" @click="handleCurrentChange(pagination.currentPage)">
搜索
</el-button>
<el-table <el-table
:data="app_devices_lists" :data="app_devices_lists"
@ -183,7 +255,7 @@
fixed fixed
prop="device_udid" prop="device_udid"
label="设备ID" label="设备ID"
> >
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="device_name" prop="device_name"
@ -220,13 +292,15 @@
style="width: 30%;margin-right: 30px;margin-bottom: 10px" style="width: 30%;margin-right: 30px;margin-bottom: 10px"
v-model="udidsearch" v-model="udidsearch"
clearable clearable
placeholder="输入UDID" /> placeholder="输入UDID"/>
<el-input <el-input
style="width: 20%;margin-right: 30px;margin-bottom: 10px" style="width: 20%;margin-right: 30px;margin-bottom: 10px"
v-model="Bundleidsearch" v-model="Bundleidsearch"
clearable clearable
placeholder="输入BundleID" /> placeholder="输入BundleID"/>
<el-button type="primary" icon="el-icon-search" @click="handleCurrentChange(pagination.currentPage)">搜索</el-button> <el-button type="primary" icon="el-icon-search" @click="handleCurrentChange(pagination.currentPage)">
搜索
</el-button>
<el-table <el-table
@ -239,7 +313,7 @@
fixed fixed
prop="udid" prop="udid"
label="设备ID" label="设备ID"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover trigger="hover" placement="top"> <el-popover trigger="hover" placement="top">
<p>Bundle_ID: {{ scope.row.bundle_id }}</p> <p>Bundle_ID: {{ scope.row.bundle_id }}</p>
@ -282,11 +356,12 @@
fixed="right" fixed="right"
label="操作" label="操作"
width="80"> width="80">
<template slot-scope="scope" > <template slot-scope="scope">
<el-button <el-button
size="mini" size="mini"
type="danger" type="danger"
@click="udidDeleteFun(scope)">删除</el-button> @click="udidDeleteFun(scope)">删除
</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -311,33 +386,34 @@
<script> <script>
import {iosdeveloper, iosdevices, iosdevicesudid, userinfos} from "../restful"; import {iosdeveloper, iosdevices, iosdevicesudid, userinfos} from "../restful";
import {removeAaary,IsNum} from "../utils"; import {removeAaary, IsNum} from "../utils";
export default { export default {
name: "FirSuperSignBase", name: "FirSuperSignBase",
data() { data() {
return { return {
app_developer_lists:[], app_developer_lists: [],
app_devices_lists:[], app_devices_lists: [],
app_udid_lists:[], app_udid_lists: [],
activeName:"iosdeveloper", activeName: "iosdeveloper",
udidsearch:"", udidsearch: "",
Bundleidsearch:"", Bundleidsearch: "",
appidseach:"", appidseach: "",
dialogaddDeveloperVisible:false, dialogaddDeveloperVisible: false,
title:"", title: "",
editdeveloperinfo:{}, editdeveloperinfo: {},
isedit:false, isedit: false,
placeholder:"", placeholder: "",
codeactiveVisible:false, codeactiveVisible: false,
pagination:{"currentPage":1,"total":0,"pagesize":10}, pagination: {"currentPage": 1, "total": 0, "pagesize": 10},
developer_used_info:{"all_usable_number":0,"other_used_sum":0,"all_use_number":0}, developer_used_info: {"all_usable_number": 0, "other_used_sum": 0, "all_use_number": 0},
percentage:0, percentage: 0,
authcode: "",
authemail: "",
} }
}, },
methods: { methods: {
developer_usedColor(percentage){ developer_usedColor(percentage) {
if (percentage < 20) { if (percentage < 20) {
return '#6f7ad3'; return '#6f7ad3';
} else if (percentage < 40) { } else if (percentage < 40) {
@ -347,75 +423,85 @@
} else if (percentage < 80) { } else if (percentage < 80) {
return '#e6a23c'; return '#e6a23c';
} else if(percentage<90){ } else if (percentage < 90) {
return '#E63918'; return '#E63918';
}else { } else {
return '#F50346'; return '#F50346';
} }
}, },
udidDeleteFun(scope){ udidDeleteFun(scope) {
this.iosdevicesudidFun('DELETE',{id:scope.row.id,aid:scope.row.app_id}); this.iosdevicesudidFun('DELETE', {id: scope.row.id, aid: scope.row.app_id});
this.app_udid_lists=removeAaary(this.app_udid_lists,scope.row) this.app_udid_lists = removeAaary(this.app_udid_lists, scope.row)
}, },
handleSizeChange(val) { handleSizeChange(val) {
this.pagination.pagesize=val; this.pagination.pagesize = val;
this.get_data_from_tabname(this.activeName,{"size":this.pagination.pagesize,"page":this.pagination.currentPage}) this.get_data_from_tabname(this.activeName, {
"size": this.pagination.pagesize,
"page": this.pagination.currentPage
})
}, },
handleCurrentChange(val) { handleCurrentChange(val) {
this.pagination.currentPage=val; this.pagination.currentPage = val;
this.get_data_from_tabname(this.activeName,{"size":this.pagination.pagesize,"page":this.pagination.currentPage}) this.get_data_from_tabname(this.activeName, {
"size": this.pagination.pagesize,
"page": this.pagination.currentPage
})
}, },
syncdevices(){ syncdevices() {
this.iosdeveloperFun({"methods":"PUT","data":{"email":this.editdeveloperinfo.email,"act":"syncdevice"}}); this.iosdeveloperFun({
"methods": "PUT",
"data": {"email": this.editdeveloperinfo.email, "act": "syncdevice"}
});
}, },
isocertcert(){ isocertcert() {
this.iosdeveloperFun({"methods":"PUT","data":{"email":this.editdeveloperinfo.email,"act":"ioscert"}}); this.iosdeveloperFun({
"methods": "PUT",
"data": {"email": this.editdeveloperinfo.email, "act": "ioscert"}
});
}, },
inputcode(developer){ inputcode() {
this.$prompt('请输入验证码', '提示', { this.authcode = this.authcode.replace(/^\s+|\s+$/g, "");
confirmButtonText: '确定', if (this.authcode.toString().length > 5 && IsNum(this.authcode)) {
cancelButtonText: '取消', this.iosdeveloperFun({
closeOnClickModal:false, "methods": "PUT",
}).then(({ value }) => { "data": {"email": this.authemail, "act": "nowactive", "code": this.authcode}
if(value.toString().length>5 && IsNum(value)){
this.iosdeveloperFun({"methods":"PUT","data":{"email":developer.email,"act":"nowactive","code":value.replace(/^\s+|\s+$/g, "")}});
}
}).catch(() => {
this.$message({
type: 'info',
message: '取消激活'
}); });
}); this.authcode = "";
this.authemail = ""
}
}, },
activedeveloperFun(developer){ activedeveloperFun(developer, act) {
this.iosdeveloperFun({"methods":"PUT","data":{"email":developer.email,"act":"preactive"}}); this.iosdeveloperFun({"methods": "PUT", "data": {"email": developer.email, "act": act}});
this.inputcode(developer) this.codeactiveVisible = true;
this.authemail = developer.email;
// this.inputcode(developer)
}, },
canceledit(){ canceledit() {
this.dialogaddDeveloperVisible=false; this.dialogaddDeveloperVisible = false;
this.editdeveloperinfo={}; this.editdeveloperinfo = {};
this.isedit=false; this.isedit = false;
this.placeholder="" this.placeholder = ""
}, },
handleEditDeveloper(developer_info){ handleEditDeveloper(developer_info) {
this.editdeveloperinfo=developer_info; this.editdeveloperinfo = developer_info;
this.title='编辑开发者账户'; this.title = '编辑开发者账户';
this.dialogaddDeveloperVisible=true; this.dialogaddDeveloperVisible = true;
this.isedit=true; this.isedit = true;
this.placeholder="为空表示不修改密码" this.placeholder = "为空表示不修改密码"
}, },
updateorcreate(){ updateorcreate() {
if(this.isedit){ if (this.isedit) {
this.iosdeveloperFun({"methods":"PUT","data":this.editdeveloperinfo}) this.iosdeveloperFun({"methods": "PUT", "data": this.editdeveloperinfo})
}else { } else {
if(this.editdeveloperinfo.email && this.editdeveloperinfo.password && this.editdeveloperinfo.usable_number ){ if (this.editdeveloperinfo.email && this.editdeveloperinfo.password && this.editdeveloperinfo.usable_number) {
this.iosdeveloperFun({"methods":"POST","data":this.editdeveloperinfo}); this.iosdeveloperFun({"methods": "POST", "data": this.editdeveloperinfo});
}else { } else {
this.$message.warning("输入格式有误") this.$message.warning("输入格式有误")
} }
} }
}, },
handleDeleteDeveloper(developer_info){ handleDeleteDeveloper(developer_info) {
this.$confirm('此操作会删除该苹果开发者账户下面的生成的证书等数据,可能会导致超级签包的闪退, 是否继续?', '警告', { this.$confirm('此操作会删除该苹果开发者账户下面的生成的证书等数据,可能会导致超级签包的闪退, 是否继续?', '警告', {
@ -423,7 +509,7 @@
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.iosdeveloperFun({"methods":"DELETE","data":{"email":developer_info.email}}); this.iosdeveloperFun({"methods": "DELETE", "data": {"email": developer_info.email}});
}).catch(() => { }).catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',
@ -431,29 +517,29 @@
}); });
}); });
}, },
get_data_from_tabname(tabname,data={}){ get_data_from_tabname(tabname, data = {}) {
data.udid=this.udidsearch.replace(/^\s+|\s+$/g, ""); data.udid = this.udidsearch.replace(/^\s+|\s+$/g, "");
data.bundleid=this.Bundleidsearch.replace(/^\s+|\s+$/g, ""); data.bundleid = this.Bundleidsearch.replace(/^\s+|\s+$/g, "");
data.appid=this.appidseach.replace(/^\s+|\s+$/g, ""); data.appid = this.appidseach.replace(/^\s+|\s+$/g, "");
this.$router.push({"name":'FirSuperSignBase', params: {act: tabname}}); this.$router.push({"name": 'FirSuperSignBase', params: {act: tabname}});
if(tabname === "useddevices"){ if (tabname === "useddevices") {
this.iosdevicesFun('GET',data) this.iosdevicesFun('GET', data)
}else if(tabname === "devicesudid"){ } else if (tabname === "devicesudid") {
this.iosdevicesudidFun('GET',data) this.iosdevicesudidFun('GET', data)
}else if(tabname === "adddeveloper"){ } else if (tabname === "adddeveloper") {
this.title='新增私有开发者账户'; // this.title='';
this.dialogaddDeveloperVisible=true; // this.dialogaddDeveloperVisible=true;
}else if(tabname === "iosdeveloper"){ } else if (tabname === "iosdeveloper") {
this.iosdeveloperFun({"methods":"GET","data":data}) this.iosdeveloperFun({"methods": "GET", "data": data})
} }
}, },
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
handleClick(tab, event) { handleClick(tab, event) {
this.pagination={"currentPage":1,"total":0,"pagesize":10}; this.pagination = {"currentPage": 1, "total": 0, "pagesize": 10};
this.get_data_from_tabname(tab.name); this.get_data_from_tabname(tab.name);
}, },
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
deviceformatter(row, column){ deviceformatter(row, column) {
let stime = row.created_time; let stime = row.created_time;
if (stime) { if (stime) {
stime = stime.split(".")[0].split("T"); stime = stime.split(".")[0].split("T");
@ -462,7 +548,7 @@
return ''; return '';
}, },
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
formatter(row, column){ formatter(row, column) {
let stime = row.updated_time; let stime = row.updated_time;
if (stime) { if (stime) {
stime = stime.split(".")[0].split("T"); stime = stime.split(".")[0].split("T");
@ -470,77 +556,82 @@
} else } else
return ''; return '';
}, },
iosdevicesFun(methods,data){ iosdevicesFun(methods, data) {
iosdevices(data=>{ iosdevices(data => {
if(data.code === 1000){ if (data.code === 1000) {
this.app_devices_lists = data.data; this.app_devices_lists = data.data;
this.pagination.total=data.count; this.pagination.total = data.count;
} }
},{ }, {
"methods":methods,"data":data "methods": methods, "data": data
}) })
}, },
iosdeveloperFun(params){ iosdeveloperFun(params) {
iosdeveloper(data=>{ iosdeveloper(data => {
if(data.code === 1000){ if (data.code === 1000) {
this.app_developer_lists = data.data; this.app_developer_lists = data.data;
this.pagination.total=data.count; this.pagination.total = data.count;
if(data.use_num){ if (data.use_num) {
this.developer_used_info=data.use_num; this.developer_used_info = data.use_num;
if(this.developer_used_info.all_usable_number !==0){ if (this.developer_used_info.all_usable_number !== 0) {
this.percentage=parseInt(this.developer_used_info.flyapp_used_sum*100/this.developer_used_info.all_usable_number); this.percentage = parseInt(this.developer_used_info.flyapp_used_sum * 100 / this.developer_used_info.all_usable_number);
} }
} }
if(this.dialogaddDeveloperVisible){ if (this.dialogaddDeveloperVisible) {
this.canceledit(); this.canceledit();
this.$message.success("操作成功"); this.$message.success("操作成功");
this.activeName="iosdeveloper"; this.activeName = "iosdeveloper";
this.editdeveloperinfo={}; this.editdeveloperinfo = {};
} }
} if (!this.edit && this.editdeveloperinfo.email) {
else if(data.code === 1008){ this.$message.success("添加成功");
this.activeName = "iosdeveloper";
this.editdeveloperinfo = {};
}
} else if (data.code === 1008) {
this.$message.error(data.msg); this.$message.error(data.msg);
} } else {
else {
this.$message.error("操作失败") this.$message.error("操作失败")
} }
},params) if (this.codeactiveVisible) {
this.codeactiveVisible = false;
}
}, params)
}, },
iosdevicesudidFun(action,data){ iosdevicesudidFun(action, data) {
iosdevicesudid(data=>{ iosdevicesudid(data => {
if(data.code === 1000){ if (data.code === 1000) {
if(action !== "DELETE"){ if (action !== "DELETE") {
this.app_udid_lists = data.data; this.app_udid_lists = data.data;
this.pagination.total=data.count; this.pagination.total = data.count;
} }
} }
},{ }, {
"methods":action,"data":data "methods": action, "data": data
}) })
}, },
getUserInfoFun(){ getUserInfoFun() {
userinfos(data=>{ userinfos(data => {
if(data.code === 1000){ if (data.code === 1000) {
this.$store.dispatch("getUser",data.data); this.$store.dispatch("getUser", data.data);
}else { } else {
this.$message.error("用户信息获取失败") this.$message.error("用户信息获取失败")
} }
},{"methods":"GET"}) }, {"methods": "GET"})
}, },
}, mounted() { }, mounted() {
this.getUserInfoFun(); this.getUserInfoFun();
if(this.$route.params.act){ if (this.$route.params.act) {
let activeName=this.$route.params.act; let activeName = this.$route.params.act;
let activeName_list=["useddevices","devicesudid","adddeveloper","iosdeveloper"]; let activeName_list = ["useddevices", "devicesudid", "adddeveloper", "iosdeveloper"];
for(let index in activeName_list){ for (let index in activeName_list) {
if(activeName_list[index] === activeName){ if (activeName_list[index] === activeName) {
this.activeName=activeName; this.activeName = activeName;
let bundleid=this.$route.query.bundleid; let bundleid = this.$route.query.bundleid;
if(bundleid){ if (bundleid) {
this.Bundleidsearch=bundleid; this.Bundleidsearch = bundleid;
} }
this.get_data_from_tabname(activeName); this.get_data_from_tabname(activeName);
return return

@ -70,104 +70,106 @@
data() { data() {
return { return {
imageUrl: '', imageUrl: '',
userinfo:{}, userinfo: {},
uploadconf:{}, uploadconf: {},
} }
}, },
methods: { methods: {
updateimgs(certinfo){ updateimgs(certinfo) {
uploadimgs(data => { uploadimgs(data => {
if (data.code === 1000) { if (data.code === 1000) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(data.data); console.log(data.data);
this.$message.success('上传成功'); this.$message.success('上传成功');
this.updateUserInfo({"methods":'GET'}); this.updateUserInfo({"methods": 'GET'});
}else { } else {
this.$message.error('更新失败'); this.$message.error('更新失败');
} }
},{'methods':'PUT','data':{'certinfo':certinfo}}); }, {'methods': 'PUT', 'data': {'certinfo': certinfo}});
}, },
uploadtostorage(file,certinfo){ uploadtostorage(file, certinfo) {
if(certinfo.storage === 1){ if (certinfo.storage === 1) {
// eslint-disable-next-line no-unused-vars,no-unreachable // eslint-disable-next-line no-unused-vars,no-unreachable
uploadqiniuoss(file,certinfo,this,res=>{ uploadqiniuoss(file, certinfo, this, res => {
this.updateimgs(certinfo); this.updateimgs(certinfo);
},process=>{ }, process => {
this.uploadprocess = process; this.uploadprocess = process;
}) })
}else if(certinfo.storage === 2){ } else if (certinfo.storage === 2) {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
uploadaliyunoss(file,certinfo,this,res=>{ uploadaliyunoss(file, certinfo, this, res => {
this.updateimgs(certinfo); this.updateimgs(certinfo);
},process=>{ }, process => {
this.uploadprocess = process; this.uploadprocess = process;
}); });
}else { } else {
// //
certinfo.upload_url = getuploadurl(); certinfo.upload_url = getuploadurl();
// eslint-disable-next-line no-unused-vars,no-unreachable // eslint-disable-next-line no-unused-vars,no-unreachable
uploadlocalstorage(file,certinfo,this,res=>{ uploadlocalstorage(file, certinfo, this, res => {
this.updateimgs(certinfo); this.updateimgs(certinfo);
},process=>{ }, process => {
this.uploadprocess = process; this.uploadprocess = process;
}) })
} }
}, },
updateUserInfo(datainfo){ updateUserInfo(datainfo) {
userinfos(data=>{ userinfos(data => {
if(data.code === 1000){ if (data.code === 1000) {
this.userinfo = data.data; this.userinfo = data.data;
this.$store.dispatch("getUser",data.data); this.$store.dispatch("getUser", data.data);
this.$store.dispatch('doucurrentapp', {}); this.$store.dispatch('doucurrentapp', {});
this.imageUrl = data.data.head_img; this.imageUrl = data.data.head_img;
if(datainfo.data){ if (datainfo.data) {
this.$message.success("更新成功") this.$message.success("更新成功")
} }
}else { } else {
this.$message.error("更新失败") this.$message.error("更新失败")
} }
},datainfo) }, datainfo)
}, },
update_name(){ update_name() {
this.updateUserInfo({"methods":'PUT','data':{"first_name":this.userinfo.first_name}}); this.updateUserInfo({"methods": 'PUT', 'data': {"first_name": this.userinfo.first_name}});
}, },
beforeAvatarUpload(file) { beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2; const isLt2M = file.size / 1024 / 1024 < 2;
if(file.type === 'image/jpeg' || file.type === 'image/png'|| file.type === 'image/jpg'){ if (file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg') {
if (isLt2M) { if (isLt2M) {
uploadimgs(data => { uploadimgs(data => {
if (data.code === 1000) { if (data.code === 1000) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(data.data); console.log(data.data);
let certinfo=data.data; let certinfo = data.data;
this.uploadtostorage(file,certinfo); this.uploadtostorage(file, certinfo);
} }
},{'methods':'GET','data':{'app_id':this.userinfo.uid,'upload_key':file.name,'ftype':'head'}}); }, {
'methods': 'GET',
'data': {'app_id': this.userinfo.uid, 'upload_key': file.name, 'ftype': 'head'}
});
return false; return false;
} } else {
else{
this.$message.error('上传头像图片大小不能超过 2MB!'); this.$message.error('上传头像图片大小不能超过 2MB!');
} }
}else { } else {
this.$message.error('上传头像图片只能是 JPG/PNG/JPEG 格式!'); this.$message.error('上传头像图片只能是 JPG/PNG/JPEG 格式!');
} }
return false; return false;
}, },
setfunactive(item){ setfunactive(item) {
for (let key in this.$refs) { for (let key in this.$refs) {
if(key === item){ if (key === item) {
this.$refs[key].classList.add('active'); this.$refs[key].classList.add('active');
}else { } else {
this.$refs[key].classList.remove('active'); this.$refs[key].classList.remove('active');
} }
} }
@ -177,21 +179,19 @@
this.setfunactive('userinfo'); this.setfunactive('userinfo');
} else if (this.$store.state.userInfoIndex === 1) { } else if (this.$store.state.userInfoIndex === 1) {
this.setfunactive('changepwd'); this.setfunactive('changepwd');
}else if (this.$store.state.userInfoIndex === 2) { } else if (this.$store.state.userInfoIndex === 2) {
this.setfunactive('storage'); this.setfunactive('storage');
} }
} }
}, mounted() { }, mounted() {
this.autoSetInfoIndex(); this.autoSetInfoIndex();
this.updateUserInfo({"methods":'GET'}); this.updateUserInfo({"methods": 'GET'});
}, watch: { }, watch: {
'$store.state.userInfoIndex': function () { '$store.state.userInfoIndex': function () {
this.autoSetInfoIndex(); this.autoSetInfoIndex();
}, },
},filters:{ }, filters: {}, computed: {
getuppicurl() {
},computed:{
getuppicurl(){
return getuserpicurl() return getuserpicurl()
} }
} }

@ -59,17 +59,19 @@
updatepasswd() { updatepasswd() {
if (this.form.newpassword === this.form.surepassword) { if (this.form.newpassword === this.form.surepassword) {
userinfos(data=>{ userinfos(data => {
if(data.code === 1000){ if (data.code === 1000) {
this.userinfo = data.data; this.userinfo = data.data;
this.$message.success('密码修改成功'); this.$message.success('密码修改成功');
}else { } else {
this.$message.error('密码修改失败,'+data.msg); this.$message.error('密码修改失败,' + data.msg);
} }
},{"methods":'PUT','data':{ }, {
"methods": 'PUT', 'data': {
"oldpassword": this.form.oldpassword, "oldpassword": this.form.oldpassword,
"surepassword": this.form.surepassword "surepassword": this.form.surepassword
}}); }
});
} else { } else {
this.$message.error('密码不一致'); this.$message.error('密码不一致');
} }

@ -5,14 +5,16 @@
<el-form-item> <el-form-item>
<el-row> <el-row>
<el-col :span="22"> <el-col :span="22">
<el-input v-model="userinfo.username" prefix-icon="el-icon-user" placeholder="用户名" disabled></el-input> <el-input v-model="userinfo.username" prefix-icon="el-icon-user" placeholder="用户名"
disabled></el-input>
</el-col> </el-col>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-row> <el-row>
<el-col :span="18"> <el-col :span="18">
<el-input v-model="userinfo.qq" :readonly="editqq !== true" ref="qq" prefix-icon="el-icon-message" <el-input v-model="userinfo.qq" :readonly="editqq !== true" ref="qq"
prefix-icon="el-icon-message"
placeholder="QQ"></el-input> placeholder="QQ"></el-input>
</el-col> </el-col>
<el-col :span="2"> <el-col :span="2">
@ -87,6 +89,7 @@
<script> <script>
import {userinfos} from '../restful' import {userinfos} from '../restful'
export default { export default {
name: "FirUserProfileInfo", name: "FirUserProfileInfo",
data() { data() {
@ -99,38 +102,38 @@
editposition: false editposition: false
} }
}, methods: { }, methods: {
saveQQ(){ saveQQ() {
this.updateUserInfo({"methods":'PUT','data':this.userinfo}); this.updateUserInfo({"methods": 'PUT', 'data': this.userinfo});
this.changeQQValue() this.changeQQValue()
}, },
savePositionValue(){ savePositionValue() {
this.updateUserInfo({"methods":'PUT','data':this.userinfo}); this.updateUserInfo({"methods": 'PUT', 'data': this.userinfo});
this.changePositionValue() this.changePositionValue()
}, },
savePhone(){ savePhone() {
this.updateUserInfo({"methods":'PUT','data':this.userinfo}); this.updateUserInfo({"methods": 'PUT', 'data': this.userinfo});
this.changePhoneValue() this.changePhoneValue()
}, },
updateUserInfo(datainfo){ updateUserInfo(datainfo) {
userinfos(data=>{ userinfos(data => {
if(data.code === 1000){ if (data.code === 1000) {
this.userinfo = data.data; this.userinfo = data.data;
this.$store.dispatch("getUser",data.data); this.$store.dispatch("getUser", data.data);
if(data.data.sms_code){ if (data.data.sms_code) {
this.$notify({ this.$notify({
title: '验证码', title: '验证码',
message: '您正在修改手机号码,验证码为:'+data.data.sms_code, message: '您正在修改手机号码,验证码为:' + data.data.sms_code,
type: 'success' type: 'success'
}); });
} }
if(datainfo.data){ if (datainfo.data) {
this.$message.success("更新成功") this.$message.success("更新成功")
} }
}else { } else {
this.$message.error("更新失败") this.$message.error("更新失败")
} }
},datainfo) }, datainfo)
}, },
changePhoneValue() { changePhoneValue() {
this.editphone = !this.editphone; this.editphone = !this.editphone;
@ -159,7 +162,7 @@
} }
}, },
getphonecode() { getphonecode() {
this.updateUserInfo({"methods":'GET','data':{'act':'sms'}}); this.updateUserInfo({"methods": 'GET', 'data': {'act': 'sms'}});
} }
}, mounted() { }, mounted() {
@ -167,8 +170,8 @@
// this.updateUserInfo({"methods":false}); // this.updateUserInfo({"methods":false});
this.userinfo = this.$store.state.userinfo; this.userinfo = this.$store.state.userinfo;
},watch:{ }, watch: {
'$store.state.userinfo':function () { '$store.state.userinfo': function () {
this.userinfo = this.$store.state.userinfo; this.userinfo = this.$store.state.userinfo;
} }
} }

@ -1,56 +1,58 @@
<template> <template>
<div style="text-align:center"> <div style="text-align:center">
<h2 v-if="is_admin_storage">管理员存储您配置的存储将决定其他用户配置的默认存储请谨慎修改</h2> <h2 v-if="is_admin_storage">管理员存储您配置的存储将决定其他用户配置的默认存储请谨慎修改</h2>
<el-dialog :title="title" :visible.sync="dialogstorageVisible" :destroy-on-close="true" :close-on-click-modal="false"> <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" <el-form v-if="editstorageinfo.id !==-1" ref="storageinfoform" :model="editstorageinfo"
label-width="80px" style="margin:0 auto;"> label-width="80px" style="margin:0 auto;">
<el-form-item label-width="100px" label="存储类型"> <el-form-item label-width="100px" label="存储类型">
<el-select :disabled='disabled' v-model="editstorageinfo.storage_type" placeholder="存储类型" <el-select :disabled='disabled' v-model="editstorageinfo.storage_type" placeholder="存储类型"
style="margin-left: -100px"> style="margin-left: -100px">
<el-option v-for="st in storage_list" :key="st.id" :label="st.name" :value="st.id"></el-option> <el-option v-for="st in storage_list" :key="st.id" :label="st.name" :value="st.id"></el-option>
</el-select> </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>
<el-form-item label-width="110px" label="bucket_name"> <div v-if="editstorageinfo.storage_type">
<el-input :disabled='disabled' v-model="editstorageinfo.bucket_name"></el-input> <el-form-item label-width="110px" label="存储名称">
</el-form-item> <el-input :disabled='disabled' v-model="editstorageinfo.name"></el-input>
<el-form-item label-width="110px" label="下载域名"> </el-form-item>
<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="key">
<el-form-item label-width="110px" label="sts_role_arn"> <el-input :disabled='disabled' v-model="editstorageinfo.access_key"></el-input>
<el-input :disabled='disabled' </el-form-item>
v-model="editstorageinfo.additionalparameter.sts_role_arn"></el-input> <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>
<el-form-item label-width="110px" label="endpoint"> <el-form-item label-width="110px" label="bucket_name">
<el-input :disabled='disabled' v-model="editstorageinfo.additionalparameter.endpoint"></el-input> <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> </el-form-item>
</div> <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="备注"> <el-form-item label-width="110px" label="endpoint">
<el-input :disabled='disabled' v-model="editstorageinfo.description"></el-input> <el-input :disabled='disabled'
</el-form-item> 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="updateorcreate">保存</el-button>
<el-button v-if="!disabled" @click="dialogstorageVisible=false">取消</el-button> <el-button v-if="!disabled" @click="dialogstorageVisible=false">取消</el-button>
</div> </div>
</el-form> </el-form>
</el-dialog> </el-dialog>
@ -71,20 +73,23 @@
</el-option> </el-option>
</el-option-group> </el-option-group>
</el-select> </el-select>
<el-button style="margin-left: 10px" round type="info" icon="el-icon-thumb" @click="change_storage_info">保存</el-button> <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-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-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-plus" @click="add_storage_info"></el-button>-->
<!-- <el-button round type="info" icon="el-icon-delete" @click="del_storage_info"></el-button>--> <!-- <el-button round type="info" icon="el-icon-delete" @click="del_storage_info"></el-button>-->
<!-- </el-button-group>--> <!-- </el-button-group>-->
<el-divider></el-divider> <el-divider></el-divider>
<el-form v-if="storageinfo.id && storageinfo.id !==-1" ref="storageinfoform" :model="storageinfo" <el-form v-if="storageinfo.id && storageinfo.id !==-1" ref="storageinfoform" :model="storageinfo"
label-width="80px" style="width: 39%;margin:0 auto;"> label-width="80px" style="width: 39%;margin:0 auto;">
<el-form-item label-width="110px" label="存储类型"> <el-form-item label-width="110px" label="存储类型">
<el-select :disabled='Sdisabled' v-model="storageinfo.storage_type" placeholder="存储类型" <el-select :disabled='Sdisabled' v-model="storageinfo.storage_type" placeholder="存储类型"
style="margin-left: -60px"> style="margin-left: -60px">
<el-option v-for="st in storage_list" :key="st.id" :label="st.name" :value="st.id"></el-option> <el-option v-for="st in storage_list" :key="st.id" :label="st.name"
:value="st.id"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -115,7 +120,8 @@
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="endpoint"> <el-form-item label-width="110px" label="endpoint">
<el-input :disabled='Sdisabled' v-model="storageinfo.additionalparameter.endpoint"></el-input> <el-input :disabled='Sdisabled'
v-model="storageinfo.additionalparameter.endpoint"></el-input>
</el-form-item> </el-form-item>
<el-form-item label-width="110px" label="备注"> <el-form-item label-width="110px" label="备注">
@ -173,21 +179,23 @@
fixed="right" fixed="right"
label="操作" label="操作"
width="120"> width="120">
<template slot-scope="scope" > <template slot-scope="scope">
<div v-if="scope.row.id === org_storage_id"> <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> <el-button v-if="scope.row.id === org_storage_id" @click="showstorage(scope.row)"
type="success" size="small">使用中
</el-button>
</div> </div>
<div v-else> <div v-else>
<el-button @click="showstorage(scope.row)" type="text" size="small">查看</el-button> <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="editstorage(scope.row)" type="text" size="small">编辑</el-button>
<el-button @click="del_storage_info(scope.row)" type="text" size="small">删除</el-button> <el-button @click="del_storage_info(scope.row)" type="text" size="small">删除</el-button>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="新增存储" name="addstorage" > <el-tab-pane label="新增存储" name="addstorage">
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@ -204,12 +212,12 @@
data() { data() {
return { return {
fstorage_lists: [], fstorage_lists: [],
Sdisabled:true, Sdisabled: true,
use_storage_id: 0, use_storage_id: 0,
org_storage_id:0, org_storage_id: 0,
title:'', title: '',
dialogstorageVisible:false, dialogstorageVisible: false,
editstorageinfo:{'additionalparameter':{}}, editstorageinfo: {'additionalparameter': {}},
selectlabel: "", selectlabel: "",
storageinfo: {'additionalparameter': {}}, storageinfo: {'additionalparameter': {}},
storage_list: [], storage_list: [],
@ -217,32 +225,32 @@
isaddflag: false, isaddflag: false,
activeName: 'chostorage', activeName: 'chostorage',
storage_info_lists: [], storage_info_lists: [],
is_admin_storage:false, is_admin_storage: false,
} }
}, methods: { }, methods: {
showstorage(editstorageinfo){ showstorage(editstorageinfo) {
this.title='查看存储信息'; this.title = '查看存储信息';
this.disabled=true; this.disabled = true;
this.dialogstorageVisible=true; this.dialogstorageVisible = true;
this.editstorageinfo=deepCopy(editstorageinfo); this.editstorageinfo = deepCopy(editstorageinfo);
}, },
editstorage(editstorageinfo){ editstorage(editstorageinfo) {
this.title='存储编辑'; this.title = '存储编辑';
this.disabled=false; this.disabled = false;
this.dialogstorageVisible=true; this.dialogstorageVisible = true;
this.editstorageinfo=deepCopy(editstorageinfo); this.editstorageinfo = deepCopy(editstorageinfo);
this.isaddflag=false; this.isaddflag = false;
},add_storage_click(){ }, add_storage_click() {
this.title='新增存储'; this.title = '新增存储';
this.disabled=false; this.disabled = false;
this.dialogstorageVisible=true; this.dialogstorageVisible = true;
this.editstorageinfo={'additionalparameter':{}}; this.editstorageinfo = {'additionalparameter': {}};
this.isaddflag=true; this.isaddflag = true;
}, },
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
handleClick(tab, event) { handleClick(tab, event) {
if(tab.name === 'addstorage'){ if (tab.name === 'addstorage') {
this.add_storage_click() this.add_storage_click()
} }
}, },
@ -254,9 +262,9 @@
getStorageinfo(data => { getStorageinfo(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.$message.success('操作成功'); this.$message.success('操作成功');
this.dialogstorageVisible=false; this.dialogstorageVisible = false;
if (this.isaddflag) { if (this.isaddflag) {
this.activeName='setstorage'; this.activeName = 'setstorage';
} }
this.getstorageinfoFun(); this.getstorageinfoFun();
@ -271,11 +279,11 @@
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
getStorageinfo(data => { getStorageinfo(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.$message.success('删除成功'); this.$message.success('删除成功');
this.getstorageinfoFun(); this.getstorageinfoFun();
} }
}, {"methods": 'DELETE', 'data': {'id': sinfo.id, 'tid': sinfo.storage_type}}) }, {"methods": 'DELETE', 'data': {'id': sinfo.id, 'tid': sinfo.storage_type}})
}).catch(() => { }).catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',
@ -285,24 +293,24 @@
}, },
change_storage_info() { change_storage_info() {
this.$confirm('此操作将导致应用,图片,显示下载异常, 是否继续?', '警告', { this.$confirm('此操作将导致应用,图片,显示下载异常, 是否继续?', '警告', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
getStorageinfo(data => { getStorageinfo(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.$message.success('修改成功'); this.$message.success('修改成功');
this.getstorageinfoFun(); this.getstorageinfoFun();
} }
}, {"methods": 'PUT', 'data': {'use_storage_id':this.use_storage_id}}); }, {"methods": 'PUT', 'data': {'use_storage_id': this.use_storage_id}});
this.getstorageinfoFun(); this.getstorageinfoFun();
}).catch(() => { }).catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',
message: '已取消操作' message: '已取消操作'
});
}); });
});
}, },
select_storage(a) { select_storage(a) {
this.disabled = true; this.disabled = true;
@ -357,13 +365,13 @@
getstorageinfoFun() { getstorageinfoFun() {
getStorageinfo(data => { getStorageinfo(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.org_storage_id=this.use_storage_id = data.storage; this.org_storage_id = this.use_storage_id = data.storage;
this.storage_list = data.storage_list; this.storage_list = data.storage_list;
this.storage_info_lists = data.data; this.storage_info_lists = data.data;
this.is_admin_storage = data.is_admin_storage; this.is_admin_storage = data.is_admin_storage;
this.format_storage(data.data); this.format_storage(data.data);
this.disabled=true; this.disabled = true;
this.isaddflag=false; this.isaddflag = false;
} else { } else {
this.$message.error('存储获取失败,' + data); this.$message.error('存储获取失败,' + data);
} }

@ -4,6 +4,7 @@ import router from "@/router";
import ElementUI from 'element-ui' import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css' import 'element-ui/lib/theme-chalk/index.css'
import Vuex from 'vuex' import Vuex from 'vuex'
const qiniu = require('qiniu-js'); const qiniu = require('qiniu-js');
Vue.prototype.qiniu = qiniu; Vue.prototype.qiniu = qiniu;

@ -1,6 +1,7 @@
import Axios from 'axios' import Axios from 'axios'
import VueCookies from 'vue-cookies' import VueCookies from 'vue-cookies'
import router from "../router"; import router from "../router";
const https = require('https'); const https = require('https');
const Base64 = require('js-base64').Base64; const Base64 = require('js-base64').Base64;
Axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; Axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
@ -11,8 +12,10 @@ Axios.defaults.httpsAgent = new https.Agent({
const DOMAIN = 'https://fly.harmonygames.cn'; const DOMAIN = 'https://fly.harmonygames.cn';
const APIPATH='/api/v1/fir/server'; // const DOMAIN = 'https://testapp.harmonygames.cn';
let USERSEVER = DOMAIN+APIPATH; // const DOMAIN = 'http://172.16.133.34:8000';
const APIPATH = '/api/v1/fir/server';
let USERSEVER = DOMAIN + APIPATH;
export function set_auth_token() { export function set_auth_token() {
@ -41,11 +44,64 @@ export function set_auth_token() {
set_auth_token(); set_auth_token();
function ErrorMsg(error) {
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误(400)';
break;
case 401:
error.message = '未授权,请重新登录(401)';
break;
case 403:
error.message = '拒绝访问(403)';
break;
case 404:
error.message = '请求出错(404)';
break;
case 408:
error.message = '请求超时(408)';
break;
case 500:
error.message = '服务器错误(500)';
break;
case 501:
error.message = '服务未实现(501)';
break;
case 502:
error.message = '网络错误(502)';
break;
case 503:
error.message = '服务不可用(503)';
break;
case 504:
error.message = '网络超时(504)';
break;
case 505:
error.message = 'HTTP版本不受支持(505)';
break;
default:
error.message = `连接出错(${error.response.status})!`;
}
} else {
error.message = '连接服务器失败!';
}
if (error.response && error.response.status === 403) {
router.push({name: 'FirLogin'});
}
if (error.message === 'Network Error') {
alert('网络连接失败');
} else {
alert(error)
}
}
function getData(methods = true, url, params = {}, callBack, load, isCode = false) { function getData(methods = true, url, params = {}, callBack, load, isCode = false) {
if (methods === "DELETE") { if (methods === "DELETE") {
Axios Axios
.delete(url, {params:params}) .delete(url, {params: params})
.then(function (response) { .then(function (response) {
if (isCode) { if (isCode) {
callBack(response.data); callBack(response.data);
@ -54,58 +110,11 @@ function getData(methods = true, url, params = {}, callBack, load, isCode = fals
} }
}) })
.catch(function (error) { .catch(function (error) {
ErrorMsg(error);
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误(400)';
break;
case 401:
error.message = '未授权,请重新登录(401)';
break;
case 403:
error.message = '拒绝访问(403)';
break;
case 404:
error.message = '请求出错(404)';
break;
case 408:
error.message = '请求超时(408)';
break;
case 500:
error.message = '服务器错误(500)';
break;
case 501:
error.message = '服务未实现(501)';
break;
case 502:
error.message = '网络错误(502)';
break;
case 503:
error.message = '服务不可用(503)';
break;
case 504:
error.message = '网络超时(504)';
break;
case 505:
error.message = 'HTTP版本不受支持(505)';
break;
default:
error.message = `连接出错(${error.response.status})!`;
}
} else {
error.message = '连接服务器失败!';
}
if (error.message === 'Network Error') {
alert('网络连接失败');
} else {
alert(error)
}
callBack(null); callBack(null);
}); });
} } else if (methods === "PUT") {
else if (methods === "PUT") {
Axios Axios
.put(url, params) .put(url, params)
.then(function (response) { .then(function (response) {
@ -116,16 +125,11 @@ function getData(methods = true, url, params = {}, callBack, load, isCode = fals
} }
}) })
.catch(function (error) { .catch(function (error) {
// eslint-disable-next-line no-console ErrorMsg(error);
console.log(error, error.response);
callBack(null); callBack(null);
}); });
} } else if (methods === 'POST') {
else if (methods === 'POST') {
Axios Axios
.post(url, params) .post(url, params)
.then(function (response) { .then(function (response) {
@ -137,22 +141,18 @@ function getData(methods = true, url, params = {}, callBack, load, isCode = fals
}) })
.catch(function (error) { .catch(function (error) {
// eslint-disable-next-line no-console ErrorMsg(error);
console.log(error, error.response);
callBack(null); callBack(null);
}); });
} else { } else {
Axios Axios
.get(url, {params: params}) .get(url, {params: params})
.then(function (response) { .then(function (response) {
callBack(response.data); callBack(response.data);
}) })
.catch(function (error) { .catch(function (error) {
// eslint-disable-next-line no-console ErrorMsg(error);
console.log(error, error.response);
if(error.response && error.response.status === 403){
router.push({name: 'FirLogin'});
}
callBack(null); callBack(null);
}); });
} }
@ -304,7 +304,7 @@ export function getapptimeline(callBack, params, load = true) {
export function getShortAppinfo(callBack, params, load = true) { export function getShortAppinfo(callBack, params, load = true) {
getData( getData(
'GET', 'GET',
USERSEVER + '/short/' + params.short , USERSEVER + '/short/' + params.short,
params, params,
data => { data => {
callBack(data); callBack(data);
@ -319,7 +319,7 @@ export function getShortAppinfo(callBack, params, load = true) {
export function getStorageinfo(callBack, params, load = true) { export function getStorageinfo(callBack, params, load = true) {
getData( getData(
params.methods, params.methods,
USERSEVER + '/storage' , USERSEVER + '/storage',
params.data, params.data,
data => { data => {
callBack(data); callBack(data);
@ -347,8 +347,9 @@ export function userinfos(callBack, params, load = true) {
} }
export function getuserpicurl() { export function getuserpicurl() {
return USERSEVER+ '/userinfo' return USERSEVER + '/userinfo'
} }
export function getapppicurl(app_id) { export function getapppicurl(app_id) {
return USERSEVER + '/apps/' + app_id return USERSEVER + '/apps/' + app_id
} }
@ -362,7 +363,7 @@ export function getuploadurl() {
export function analyseApps(callBack, params, load = true) { export function analyseApps(callBack, params, load = true) {
getData( getData(
params.methods, params.methods,
USERSEVER + '/analyse' , USERSEVER + '/analyse',
params.data, params.data,
data => { data => {
callBack(data); callBack(data);
@ -378,7 +379,7 @@ export function analyseApps(callBack, params, load = true) {
export function getdownloadurl(callBack, params, load = true) { export function getdownloadurl(callBack, params, load = true) {
getData( getData(
'GET', 'GET',
USERSEVER + '/install/'+params.app_id , USERSEVER + '/install/' + params.app_id,
params.data, params.data,
data => { data => {
callBack(data); callBack(data);
@ -390,22 +391,22 @@ export function getdownloadurl(callBack, params, load = true) {
} }
/**上传文件到服务器 */ /**上传文件到服务器 */
export function uploadstorage(certinfo,file,successCallback,processCallback) { export function uploadstorage(certinfo, file, successCallback, processCallback) {
let config = { let config = {
onUploadProgress: function (progressEvent) { onUploadProgress: function (progressEvent) {
let total=progressEvent.total; let total = progressEvent.total;
let loaded = progressEvent.loaded; let loaded = progressEvent.loaded;
processCallback(Math.round(loaded*100/total)) processCallback(Math.round(loaded * 100 / total))
}, },
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
'Authorization':VueCookies.get('auth_token'), 'Authorization': VueCookies.get('auth_token'),
}, },
}; };
const data = new FormData(); const data = new FormData();
data.append('file', file); data.append('file', file);
data.append('certinfo',JSON.stringify(certinfo)); data.append('certinfo', JSON.stringify(certinfo));
Axios.post(certinfo.upload_url, data, config).then(res => { Axios.post(certinfo.upload_url, data, config).then(res => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(res); console.log(res);

@ -31,7 +31,7 @@ import FirUserProfileStorage from "@/components/FirUserProfileStorage";
import FirSuperSignBase from "@/components/FirSuperSignBase"; import FirSuperSignBase from "@/components/FirSuperSignBase";
const router = new VueRouter({ const router = new VueRouter({
mode:'history', mode: 'history',
routes: [ routes: [
{ {
path: '/', path: '/',
@ -127,7 +127,7 @@ const router = new VueRouter({
name: 'FirSuperSignBase', name: 'FirSuperSignBase',
component: FirSuperSignBase, component: FirSuperSignBase,
} }
] ]
}, },
{ {
path: '/register', path: '/register',

@ -1,11 +1,11 @@
//滚动条在Y轴上的滚动距离 //滚动条在Y轴上的滚动距离
export function getScrollTop(){ export function getScrollTop() {
let scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0; let scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0;
if(document.body){ if (document.body) {
bodyScrollTop = document.body.scrollTop; bodyScrollTop = document.body.scrollTop;
} }
if(document.documentElement){ if (document.documentElement) {
documentScrollTop = document.documentElement.scrollTop; documentScrollTop = document.documentElement.scrollTop;
} }
scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop; scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;
@ -14,14 +14,13 @@ export function getScrollTop(){
} }
//文档的总高度 //文档的总高度
export function getScrollHeight(){ export function getScrollHeight() {
let scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0; let scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;
if(document.body){ if (document.body) {
bodyScrollHeight = document.body.scrollHeight; bodyScrollHeight = document.body.scrollHeight;
} }
if(document.documentElement){ if (document.documentElement) {
documentScrollHeight = document.documentElement.scrollHeight; documentScrollHeight = document.documentElement.scrollHeight;
} }
scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight; scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
@ -30,49 +29,49 @@ export function getScrollHeight(){
//浏览器视口的高度 //浏览器视口的高度
export function getWindowHeight(){ export function getWindowHeight() {
let windowHeight = 0; let windowHeight = 0;
if(document.compatMode === "CSS1Compat"){ if (document.compatMode === "CSS1Compat") {
windowHeight = document.documentElement.clientHeight; windowHeight = document.documentElement.clientHeight;
}else{ } else {
windowHeight = document.body.clientHeight; windowHeight = document.body.clientHeight;
} }
return windowHeight; return windowHeight;
} }
export function getappinfo(file,successcallback,errcallback) { export function getappinfo(file, successcallback, errcallback) {
const AppInfoParser = require('app-info-parser'); const AppInfoParser = require('app-info-parser');
const parser = new AppInfoParser(file); const parser = new AppInfoParser(file);
let analyseappinfo={}; let analyseappinfo = {};
parser.parse().then(result => { parser.parse().then(result => {
analyseappinfo.icon = result.icon; analyseappinfo.icon = result.icon;
analyseappinfo.filename = file.name; analyseappinfo.filename = file.name;
analyseappinfo.filesize = file.size; analyseappinfo.filesize = file.size;
if(result.CFBundleDisplayName){ if (result.CFBundleDisplayName) {
analyseappinfo.appname = result.CFBundleDisplayName; analyseappinfo.appname = result.CFBundleDisplayName;
analyseappinfo.bundleid = result.CFBundleIdentifier; analyseappinfo.bundleid = result.CFBundleIdentifier;
analyseappinfo.version = result.CFBundleShortVersionString; analyseappinfo.version = result.CFBundleShortVersionString;
analyseappinfo.buildversion = result.CFBundleVersion; analyseappinfo.buildversion = result.CFBundleVersion;
analyseappinfo.miniosversion = result.MinimumOSVersion; analyseappinfo.miniosversion = result.MinimumOSVersion;
if(result.mobileProvision.ProvisionedDevices){ if (result.mobileProvision.ProvisionedDevices) {
analyseappinfo.release_type='Adhoc'; analyseappinfo.release_type = 'Adhoc';
analyseappinfo.release_type_id=1; analyseappinfo.release_type_id = 1;
analyseappinfo.udid=result.mobileProvision.ProvisionedDevices; analyseappinfo.udid = result.mobileProvision.ProvisionedDevices;
}else { } else {
analyseappinfo.release_type='Inhouse'; analyseappinfo.release_type = 'Inhouse';
analyseappinfo.release_type_id=2; analyseappinfo.release_type_id = 2;
analyseappinfo.udid=[]; analyseappinfo.udid = [];
} }
analyseappinfo.type = 'iOS'; analyseappinfo.type = 'iOS';
}else { } else {
analyseappinfo.appname = result.application.label[0]; analyseappinfo.appname = result.application.label[0];
analyseappinfo.bundleid = result.package; analyseappinfo.bundleid = result.package;
analyseappinfo.version = result.versionName; analyseappinfo.version = result.versionName;
analyseappinfo.buildversion = result.versionCode; analyseappinfo.buildversion = result.versionCode;
analyseappinfo.miniosversion = result.usesSdk.minSdkVersion; analyseappinfo.miniosversion = result.usesSdk.minSdkVersion;
analyseappinfo.type = 'Android'; analyseappinfo.type = 'Android';
analyseappinfo.release_type = 'Android'; analyseappinfo.release_type = 'Android';
analyseappinfo.release_type_id=0; analyseappinfo.release_type_id = 0;
} }
successcallback(analyseappinfo) successcallback(analyseappinfo)
@ -82,23 +81,23 @@ export function getappinfo(file,successcallback,errcallback) {
}); });
} }
export function uploadqiniuoss(file,certinfo,app,successcallback,processcallback){ export function uploadqiniuoss(file, certinfo, app, successcallback, processcallback) {
// let app = this; // let app = this;
// let file=this.currentfile; // let file=this.currentfile;
let observer = { let observer = {
next(res){ next(res) {
processcallback(Math.round(res.total.percent)); processcallback(Math.round(res.total.percent));
}, },
error(err){ error(err) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(err); console.log(err);
app.$message({ app.$message({
message:file.name + '上传失败,请刷新页面重试', message: file.name + '上传失败,请刷新页面重试',
type: 'error', type: 'error',
duration:0 duration: 0
}); });
}, },
complete(res){ complete(res) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log(res); // console.log(res);
successcallback(res); successcallback(res);
@ -109,7 +108,7 @@ export function uploadqiniuoss(file,certinfo,app,successcallback,processcallback
params: {}, params: {},
// mimeType: ["image/png"] // mimeType: ["image/png"]
}; };
let config={}; let config = {};
let observable = app.qiniu.upload(file, certinfo.upload_key, certinfo.upload_token, putExtra, config); let observable = app.qiniu.upload(file, certinfo.upload_key, certinfo.upload_token, putExtra, config);
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
let subscription = observable.subscribe(observer) // 上传开始 let subscription = observable.subscribe(observer) // 上传开始
@ -119,13 +118,13 @@ export function uploadqiniuoss(file,certinfo,app,successcallback,processcallback
export function dataURLtoFile(dataurl, filename) {//将base64转换为文件 export function dataURLtoFile(dataurl, filename) {//将base64转换为文件
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){ while (n--) {
u8arr[n] = bstr.charCodeAt(n); u8arr[n] = bstr.charCodeAt(n);
} }
return new File([u8arr], filename, {type:mime}); return new File([u8arr], filename, {type: mime});
} }
export function uploadaliyunoss(file,certinfo,app,successcallback,processcallback) { export function uploadaliyunoss(file, certinfo, app, successcallback, processcallback) {
const OSS = require('ali-oss'); const OSS = require('ali-oss');
let token = certinfo.upload_token; let token = certinfo.upload_token;
let client = new OSS({ let client = new OSS({
@ -155,26 +154,27 @@ export function uploadaliyunoss(file,certinfo,app,successcallback,processcallbac
// people: 'test', // people: 'test',
// }, // },
}; };
client.multipartUpload(certinfo.upload_key, file, options).then( (res) => { client.multipartUpload(certinfo.upload_key, file, options).then((res) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('upload success: %j', res); console.log('upload success: %j', res);
successcallback(res); successcallback(res);
currentCheckpoint = null; currentCheckpoint = null;
}).catch((err) => { }).catch((err) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(err); console.error(err);
app.$message({ app.$message({
message:file.name + '上传失败,请刷新页面重试', message: file.name + '上传失败,请刷新页面重试',
type: 'error', type: 'error',
duration:0 duration: 0
}); });
}); });
} }
import {uploadstorage} from '../restful' import {uploadstorage} from '../restful'
export function uploadlocalstorage(file,certinfo,app,successcallback,processcallback) {
uploadstorage(certinfo,file,successcallback,processcallback) export function uploadlocalstorage(file, certinfo, app, successcallback, processcallback) {
uploadstorage(certinfo, file, successcallback, processcallback)
} }
@ -185,12 +185,10 @@ export function removeAaary(_arr, _obj) {
if (i == 0) { if (i == 0) {
_arr.shift(); //删除并返回数组的第一个元素 _arr.shift(); //删除并返回数组的第一个元素
return _arr; return _arr;
} } else if (i == length - 1) {
else if (i == length - 1) {
_arr.pop(); //删除并返回数组的最后一个元素 _arr.pop(); //删除并返回数组的最后一个元素
return _arr; return _arr;
} } else {
else {
_arr.splice(i, 1); //删除下标为i的元素 _arr.splice(i, 1); //删除下标为i的元素
return _arr; return _arr;
} }
@ -200,19 +198,19 @@ export function removeAaary(_arr, _obj) {
//深拷贝 //深拷贝
export function deepCopy(source) { export function deepCopy(source) {
let result={}; let result = {};
for (let key in source) { for (let key in source) {
result[key] = typeof source[key]==='object'? deepCopy(source[key]): source[key]; result[key] = typeof source[key] === 'object' ? deepCopy(source[key]) : source[key];
} }
return result; return result;
} }
export function IsNum(s){ export function IsNum(s) {
if(s!=null){ if (s != null) {
var r,re; var r, re;
re = /\d*/i; //\d表示数字,*表示匹配多个数字 re = /\d*/i; //\d表示数字,*表示匹配多个数字
r = s.match(re); r = s.match(re);
return (r==s)?true:false; return (r == s) ? true : false;
} }
return false; return false;
} }

@ -3,7 +3,6 @@ from django.contrib import admin
# Register your models here. # Register your models here.
from .models import * from .models import *
admin.site.register(UserInfo) admin.site.register(UserInfo)
admin.site.register(Apps) admin.site.register(Apps)
admin.site.register(AppReleaseInfo) admin.site.register(AppReleaseInfo)
@ -15,4 +14,3 @@ admin.site.register(AppIOSDeveloperInfo)
admin.site.register(APPSuperSignUsedInfo) admin.site.register(APPSuperSignUsedInfo)
admin.site.register(APPToDeveloper) admin.site.register(APPToDeveloper)
admin.site.register(UDIDsyncDeveloper) admin.site.register(UDIDsyncDeveloper)

@ -7,7 +7,6 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -21,28 +20,39 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')), ('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('is_superuser', models.BooleanField(default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
verbose_name='superuser status')),
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ('is_staff', models.BooleanField(default=False,
help_text='Designates whether the user can log into this admin site.',
verbose_name='staff status')),
('username', models.CharField(max_length=64, unique=True, verbose_name='用户名')), ('username', models.CharField(max_length=64, unique=True, verbose_name='用户名')),
('email', models.EmailField(blank=True, max_length=255, null=True, unique=True, verbose_name='email address')), ('email',
models.EmailField(blank=True, max_length=255, null=True, unique=True, verbose_name='email address')),
('uid', models.CharField(db_index=True, max_length=64, unique=True)), ('uid', models.CharField(db_index=True, max_length=64, unique=True)),
('mobile', models.BigIntegerField(help_text='用于手机验证码登录', null=True, unique=True, verbose_name='手机')), ('mobile', models.BigIntegerField(help_text='用于手机验证码登录', null=True, unique=True, verbose_name='手机')),
('qq', models.BigIntegerField(blank=True, db_index=True, null=True, verbose_name='QQ')), ('qq', models.BigIntegerField(blank=True, db_index=True, null=True, verbose_name='QQ')),
('is_active', models.BooleanField(default=True, verbose_name='账户状态,默认启用')), ('is_active', models.BooleanField(default=True, verbose_name='账户状态,默认启用')),
('job', models.TextField(blank=True, max_length=128, null=True, verbose_name='职位')), ('job', models.TextField(blank=True, max_length=128, null=True, verbose_name='职位')),
('company', models.CharField(blank=True, max_length=128, null=True, verbose_name='公司')), ('company', models.CharField(blank=True, max_length=128, null=True, verbose_name='公司')),
('gender', models.SmallIntegerField(choices=[(0, '保密'), (1, ''), (2, '')], default=0, verbose_name='性别')), ('gender',
models.SmallIntegerField(choices=[(0, '保密'), (1, ''), (2, '')], default=0, verbose_name='性别')),
('head_img', models.CharField(default='head_img.jpeg', max_length=256, verbose_name='个人头像')), ('head_img', models.CharField(default='head_img.jpeg', max_length=256, verbose_name='个人头像')),
('role', models.SmallIntegerField(choices=[(0, '普通会员'), (1, 'VIP'), (2, 'SVIP'), (3, '管理员')], default=0, verbose_name='角色')), ('role', models.SmallIntegerField(choices=[(0, '普通会员'), (1, 'VIP'), (2, 'SVIP'), (3, '管理员')], default=0,
verbose_name='角色')),
('memo', models.TextField(blank=True, default=None, null=True, verbose_name='备注')), ('memo', models.TextField(blank=True, default=None, null=True, verbose_name='备注')),
('date_joined', models.DateTimeField(auto_now_add=True, verbose_name='注册时间')), ('date_joined', models.DateTimeField(auto_now_add=True, verbose_name='注册时间')),
('download_times', models.IntegerField(default=100, verbose_name='下载次数')), ('download_times', models.IntegerField(default=100, verbose_name='下载次数')),
('all_download_times', models.BigIntegerField(default=0, verbose_name='总共下载次数')), ('all_download_times', models.BigIntegerField(default=0, verbose_name='总共下载次数')),
('domain_name', models.CharField(blank=True, max_length=64, null=True, verbose_name='域名')), ('domain_name', models.CharField(blank=True, max_length=64, null=True, verbose_name='域名')),
('history_release_limit', models.IntegerField(blank=True, default=10, null=True, verbose_name='app 历史记录版本')), ('history_release_limit',
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), models.IntegerField(blank=True, default=10, null=True, verbose_name='app 历史记录版本')),
('groups', models.ManyToManyField(blank=True,
help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.',
related_name='user_set', related_query_name='user', to='auth.Group',
verbose_name='groups')),
], ],
options={ options={
'verbose_name': '账户信息', 'verbose_name': '账户信息',
@ -57,7 +67,8 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64, unique=True, verbose_name='开发者标识')), ('name', models.CharField(max_length=64, unique=True, verbose_name='开发者标识')),
('email', models.EmailField(blank=True, max_length=64, null=True, unique=True, verbose_name='email address')), ('email',
models.EmailField(blank=True, max_length=64, null=True, unique=True, verbose_name='email address')),
('password', models.CharField(max_length=64)), ('password', models.CharField(max_length=64)),
('is_actived', models.BooleanField(default=False, verbose_name='是否已经激活')), ('is_actived', models.BooleanField(default=False, verbose_name='是否已经激活')),
('certid', models.CharField(blank=True, max_length=64, null=True, verbose_name='超级签名自动创建证书ID')), ('certid', models.CharField(blank=True, max_length=64, null=True, verbose_name='超级签名自动创建证书ID')),
@ -66,7 +77,8 @@ class Migration(migrations.Migration):
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('description', models.TextField(blank=True, default='', null=True, verbose_name='备注')), ('description', models.TextField(blank=True, default='', null=True, verbose_name='备注')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')), ('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL,
verbose_name='用户ID')),
], ],
options={ options={
'verbose_name': '苹果开发者账户', 'verbose_name': '苹果开发者账户',
@ -89,8 +101,10 @@ class Migration(migrations.Migration):
('issupersign', models.BigIntegerField(default=False, verbose_name='是否超级签名包')), ('issupersign', models.BigIntegerField(default=False, verbose_name='是否超级签名包')),
('description', models.TextField(blank=True, default=None, null=True, verbose_name='描述')), ('description', models.TextField(blank=True, default=None, null=True, verbose_name='描述')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('has_combo', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='combo_app_info', to='api.Apps', verbose_name='关联应用')), ('has_combo', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')), related_name='combo_app_info', to='api.Apps', verbose_name='关联应用')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL,
verbose_name='用户ID')),
], ],
options={ options={
'verbose_name': '应用信息', 'verbose_name': '应用信息',
@ -106,7 +120,8 @@ class Migration(migrations.Migration):
('address', models.CharField(blank=True, max_length=128, null=True, verbose_name='联系地址')), ('address', models.CharField(blank=True, max_length=128, null=True, verbose_name='联系地址')),
('mobile', models.BigIntegerField(blank=True, null=True, verbose_name='联系电话')), ('mobile', models.BigIntegerField(blank=True, null=True, verbose_name='联系电话')),
('date_verify', models.DateTimeField(auto_now_add=True, verbose_name='认证时间')), ('date_verify', models.DateTimeField(auto_now_add=True, verbose_name='认证时间')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='verify_info', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='verify_info',
to=settings.AUTH_USER_MODEL, verbose_name='关联用户')),
], ],
options={ options={
'verbose_name': '实名认证', 'verbose_name': '实名认证',
@ -119,7 +134,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('access_token', models.CharField(max_length=64, unique=True)), ('access_token', models.CharField(max_length=64, unique=True)),
('created', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('created', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token',
to=settings.AUTH_USER_MODEL, verbose_name='关联用户')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -136,7 +152,8 @@ class Migration(migrations.Migration):
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('is_signed', models.BooleanField(default=False, verbose_name='是否完成签名打包')), ('is_signed', models.BooleanField(default=False, verbose_name='是否完成签名打包')),
('binary_file', models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称')), ('binary_file', models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')), ('app_id',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
], ],
options={ options={
'verbose_name': '设备详情', 'verbose_name': '设备详情',
@ -150,10 +167,15 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')), ('app_id',
('developerid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo', verbose_name='所使用苹果开发者账户')), models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
('udid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppUDID', verbose_name='所消耗的udid')), ('developerid',
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')), models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo',
verbose_name='所使用苹果开发者账户')),
('udid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppUDID',
verbose_name='所消耗的udid')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL,
verbose_name='用户ID')),
], ],
options={ options={
'verbose_name': '设备使用统计', 'verbose_name': '设备使用统计',
@ -165,17 +187,26 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=64, null=True, verbose_name='存储名字')), ('name', models.CharField(blank=True, max_length=64, null=True, verbose_name='存储名字')),
('storage_type', models.SmallIntegerField(choices=[(0, '本地存储'), (1, '七牛云存储'), (2, '阿里云存储'), (3, '默认存储')], default=3, verbose_name='存储类型')), ('storage_type',
models.SmallIntegerField(choices=[(0, '本地存储'), (1, '七牛云存储'), (2, '阿里云存储'), (3, '默认存储')], default=3,
verbose_name='存储类型')),
('access_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问key')), ('access_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问key')),
('secret_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问secret')), ('secret_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问secret')),
('bucket_name', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储空间bucket_name')), (
('domain_name', models.CharField(blank=True, help_text='fly-storage.dvcloud.xin,可以自定义端口', max_length=128, null=True, verbose_name='下载域名')), 'bucket_name',
models.CharField(blank=True, max_length=128, null=True, verbose_name='存储空间bucket_name')),
('domain_name',
models.CharField(blank=True, help_text='fly-storage.dvcloud.xin,可以自定义端口', max_length=128, null=True,
verbose_name='下载域名')),
('is_https', models.BooleanField(default=True, verbose_name='是否支持https')), ('is_https', models.BooleanField(default=True, verbose_name='是否支持https')),
('additionalparameters', models.TextField(blank=True, default=None, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ', null=True, verbose_name='额外参数')), ('additionalparameters',
models.TextField(blank=True, default=None, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ',
null=True, verbose_name='额外参数')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('description', models.TextField(blank=True, default='', null=True, verbose_name='备注')), ('description', models.TextField(blank=True, default='', null=True, verbose_name='备注')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')), ('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL,
verbose_name='用户ID')),
], ],
options={ options={
'verbose_name': '存储配置', 'verbose_name': '存储配置',
@ -187,10 +218,14 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_master', models.BooleanField(default=True, verbose_name='是否master版本')), ('is_master', models.BooleanField(default=True, verbose_name='是否master版本')),
('release_id', models.CharField(db_index=True, max_length=64, unique=True, verbose_name='release 版本id')), (
'release_id',
models.CharField(db_index=True, max_length=64, unique=True, verbose_name='release 版本id')),
('build_version', models.CharField(blank=True, max_length=16, verbose_name='build版本')), ('build_version', models.CharField(blank=True, max_length=16, verbose_name='build版本')),
('app_version', models.CharField(blank=True, max_length=16, verbose_name='app版本')), ('app_version', models.CharField(blank=True, max_length=16, verbose_name='app版本')),
('release_type', models.SmallIntegerField(choices=[(0, 'android'), (1, 'adhoc'), (2, 'Inhouse'), (3, 'unknown')], default=0, verbose_name='版本类型')), ('release_type',
models.SmallIntegerField(choices=[(0, 'android'), (1, 'adhoc'), (2, 'Inhouse'), (3, 'unknown')],
default=0, verbose_name='版本类型')),
('minimum_os_version', models.CharField(max_length=64, verbose_name='应用可安装的最低系统版本')), ('minimum_os_version', models.CharField(max_length=64, verbose_name='应用可安装的最低系统版本')),
('binary_size', models.BigIntegerField(verbose_name='应用大小')), ('binary_size', models.BigIntegerField(verbose_name='应用大小')),
('binary_url', models.CharField(blank=True, max_length=128, verbose_name='第三方下载URL')), ('binary_url', models.CharField(blank=True, max_length=128, verbose_name='第三方下载URL')),
@ -198,7 +233,8 @@ class Migration(migrations.Migration):
('changelog', models.TextField(blank=True, default=None, null=True, verbose_name='更新日志')), ('changelog', models.TextField(blank=True, default=None, null=True, verbose_name='更新日志')),
('udid', models.TextField(blank=True, default='', null=True, verbose_name='ios内测版 udid')), ('udid', models.TextField(blank=True, default='', null=True, verbose_name='ios内测版 udid')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')), ('app_id',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
], ],
options={ options={
'verbose_name': '应用详情', 'verbose_name': '应用详情',
@ -208,12 +244,15 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='userinfo', model_name='userinfo',
name='storage', name='storage',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='app_storage', to='api.AppStorage', verbose_name='存储'), field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
related_name='app_storage', to='api.AppStorage', verbose_name='存储'),
), ),
migrations.AddField( migrations.AddField(
model_name='userinfo', model_name='userinfo',
name='user_permissions', name='user_permissions',
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'), field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.',
related_name='user_set', related_query_name='user', to='auth.Permission',
verbose_name='user permissions'),
), ),
migrations.AddIndex( migrations.AddIndex(
model_name='apps', model_name='apps',

@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('api', '0001_initial'), ('api', '0001_initial'),
] ]

@ -5,7 +5,6 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('api', '0002_auto_20200503_1120'), ('api', '0002_auto_20200503_1120'),
] ]
@ -17,8 +16,11 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('binary_file', models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称')), ('binary_file', models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')), ('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')), ('app_id',
('developerid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo', verbose_name='所使用苹果开发者账户')), models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
('developerid',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo',
verbose_name='所使用苹果开发者账户')),
], ],
options={ options={
'verbose_name': '设备使用统计', 'verbose_name': '设备使用统计',

@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('api', '0003_apptodeveloper'), ('api', '0003_apptodeveloper'),
] ]

@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('api', '0004_auto_20200504_2054'), ('api', '0004_auto_20200504_2054'),
] ]

@ -5,7 +5,6 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('api', '0005_apptodeveloper_release_file'), ('api', '0005_apptodeveloper_release_file'),
] ]
@ -20,7 +19,9 @@ class Migration(migrations.Migration):
('serial', models.CharField(blank=True, max_length=64, null=True, verbose_name='序列号')), ('serial', models.CharField(blank=True, max_length=64, null=True, verbose_name='序列号')),
('version', models.CharField(blank=True, max_length=64, null=True, verbose_name='型号')), ('version', models.CharField(blank=True, max_length=64, null=True, verbose_name='型号')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('developerid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo', verbose_name='所使用苹果开发者账户')), ('developerid',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo',
verbose_name='所使用苹果开发者账户')),
], ],
options={ options={
'verbose_name': 'iOS开发平台同步设备信息', 'verbose_name': 'iOS开发平台同步设备信息',

@ -116,7 +116,7 @@ class Apps(models.Model):
indexes = [models.Index(fields=['app_id']), models.Index(fields=['id', 'user_id', 'type'])] indexes = [models.Index(fields=['app_id']), models.Index(fields=['id', 'user_id', 'type'])]
def __str__(self): def __str__(self):
return "%s %s-%s %s" % (self.name, self.get_type_display(), self.short, self.issupersign) return "%s %s-%s %s" % (self.name, self.get_type_display(), self.short, self.issupersign)
class AppReleaseInfo(models.Model): class AppReleaseInfo(models.Model):

@ -14,34 +14,33 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path,re_path,include from django.urls import path, re_path, include
from api.views.login import LoginView,UserInfoView from api.views.login import LoginView, UserInfoView
from api.views.logout import LogoutView from api.views.logout import LogoutView
from api.views.captcha import CaptchaView from api.views.captcha import CaptchaView
from api.views.apps import AppsView,AppInfoView,AppReleaseinfoView from api.views.apps import AppsView, AppInfoView, AppReleaseinfoView
from api.views.download import ShortDownloadView from api.views.download import ShortDownloadView
from api.views.uploads import AppAnalyseView,UploadView from api.views.uploads import AppAnalyseView, UploadView
from api.views.storage import StorageView from api.views.storage import StorageView
from api.views.receiveudids import IosUDIDView from api.views.receiveudids import IosUDIDView
from api.views.supersign import DeveloperView,SuperSignUsedView,AppUDIDUsedView from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView
# router=DefaultRouter() # router=DefaultRouter()
# router.register("apps", AppsView) # router.register("apps", AppsView)
urlpatterns = [ urlpatterns = [
# path("",include(router.urls)), # path("",include(router.urls)),
re_path("^login",LoginView.as_view()), re_path("^login", LoginView.as_view()),
re_path("^logout",LogoutView.as_view()), re_path("^logout", LogoutView.as_view()),
re_path("^captcha_check/",CaptchaView.as_view()), re_path("^captcha_check/", CaptchaView.as_view()),
re_path("^apps$", AppsView.as_view()), re_path("^apps$", AppsView.as_view()),
re_path("^storage$", StorageView.as_view()), re_path("^storage$", StorageView.as_view()),
re_path("^apps/(?P<app_id>\w+)", AppInfoView.as_view()), re_path("^apps/(?P<app_id>\w+)", AppInfoView.as_view()),
re_path("^appinfos/(?P<app_id>\w+)/(?P<act>\w+)", AppReleaseinfoView.as_view()), re_path("^appinfos/(?P<app_id>\w+)/(?P<act>\w+)", AppReleaseinfoView.as_view()),
re_path("^upload$",UploadView.as_view()), re_path("^upload$", UploadView.as_view()),
re_path("^userinfo",UserInfoView.as_view()), re_path("^userinfo", UserInfoView.as_view()),
re_path("^short/(?P<short>\w+)$", ShortDownloadView.as_view()), re_path("^short/(?P<short>\w+)$", ShortDownloadView.as_view()),
re_path("^udid/(?P<short>\w+)$", IosUDIDView.as_view()), re_path("^udid/(?P<short>\w+)$", IosUDIDView.as_view()),
re_path("^analyse$", AppAnalyseView.as_view()), re_path("^analyse$", AppAnalyseView.as_view()),

@ -16,10 +16,11 @@ from fir_ser.settings import CACHE_KEY_TEMPLATE
cache.set(token_obj.key, token_obj.user, min(delta.total_seconds(), 3600 * 24 * 7)) cache.set(token_obj.key, token_obj.user, min(delta.total_seconds(), 3600 * 24 * 7))
''' '''
class DownloadToken(object): class DownloadToken(object):
def make_token(self,release_id,time_limit=60,key='',force_new=False): def make_token(self, release_id, time_limit=60, key='', force_new=False):
token_key = "_".join([key.lower(), CACHE_KEY_TEMPLATE.get("make_token_key"),release_id]) token_key = "_".join([key.lower(), CACHE_KEY_TEMPLATE.get("make_token_key"), release_id])
make_token_key = cache.get(token_key) make_token_key = cache.get(token_key)
if make_token_key and not force_new: if make_token_key and not force_new:
return make_token_key return make_token_key
@ -29,16 +30,16 @@ class DownloadToken(object):
user_ran_str.extend(random_str) user_ran_str.extend(random_str)
new_str = "".join(user_ran_str) new_str = "".join(user_ran_str)
cache.set(new_str, { cache.set(new_str, {
"atime":time.time()+time_limit, "atime": time.time() + time_limit,
"data":release_id "data": release_id
}, time_limit) }, time_limit)
cache.set(token_key,new_str,time_limit-1) cache.set(token_key, new_str, time_limit - 1)
return new_str return new_str
def verify_token(self,token,release_id): def verify_token(self, token, release_id):
try: try:
values = cache.get(token) values = cache.get(token)
if values and release_id in values.get("data",None): if values and release_id in values.get("data", None):
return True return True
except Exception as e: except Exception as e:
print(e) print(e)
@ -55,8 +56,11 @@ def generateTokenForMedium(medium):
else: else:
return generateNumericTokenOfLength(6) return generateNumericTokenOfLength(6)
def generateNumericTokenOfLength(length): def generateNumericTokenOfLength(length):
return "".join([random.choice(string.digits) for _ in range(length)]) return "".join([random.choice(string.digits) for _ in range(length)])
def generateAlphanumericTokenOfLength(length): def generateAlphanumericTokenOfLength(length):
return "".join([random.choice(string.digits + string.ascii_lowercase + string.ascii_uppercase) for _ in range(length)]) return "".join(
[random.choice(string.digits + string.ascii_lowercase + string.ascii_uppercase) for _ in range(length)])

@ -20,7 +20,6 @@ logger = logging.getLogger(__name__)
class BaseAli(object): class BaseAli(object):
API_BASE_URL = "" API_BASE_URL = ""
_http = requests.session() _http = requests.session()

@ -16,7 +16,6 @@ from .yun.basic import AliYunClient
class AliApi(object): class AliApi(object):
# 默认的支付配置 # 默认的支付配置
DEFAULT_ALI_PAY_CONFIG = settings.THIRD_PART_CONFIG["ALI_PAY"]["default"] DEFAULT_ALI_PAY_CONFIG = settings.THIRD_PART_CONFIG["ALI_PAY"]["default"]
# 指定的支付配置(业务拓展) # 指定的支付配置(业务拓展)

@ -1,4 +1,3 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Date: 2018/8/2 # Date: 2018/8/2

@ -1,4 +1,3 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Date: 2018/8/2 # Date: 2018/8/2

@ -1,4 +1,3 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Date: 2018/8/2 # Date: 2018/8/2

@ -1,4 +1,3 @@
#! /usr/bin/env python #! /usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Date: 2018/8/2 # Date: 2018/8/2

@ -4,7 +4,6 @@
class BaseAliPayAPI(object): class BaseAliPayAPI(object):
""" """
支付宝支付API基类 支付宝支付API基类

@ -37,8 +37,8 @@ class AliPay(BaseAli):
order = api.AliOrder() order = api.AliOrder()
def __init__( def __init__(
self, app_id, app_private_key_path, ali_public_key_path, self, app_id, app_private_key_path, ali_public_key_path,
notify_url, return_url, debug, notify_url, return_url, debug,
): ):
# 如果是调试模式,则用调试api # 如果是调试模式,则用调试api

@ -4,7 +4,6 @@
class BaseAliYunAPI(object): class BaseAliYunAPI(object):
""" """
阿里云服务API基类 阿里云服务API基类

@ -10,7 +10,6 @@ from .base import BaseAliYunAPI
class AliYunSms(BaseAliYunAPI): class AliYunSms(BaseAliYunAPI):
VERSION = "2017-05-25" VERSION = "2017-05-25"
API_BASE_URL = "http://dysmsapi.aliyuncs.com/" API_BASE_URL = "http://dysmsapi.aliyuncs.com/"
@ -62,12 +61,12 @@ class AliYunSms(BaseAliYunAPI):
return self._get(action="SendSms", data=data) return self._get(action="SendSms", data=data)
def send_batch( def send_batch(
self, self,
phone_number_json, phone_number_json,
sign_name_json, sign_name_json,
template_code, template_code,
template_param_json, template_param_json,
sms_upextend_code_json=None, sms_upextend_code_json=None,
): ):
"""短信批量发送 """短信批量发送

@ -10,7 +10,6 @@ from .base import BaseAliYunAPI
class AliYunVod(BaseAliYunAPI): class AliYunVod(BaseAliYunAPI):
VERSION = "2017-03-21" VERSION = "2017-03-21"
API_BASE_URL = "http://vod.cn-shanghai.aliyuncs.com/" API_BASE_URL = "http://vod.cn-shanghai.aliyuncs.com/"
@ -41,8 +40,8 @@ class AliYunVod(BaseAliYunAPI):
return self._get(action="GetVideoPlayAuth", data=data) return self._get(action="GetVideoPlayAuth", data=data)
def get_play_info( def get_play_info(
self, video_id, formats=None, timeout=None, stream_type=None, definition=None, self, video_id, formats=None, timeout=None, stream_type=None, definition=None,
result_type=None, output_type=None, result_type=None, output_type=None,
): ):
"""获取播放 `auth` """获取播放 `auth`
@ -99,8 +98,8 @@ class AliYunVod(BaseAliYunAPI):
return self._get(action="GetPlayInfo", data=data) return self._get(action="GetPlayInfo", data=data)
def query_flow_data( def query_flow_data(
self, domain_name=None, start_time=None, end_time=None, time_merge=None, interval=None, self, domain_name=None, start_time=None, end_time=None, time_merge=None, interval=None,
location_name_en=None, isp_name_en=None, location_name_en=None, isp_name_en=None,
): ):
"""查询流量数据 """查询流量数据
@ -156,8 +155,8 @@ class AliYunVod(BaseAliYunAPI):
return self._get(action="DescribeDomainFlowData", data=data) return self._get(action="DescribeDomainFlowData", data=data)
def query_bps_data( def query_bps_data(
self, domain_name=None, start_time=None, end_time=None, time_merge=None, interval=None, self, domain_name=None, start_time=None, end_time=None, time_merge=None, interval=None,
location_name_en=None, isp_name_en=None, location_name_en=None, isp_name_en=None,
): ):
"""查询网络带宽 """查询网络带宽

@ -17,7 +17,6 @@ from ..tools import get_iso_8061_date
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
QUERY_STRING = None QUERY_STRING = None
@ -33,7 +32,7 @@ def _get_signature(string_to_sign, secret, signer=hmac):
def __pop_standard_urlencode(query): def __pop_standard_urlencode(query):
ret = "" ret = ""
for item in query: for item in query:
if not item[1]: if not item[1]:
continue continue
@ -66,7 +65,6 @@ def _is_api_endpoint(instance):
class AliYunClient(BaseAli): class AliYunClient(BaseAli):
VERSION = "" # 每个接口都需要版本号 VERSION = "" # 每个接口都需要版本号
API_BASE_URL = "" # 阿里云api网关地址均从使用的接口定义 API_BASE_URL = "" # 阿里云api网关地址均从使用的接口定义

@ -4,13 +4,13 @@
# author: liuyu # author: liuyu
# date: 2020/3/6 # date: 2020/3/6
from api.utils.app.randomstrings import make_app_uuid from api.utils.app.randomstrings import make_app_uuid
from api.models import AppReleaseInfo,Apps from api.models import AppReleaseInfo, Apps
import random import random
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short from api.utils.storage.caches import del_cache_response_by_short
def make_resigned(bin_url,img_url,bundle_id,app_version,name):
def make_resigned(bin_url, img_url, bundle_id, app_version, name):
ios_plist_tem = """<?xml version="1.0" encoding="UTF-8"?> ios_plist_tem = """<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0"><dict> <plist version="1.0"><dict>
<key>items</key> <key>items</key>
@ -59,6 +59,7 @@ def make_resigned(bin_url,img_url,bundle_id,app_version,name):
return ios_plist_tem return ios_plist_tem
def bytes2human(n): def bytes2human(n):
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
prefix = {} prefix = {}
@ -71,11 +72,11 @@ def bytes2human(n):
return '%sB' % n return '%sB' % n
def get_release_type(app_file_name,appinfo): def get_release_type(app_file_name, appinfo):
extension = app_file_name.split(".")[1] extension = app_file_name.split(".")[1]
if extension == "ipa": if extension == "ipa":
release_type = appinfo.get("release_type") release_type = appinfo.get("release_type")
if release_type == "Adhoc": # Adhoc: 内测版 Inhouse:企业版 if release_type == "Adhoc": # Adhoc: 内测版 Inhouse:企业版
return 1 return 1
elif release_type == "Inhouse": elif release_type == "Inhouse":
return 2 return 2
@ -84,6 +85,7 @@ def get_release_type(app_file_name,appinfo):
else: else:
return 0 return 0
def get_app_type(app_file_name): def get_app_type(app_file_name):
extension = app_file_name.split(".")[1] extension = app_file_name.split(".")[1]
if extension == "ipa": if extension == "ipa":
@ -93,21 +95,20 @@ def get_app_type(app_file_name):
else: else:
return 2 return 2
def get_random_short():
def get_random_short():
short_url = ''.join(random.sample( short_url = ''.join(random.sample(
['z', 'y', 'x', 'w', 'v', 'u', 't', 's', 'r', 'q', 'p', 'o', 'n', 'm', 'l', 'k', 'j', 'i', 'h', 'g', 'f', ['z', 'y', 'x', 'w', 'v', 'u', 't', 's', 'r', 'q', 'p', 'o', 'n', 'm', 'l', 'k', 'j', 'i', 'h', 'g', 'f',
'e', 'd', 'c', 'b', 'a'], 4)) 'e', 'd', 'c', 'b', 'a'], 4))
appobj=Apps.objects.filter(short=short_url).first() appobj = Apps.objects.filter(short=short_url).first()
if appobj: if appobj:
return get_random_short() return get_random_short()
else: else:
return short_url return short_url
def SaveAppInfos(app_file_name, user_obj, appinfo, bundle_id, app_img, short, size):
def SaveAppInfos(app_file_name,user_obj,appinfo,bundle_id,app_img,short,size): app_uuid = make_app_uuid(user_obj, bundle_id + app_file_name.split(".")[1])
app_uuid = make_app_uuid(user_obj,bundle_id+app_file_name.split(".")[1])
##判断是否存在该app ##判断是否存在该app
appmobj = Apps.objects.filter(app_id=app_uuid, user_id=user_obj).first() appmobj = Apps.objects.filter(app_id=app_uuid, user_id=user_obj).first()
storage = Storage(user_obj) storage = Storage(user_obj)
@ -130,7 +131,7 @@ def SaveAppInfos(app_file_name,user_obj,appinfo,bundle_id,app_img,short,size):
return return
else: else:
try: try:
del_cache_response_by_short(appmobj.short,appmobj.app_id) del_cache_response_by_short(appmobj.short, appmobj.app_id)
appmobj.short = short appmobj.short = short
appmobj.name = appinfo["labelname"] appmobj.name = appinfo["labelname"]
appmobj.bundle_id = bundle_id appmobj.bundle_id = bundle_id
@ -153,8 +154,8 @@ def SaveAppInfos(app_file_name,user_obj,appinfo,bundle_id,app_img,short,size):
"minimum_os_version": appinfo.get("miniOSversion", None), "minimum_os_version": appinfo.get("miniOSversion", None),
"binary_size": size, "binary_size": size,
"is_master": True, "is_master": True,
"changelog":appinfo.get("changelog",''), "changelog": appinfo.get("changelog", ''),
"udid":appinfo.get("udid",''), "udid": appinfo.get("udid", ''),
} }
AppReleaseInfo.objects.create(**release_data) AppReleaseInfo.objects.create(**release_data)
@ -171,9 +172,8 @@ def SaveAppInfos(app_file_name,user_obj,appinfo,bundle_id,app_img,short,size):
if release_queryset.count() > history_release_limit: if release_queryset.count() > history_release_limit:
flag = 0 flag = 0
for release_obj in release_queryset: for release_obj in release_queryset:
flag +=1 flag += 1
if flag > history_release_limit: if flag > history_release_limit:
storage.delete_file(release_obj.release_id,appmobj.type) storage.delete_file(release_obj.release_id, appmobj.type)
storage.delete_file(release_obj.icon_url) storage.delete_file(release_obj.icon_url)
release_obj.delete() release_obj.delete()

@ -12,7 +12,7 @@ from androguard.core.bytecodes import apk
import plistlib import plistlib
def get_android_data( package_file): def get_android_data(package_file):
try: try:
apkobj = apk.APK(package_file) apkobj = apk.APK(package_file)
except Exception as err: except Exception as err:
@ -26,7 +26,8 @@ def get_android_data( package_file):
sdk_version = apkobj.get_target_sdk_version() sdk_version = apkobj.get_target_sdk_version()
return labelname, bundle_id, versioncode, versioname, sdk_version return labelname, bundle_id, versioncode, versioname, sdk_version
def get_ios_data( ios_file):
def get_ios_data(ios_file):
if zipfile.is_zipfile(ios_file): if zipfile.is_zipfile(ios_file):
ipaobj = zipfile.ZipFile(ios_file) ipaobj = zipfile.ZipFile(ios_file)
info_path = get_ios_info_path(ipaobj) info_path = get_ios_info_path(ipaobj)
@ -39,22 +40,23 @@ def get_ios_data( ios_file):
print("inhouse") print("inhouse")
def get_ios_info_path(ipaobj):
def get_ios_info_path( ipaobj):
infopath_re = re.compile(r'.*.app/embedded.mobileprovision') infopath_re = re.compile(r'.*.app/embedded.mobileprovision')
for i in ipaobj.namelist(): for i in ipaobj.namelist():
m = infopath_re.match(i) m = infopath_re.match(i)
if m is not None: if m is not None:
return m.group() return m.group()
def get_ios_icon_path( ipaobj):
def get_ios_icon_path(ipaobj):
infopath_re = re.compile(r'Payload/[^/]*.app/AppIcon[^/]*[^(ipad)].png') infopath_re = re.compile(r'Payload/[^/]*.app/AppIcon[^/]*[^(ipad)].png')
for i in ipaobj.namelist(): for i in ipaobj.namelist():
m = infopath_re.match(i) m = infopath_re.match(i)
if m is not None: if m is not None:
return m.group() return m.group()
def get_package_size( package_path):
def get_package_size(package_path):
fsize = os.path.getsize(package_path) fsize = os.path.getsize(package_path)
fsize = fsize / float(1024 * 1024) fsize = fsize / float(1024 * 1024)
return round(fsize, 2) return round(fsize, 2)
@ -68,4 +70,4 @@ info_path = get_ios_icon_path(ipaobj)
print(info_path) print(info_path)
with open('111222.png', 'wb') as f: with open('111222.png', 'wb') as f:
f.write(ipaobj.read(info_path)) f.write(ipaobj.read(info_path))

@ -5,7 +5,7 @@
# date: 2019/12/19 # date: 2019/12/19
import requests import requests
import zipfile, re, os, random,io import zipfile, re, os, random, io
from androguard.core.bytecodes import apk from androguard.core.bytecodes import apk
import plistlib import plistlib
import qrcode import qrcode
@ -24,13 +24,12 @@ def bytes2human(n):
return '%sB' % n return '%sB' % n
class AppInfo(object): class AppInfo(object):
def __init__(self, app_path): def __init__(self, app_path):
self.app_path = app_path self.app_path = app_path
self.result = {} self.result = {}
def make_app_png(self,png_path,filename): def make_app_png(self, png_path, filename):
zf = zipfile.ZipFile(self.app_path) zf = zipfile.ZipFile(self.app_path)
name_list = zf.namelist() name_list = zf.namelist()
if self.app_path.endswith("apk"): if self.app_path.endswith("apk"):
@ -59,14 +58,13 @@ class AppInfo(object):
if size == 0: if size == 0:
raise Exception("File size error") raise Exception("File size error")
if not os.path.isdir(png_path): if not os.path.isdir(png_path):
os.makedirs(png_path) os.makedirs(png_path)
with open(os.path.join(png_path, "%s.png" %filename), 'wb') as f: with open(os.path.join(png_path, "%s.png" % filename), 'wb') as f:
f.write(zf.read(iconfile)) f.write(zf.read(iconfile))
return "%s.png" %filename return "%s.png" % filename
def get_app_data(self): def get_app_data(self):
if self.app_path.endswith("apk"): if self.app_path.endswith("apk"):
@ -116,13 +114,13 @@ class AppInfo(object):
versioncode = plist_root['CFBundleVersion'] versioncode = plist_root['CFBundleVersion']
bundle_id = plist_root['CFBundleIdentifier'] bundle_id = plist_root['CFBundleIdentifier']
version = plist_root['CFBundleShortVersionString'] version = plist_root['CFBundleShortVersionString']
miniOSversion = plist_root["MinimumOSVersion"] miniOSversion = plist_root["MinimumOSVersion"]
self.result = { self.result = {
"labelname": labelname, "labelname": labelname,
"bundle_id": bundle_id, "bundle_id": bundle_id,
"versioncode": versioncode, "versioncode": versioncode,
"version": version, "version": version,
"miniOSversion":miniOSversion, "miniOSversion": miniOSversion,
"type": "ios", "type": "ios",
} }
@ -247,12 +245,12 @@ class FirApi(object):
res = self.__request("post", binary_upload_url, data=binary_data, files=files) res = self.__request("post", binary_upload_url, data=binary_data, files=files)
if res.status_code == 200: if res.status_code == 200:
print(res.json()) print(res.json())
QrCode.make_logo_qr(os.path.join("https://fir.im/", short_url), icon_path, "fir_%s.png"%(appinfo["labelname"])) QrCode.make_logo_qr(os.path.join("https://fir.im/", short_url), icon_path,
"fir_%s.png" % (appinfo["labelname"]))
else: else:
raise Exception(res.content) raise Exception(res.content)
def get_app_list(self): def get_app_list(self):
url = "%s?api_token=%s" % (self.app_url, self.api_token) url = "%s?api_token=%s" % (self.app_url, self.api_token)
res = self.__request("get", url) res = self.__request("get", url)
@ -363,23 +361,23 @@ class QrCode(object):
img.save(save_path) img.save(save_path)
else: else:
imgByteArr = io.BytesIO() imgByteArr = io.BytesIO()
img.save(imgByteArr,format="PNG") img.save(imgByteArr, format="PNG")
return imgByteArr.getvalue() return imgByteArr.getvalue()
if __name__ == '__main__': if __name__ == '__main__':
apk_path = "/root/hehemajiang.apk" apk_path = "/root/hehemajiang.apk"
API_TOKEN = "3d2a41159a7d8c396ddf0e88799de14a" API_TOKEN = "3d2a41159a7d8c396ddf0e88799de14a"
fir = FirApi(API_TOKEN) fir = FirApi(API_TOKEN)
#上传 # 上传
fir.upload_app(apk_path) fir.upload_app(apk_path)
# 获取版本信息 # 获取版本信息
# print(fir.get_version_by_id("5dfb54d3b2eb4612589c3040")) # print(fir.get_version_by_id("5dfb54d3b2eb4612589c3040"))
#获取app详细信息 # 获取app详细信息
# print(fir.get_app_infos_by_id("5dfb54d3b2eb4612589c3040")) # print(fir.get_app_infos_by_id("5dfb54d3b2eb4612589c3040"))
#获取列表 # 获取列表
# print(fir.get_app_list()) # print(fir.get_app_list())

@ -4,109 +4,111 @@
# author: liuyu # author: liuyu
# date: 2020/4/24 # date: 2020/4/24
from api.utils.app.shellcmds import shell_command,use_user_pass,pshell_command from api.utils.app.shellcmds import shell_command, use_user_pass, pshell_command
from fir_ser.settings import SUPER_SIGN_ROOT from fir_ser.settings import SUPER_SIGN_ROOT
import os import os
from api.utils.app.randomstrings import make_app_uuid from api.utils.app.randomstrings import make_app_uuid
def exec_shell(cmd,remote=False,timeout=None):
def exec_shell(cmd, remote=False, timeout=None):
if remote: if remote:
hostip="10.66.6.66" hostip = "10.66.6.66"
port=65534 port = 65534
user="root" user = "root"
passwd="root" passwd = "root"
result = use_user_pass(hostip,port,user,passwd,cmd) result = use_user_pass(hostip, port, user, passwd, cmd)
print(result) print(result)
return result return result
else: else:
print(cmd) print(cmd)
result = shell_command(cmd,timeout) result = shell_command(cmd, timeout)
print(result) print(result)
if result.get("exit_code") != 0 : if result.get("exit_code") != 0:
err_info=result.get("err_info",None) err_info = result.get("err_info", None)
if err_info: if err_info:
if "have access to this membership resource. Contact your team" in err_info: if "have access to this membership resource. Contact your team" in err_info:
result["err_info"]="You currently don't have access to this membership resource" result["err_info"] = "You currently don't have access to this membership resource 【您没有权限执行该操作】"
elif "Maximum number of certificates generated" in err_info:
result["err_info"] = "Maximum number of certificates generated 【开发证书数量到上限】"
else: else:
result["err_info"]="Unknown Error" result["err_info"] = "Unknown Error"
return False,result return False, result
return True,result return True, result
class AppDeveloperApi(object): class AppDeveloperApi(object):
def __init__(self,username,password,certid): def __init__(self, username, password, certid):
self.username = username self.username = username
self.password = password self.password = password
self.certid = certid self.certid = certid
script_path=os.path.join(SUPER_SIGN_ROOT,'scripts','apple_api.rb') script_path = os.path.join(SUPER_SIGN_ROOT, 'scripts', 'apple_api.rb')
self.cmd = "ruby %s '%s' '%s'" %(script_path,self.username,self.password) self.cmd = "ruby %s '%s' '%s'" % (script_path, self.username, self.password)
def active(self,user_obj): def active(self, user_obj):
self.cmd = self.cmd + " active " self.cmd = self.cmd + " active "
print(self.cmd) print(self.cmd)
result={} result = {}
try: try:
result = pshell_command(self.cmd,user_obj,self.username) result = pshell_command(self.cmd, user_obj, self.username)
print(result) print(result)
if result["exit_code"] == 0: if result["exit_code"] == 0:
return True,result return True, result
except Exception as e: except Exception as e:
print(e) print(e)
return False,result return False, result
def file_format_path_name(self,user_obj): def file_format_path_name(self, user_obj):
cert_dir_name = make_app_uuid(user_obj,self.username) cert_dir_name = make_app_uuid(user_obj, self.username)
cert_dir_path = os.path.join(SUPER_SIGN_ROOT,cert_dir_name) cert_dir_path = os.path.join(SUPER_SIGN_ROOT, cert_dir_name)
if not os.path.isdir(cert_dir_path): if not os.path.isdir(cert_dir_path):
os.makedirs(cert_dir_path) os.makedirs(cert_dir_path)
return os.path.join(cert_dir_path,cert_dir_name) return os.path.join(cert_dir_path, cert_dir_name)
def create_cert(self,user_obj): def create_cert(self, user_obj):
self.cmd=self.cmd + " cert add '%s'" %(self.file_format_path_name(user_obj)) self.cmd = self.cmd + " cert add '%s'" % (self.file_format_path_name(user_obj))
return exec_shell(self.cmd) return exec_shell(self.cmd)
def get_profile(self,bundleId,app_id,device_udid,device_name,provisionName): def get_profile(self, bundleId, app_id, device_udid, device_name, provisionName):
self.cmd=self.cmd + " profile add '%s' '%s' '%s' '%s' '%s' '%s'" %(bundleId,app_id,device_udid,device_name,self.certid,provisionName) self.cmd = self.cmd + " profile add '%s' '%s' '%s' '%s' '%s' '%s'" % (
bundleId, app_id, device_udid, device_name, self.certid, provisionName)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)
def del_profile(self,bundleId,app_id): def del_profile(self, bundleId, app_id):
self.cmd=self.cmd + " profile del '%s' '%s'" %(bundleId,app_id) self.cmd = self.cmd + " profile del '%s' '%s'" % (bundleId, app_id)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)
def set_device_status(self,status,device_udid): def set_device_status(self, status, device_udid):
if status == "enable": if status == "enable":
self.cmd=self.cmd + " device enable '%s'" %(device_udid) self.cmd = self.cmd + " device enable '%s'" % (device_udid)
else: else:
self.cmd=self.cmd + " device disable '%s'" %(device_udid) self.cmd = self.cmd + " device disable '%s'" % (device_udid)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)
def add_device(self,device_udid,device_name): def add_device(self, device_udid, device_name):
self.cmd=self.cmd + " device add '%s' '%s'" %(device_udid,device_name) self.cmd = self.cmd + " device add '%s' '%s'" % (device_udid, device_name)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)
def get_device(self,user_obj): def get_device(self, user_obj):
self.cmd=self.cmd + " device get '%s' " %(self.file_format_path_name(user_obj)) self.cmd = self.cmd + " device get '%s' " % (self.file_format_path_name(user_obj))
return exec_shell(self.cmd) return exec_shell(self.cmd)
def add_app(self,bundleId,app_id): def add_app(self, bundleId, app_id):
self.cmd=self.cmd + " app add '%s' '%s'" %(bundleId,app_id) self.cmd = self.cmd + " app add '%s' '%s'" % (bundleId, app_id)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)
def del_app(self,bundleId,app_id): def del_app(self, bundleId, app_id):
self.cmd=self.cmd + " app del '%s' '%s'" %(bundleId,app_id) self.cmd = self.cmd + " app del '%s' '%s'" % (bundleId, app_id)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)
class ResignApp(object): class ResignApp(object):
def __init__(self,my_local_key,app_dev_pem): def __init__(self, my_local_key, app_dev_pem):
self.my_local_key=my_local_key self.my_local_key = my_local_key
self.app_dev_pem = app_dev_pem self.app_dev_pem = app_dev_pem
# script_path=os.path.join(SUPER_SIGN_ROOT,'scripts','apple_api.rb') # script_path=os.path.join(SUPER_SIGN_ROOT,'scripts','apple_api.rb')
self.cmd = "isign -c '%s' -k '%s' " %(self.app_dev_pem,self.my_local_key) self.cmd = "isign -c '%s' -k '%s' " % (self.app_dev_pem, self.my_local_key)
def sign(self,new_profile,org_ipa,new_ipa):
self.cmd = self.cmd + " -p '%s' -o '%s' '%s'" %(new_profile,new_ipa,org_ipa) def sign(self, new_profile, org_ipa, new_ipa):
self.cmd = self.cmd + " -p '%s' -o '%s' '%s'" % (new_profile, new_ipa, org_ipa)
result = exec_shell(self.cmd) result = exec_shell(self.cmd)

@ -5,24 +5,23 @@
# date: 2020/3/6 # date: 2020/3/6
import uuid import uuid
def make_from_user_uuid(userinfo): def make_from_user_uuid(userinfo):
user_id = userinfo.uid user_id = userinfo.uid
random_str = uuid.uuid1().__str__().split("-")[0:-1] random_str = uuid.uuid1().__str__().split("-")[0:-1]
user_ran_str=uuid.uuid5(uuid.NAMESPACE_DNS, user_id).__str__().split("-") user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, user_id).__str__().split("-")
user_ran_str.extend(random_str) user_ran_str.extend(random_str)
new_str = "".join(user_ran_str) new_str = "".join(user_ran_str)
return new_str return new_str
def make_app_uuid(userinfo,bundleid):
def make_app_uuid(userinfo, bundleid):
user_id = userinfo.uid user_id = userinfo.uid
app_uuid=uuid.uuid5(uuid.NAMESPACE_DNS, "%s"%(user_id+bundleid)).__str__().split("-") app_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, "%s" % (user_id + bundleid)).__str__().split("-")
fapp_uuid = "".join(app_uuid) fapp_uuid = "".join(app_uuid)
return fapp_uuid return fapp_uuid
def make_random_uuid(): def make_random_uuid():
random_str = uuid.uuid1().__str__().split("-") random_str = uuid.uuid1().__str__().split("-")
return "".join(random_str) return "".join(random_str)

@ -13,79 +13,78 @@ Python生成二维码 v1.0
''' '''
import qrcode import qrcode
from PIL import Image from PIL import Image
import os import os
#生成二维码图片
def make_qr(str,save): # 生成二维码图片
qr=qrcode.QRCode( def make_qr(str, save):
version=4, #生成二维码尺寸的大小 1-40 1:21*21(21+(n-1)*4) qr = qrcode.QRCode(
error_correction=qrcode.constants.ERROR_CORRECT_M, #L:7% M:15% Q:25% H:30% version=4, # 生成二维码尺寸的大小 1-40 1:21*21(21+(n-1)*4)
box_size=10, #每个格子的像素大小 error_correction=qrcode.constants.ERROR_CORRECT_M, # L:7% M:15% Q:25% H:30%
border=2, #边框的格子宽度大小 box_size=10, # 每个格子的像素大小
border=2, # 边框的格子宽度大小
) )
qr.add_data(str) qr.add_data(str)
qr.make(fit=True) qr.make(fit=True)
img=qr.make_image() img = qr.make_image()
img.save(save) img.save(save)
#生成带logo的二维码图片 # 生成带logo的二维码图片
def make_logo_qr(str,logo,save): def make_logo_qr(str, logo, save):
#参数配置 # 参数配置
qr=qrcode.QRCode( qr = qrcode.QRCode(
version=4, version=4,
error_correction=qrcode.constants.ERROR_CORRECT_Q, error_correction=qrcode.constants.ERROR_CORRECT_Q,
box_size=8, box_size=8,
border=2 border=2
) )
#添加转换内容 # 添加转换内容
qr.add_data(str) qr.add_data(str)
# #
qr.make(fit=True) qr.make(fit=True)
#生成二维码 # 生成二维码
img=qr.make_image() img = qr.make_image()
# #
img=img.convert("RGBA") img = img.convert("RGBA")
#添加logo # 添加logo
if logo and os.path.exists(logo): if logo and os.path.exists(logo):
icon=Image.open(logo) icon = Image.open(logo)
#获取二维码图片的大小 # 获取二维码图片的大小
img_w,img_h=img.size img_w, img_h = img.size
factor=4 factor = 4
size_w=int(img_w/factor) size_w = int(img_w / factor)
size_h=int(img_h/factor) size_h = int(img_h / factor)
#logo图片的大小不能超过二维码图片的1/4 # logo图片的大小不能超过二维码图片的1/4
icon_w,icon_h=icon.size icon_w, icon_h = icon.size
if icon_w>size_w: if icon_w > size_w:
icon_w=size_w icon_w = size_w
if icon_h>size_h: if icon_h > size_h:
icon_h=size_h icon_h = size_h
icon=icon.resize((icon_w,icon_h),Image.ANTIALIAS) icon = icon.resize((icon_w, icon_h), Image.ANTIALIAS)
#详见:http://pillow.readthedocs.org/handbook/tutorial.html # 详见:http://pillow.readthedocs.org/handbook/tutorial.html
#计算logo在二维码图中的位置 # 计算logo在二维码图中的位置
w=int((img_w-icon_w)/2) w = int((img_w - icon_w) / 2)
h=int((img_h-icon_h)/2) h = int((img_h - icon_h) / 2)
icon=icon.convert("RGBA") icon = icon.convert("RGBA")
img.paste(icon,(w,h),icon) img.paste(icon, (w, h), icon)
#详见:http://pillow.readthedocs.org/reference/Image.html#PIL.Image.Image.paste # 详见:http://pillow.readthedocs.org/reference/Image.html#PIL.Image.Image.paste
#保存处理后图片 # 保存处理后图片
img.save(save) img.save(save)
if __name__=='__main__': if __name__ == '__main__':
save_path='base__runmethod_02.png' #生成后的保存文件 save_path = 'base__runmethod_02.png' # 生成后的保存文件
logo='/tmp/pycharm_project_986/fir/tmp/icon/cmjpwyltznbioseh' #logo图片 logo = '/tmp/pycharm_project_986/fir/tmp/icon/cmjpwyltznbioseh' # logo图片
str="https://fir.im/luy4"
str = "https://fir.im/luy4"
make_logo_qr(str,logo,save_path) make_logo_qr(str, logo, save_path)

@ -3,38 +3,37 @@
# project: 3月 # project: 3月
# author: liuyu # author: liuyu
# date: 2020/3/6 # date: 2020/3/6
import time,re,os,signal import time, re, os, signal
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
import logging import logging
import paramiko,json import paramiko, json
import socket import socket
import pexpect import pexpect
from api.utils.storage.caches import developer_auth_code from api.utils.storage.caches import developer_auth_code
def default_result(): def default_result():
return {'exit_code': '99', 'return_info': 'Failed to run, function_name is not existed'} return {'exit_code': '99', 'return_info': 'Failed to run, function_name is not existed'}
def portisonline(host,port): def portisonline(host, port):
result={} result = {}
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.settimeout(3) sk.settimeout(3)
result["host"] = host result["host"] = host
result["port"]=port result["port"] = port
result["functionname"]="CHECK_HOST_ONLINE:" result["functionname"] = "CHECK_HOST_ONLINE:"
try: try:
sk.connect((host,port)) sk.connect((host, port))
result["message"]="Connection success" result["message"] = "Connection success"
result["code"]=0 result["code"] = 0
except Exception: except Exception:
result["message"]="SSH Port Connection refused" result["message"] = "SSH Port Connection refused"
result["code"]=1 result["code"] = 1
sk.close() sk.close()
return result return result
class SSHConnection(object): class SSHConnection(object):
def __init__(self, host, port, username, password): def __init__(self, host, port, username, password):
self._host = host self._host = host
@ -51,23 +50,22 @@ class SSHConnection(object):
transport.connect(username=self._username, password=self._password) transport.connect(username=self._username, password=self._password)
self._transport = transport self._transport = transport
#下载 # 下载
def download(self, remotepath, localpath): def download(self, remotepath, localpath):
if self._sftp is None: if self._sftp is None:
self._sftp = paramiko.SFTPClient.from_transport(self._transport) self._sftp = paramiko.SFTPClient.from_transport(self._transport)
self._sftp.get(remotepath, localpath) self._sftp.get(remotepath, localpath)
self.close() self.close()
#上传 # 上传
def put(self, localpath, remotepath): def put(self, localpath, remotepath):
if self._sftp is None: if self._sftp is None:
self._sftp = paramiko.SFTPClient.from_transport(self._transport) self._sftp = paramiko.SFTPClient.from_transport(self._transport)
self.exec_command('mkdir -p %s'%(os.path.dirname(remotepath))) self.exec_command('mkdir -p %s' % (os.path.dirname(remotepath)))
self._sftp.put(localpath, remotepath) self._sftp.put(localpath, remotepath)
self.close() self.close()
# 执行命令
#执行命令
def exec_command(self, command): def exec_command(self, command):
if self._client is None: if self._client is None:
self._client = paramiko.SSHClient() self._client = paramiko.SSHClient()
@ -75,10 +73,10 @@ class SSHConnection(object):
stdin, stdout, stderr = self._client.exec_command(command) stdin, stdout, stderr = self._client.exec_command(command)
data = stdout.read() data = stdout.read()
if len(data) > 0: if len(data) > 0:
return {'status':0,'infos':data} return {'status': 0, 'infos': data}
err = stderr.read() err = stderr.read()
if len(err) > 0: if len(err) > 0:
return {'status':1,'infos':err} return {'status': 1, 'infos': err}
return {'status': 0, 'infos': data} return {'status': 0, 'infos': data}
def close(self): def close(self):
@ -87,30 +85,33 @@ class SSHConnection(object):
if self._client: if self._client:
self._client.close() self._client.close()
def pshell_command(cmdstrs,user_obj,developer_email,timeout=60*10):
def pshell_command(cmdstrs, user_obj, developer_email, timeout=60 * 10):
result = default_result() result = default_result()
run = pexpect.spawn(cmdstrs, encoding='utf-8') run = pexpect.spawn(cmdstrs, encoding='utf-8')
try: try:
index = run.expect(["Two-factor Authentication","Invalid username and password combination", pexpect.EOF, pexpect.TIMEOUT],timeout=timeout) index = run.expect(
["Two-factor Authentication", "Invalid username and password combination", pexpect.EOF, pexpect.TIMEOUT],
timeout=timeout)
if index == 0: if index == 0:
count = 1 count = 1
if timeout == -1: if timeout == -1:
timeout = 60*60*24 timeout = 60 * 60 * 24
while True and count<timeout/3: while True and count < timeout / 3:
code = developer_auth_code("get",user_obj,developer_email) code = developer_auth_code("get", user_obj, developer_email)
if code: if code:
run.sendline(code) run.sendline(code)
try: try:
err = run.expect(["Unauthorized Access", pexpect.EOF, pexpect.TIMEOUT]) err = run.expect(["Unauthorized Access", pexpect.EOF, pexpect.TIMEOUT])
if err == 0: if err == 0:
result['exit_code'] = 2 result['exit_code'] = 2
result['return_info'] = 'Unauthorized Access' result['return_info'] = 'Unauthorized Access 【验证码有误】'
elif err == 1: elif err == 1:
result['exit_code'] = 0 result['exit_code'] = 0
result['return_info'] = 'Verify Code Success' result['return_info'] = 'Verify Code Success'
else: else:
result['exit_code'] = 3 result['exit_code'] = 3
result['return_info'] = 'Verify Code TimeOut or UnKnown Error' result['return_info'] = 'Verify Code TimeOut or UnKnown Error 【双重验证未知错误】'
developer_auth_code("del", user_obj, developer_email) developer_auth_code("del", user_obj, developer_email)
return result return result
except Exception as e: except Exception as e:
@ -119,23 +120,23 @@ def pshell_command(cmdstrs,user_obj,developer_email,timeout=60*10):
result['exit_code'] = 0 result['exit_code'] = 0
result['return_info'] = 'Success' result['return_info'] = 'Success'
return result return result
count+=1 count += 1
time.sleep(3) time.sleep(3)
elif index == 1: elif index == 1:
result['exit_code'] = 1 result['exit_code'] = 1
result['return_info'] = 'Invalid username and password combination' result['return_info'] = 'Invalid username and password combination 【密码或者账号有误】'
elif index == 2: elif index == 2:
result['exit_code'] = 0 result['exit_code'] = 0
result['return_info'] = 'Alreay Success' result['return_info'] = 'Alreay Success'
else: else:
result['exit_code'] = 4 result['exit_code'] = 4
result['return_info'] = 'Code TimeOut or UnKnown Error' result['return_info'] = 'Code TimeOut or UnKnown Error 【验证超时】'
except Exception as e: except Exception as e:
print(e) print(e)
return result return result
def shell_command(cmdstrs,timeout): def shell_command(cmdstrs, timeout):
result = default_result() result = default_result()
result['return_info'] = '' result['return_info'] = ''
shell_start_time = time.time() shell_start_time = time.time()
@ -147,12 +148,12 @@ def shell_command(cmdstrs,timeout):
if int(now - shell_start_time) > timeout: if int(now - shell_start_time) > timeout:
os.kill(child.pid, signal.SIGKILL) os.kill(child.pid, signal.SIGKILL)
os.waitpid(-1, os.WNOHANG) os.waitpid(-1, os.WNOHANG)
result['exit_code']=126 result['exit_code'] = 126
return result return result
out, err = child.communicate() out, err = child.communicate()
if err: if err:
result['err_info'] = err result['err_info'] = err.decode("utf-8")
shell_end_time = time.time() shell_end_time = time.time()
result['shell_run_time'] = shell_end_time - shell_start_time result['shell_run_time'] = shell_end_time - shell_start_time
out = out.strip(b'\n') out = out.strip(b'\n')
@ -161,7 +162,8 @@ def shell_command(cmdstrs,timeout):
logging.info(u'shell: %s - %s%s - %s%d' % (cmdstrs, 'return_info: ', out, 'exit_code: ', child.returncode)) logging.info(u'shell: %s - %s%s - %s%d' % (cmdstrs, 'return_info: ', out, 'exit_code: ', child.returncode))
return result return result
def use_user_pass(hostip,port,user,passwd,cmdstrs):
def use_user_pass(hostip, port, user, passwd, cmdstrs):
result = default_result() result = default_result()
checkinfo = portisonline(hostip, port) checkinfo = portisonline(hostip, port)
if checkinfo["code"] != 0: if checkinfo["code"] != 0:
@ -172,17 +174,15 @@ def use_user_pass(hostip,port,user,passwd,cmdstrs):
conn = SSHConnection(hostip, port, user, passwd) conn = SSHConnection(hostip, port, user, passwd)
result['return_info'] = '' result['return_info'] = ''
shell_start_time = time.time() shell_start_time = time.time()
out=conn.exec_command(cmdstrs) out = conn.exec_command(cmdstrs)
shell_end_time = time.time() shell_end_time = time.time()
result['shell_run_time'] = shell_end_time - shell_start_time result['shell_run_time'] = shell_end_time - shell_start_time
outs =str(out['infos'],'utf-8') outs = str(out['infos'], 'utf-8')
outs = outs.strip('\n') outs = outs.strip('\n')
result['return_info'] = outs result['return_info'] = outs
result['exit_code'] = out['status'] result['exit_code'] = out['status']
# logging.info(u'shell: %s - %s%s - %s%d' % (cmdstrs, 'return_info: ', out, 'exit_code: ', out['status'])) # logging.info(u'shell: %s - %s%s - %s%d' % (cmdstrs, 'return_info: ', out, 'exit_code: ', out['status']))
print('host: %s user:%s - shell: %s - %s%s - %s%d' % (hostip,user,cmdstrs, 'return_info: ', out, 'exit_code: ', out['status'])) print('host: %s user:%s - shell: %s - %s%s - %s%d' % (
hostip, user, cmdstrs, 'return_info: ', out, 'exit_code: ', out['status']))
conn.close() conn.close()
return result return result

@ -7,12 +7,13 @@
import uuid, xmltodict, os, re import uuid, xmltodict, os, re
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN
from api.utils.app.iossignapi import AppDeveloperApi, ResignApp from api.utils.app.iossignapi import AppDeveloperApi, ResignApp
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo,Apps,APPToDeveloper,UDIDsyncDeveloper from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper
from api.utils.app.randomstrings import make_app_uuid, make_from_user_uuid from api.utils.app.randomstrings import make_app_uuid, make_from_user_uuid
from api.utils.serializer import get_developer_udided from api.utils.serializer import get_developer_udided
from api.utils.storage.localApi import LocalStorage from api.utils.storage.localApi import LocalStorage
from api.utils.storage.caches import del_cache_response_by_short from api.utils.storage.caches import del_cache_response_by_short
from api.utils.utils import file_format_path,delete_app_to_dev_and_file,delete_app_profile_file from api.utils.utils import file_format_path, delete_app_to_dev_and_file, delete_app_profile_file
def udid_bytes_to_dict(xml_stream): def udid_bytes_to_dict(xml_stream):
@ -76,7 +77,7 @@ def get_post_udid_url(request, short):
# PATH_INFO_lists.pop(-2) # PATH_INFO_lists.pop(-2)
# PATH_INFO_lists.append(short) # PATH_INFO_lists.append(short)
# PATH_INFO_lists.insert(0, server_domain) # PATH_INFO_lists.insert(0, server_domain)
PATH_INFO_lists=[server_domain,"udid",short] PATH_INFO_lists = [server_domain, "udid", short]
udid_url = "/".join(PATH_INFO_lists) udid_url = "/".join(PATH_INFO_lists)
return udid_url return udid_url
@ -106,7 +107,7 @@ def get_redirect_server_domain(request):
class IosUtils(object): class IosUtils(object):
def __init__(self, udid_info,user_obj,app_obj=None): def __init__(self, udid_info, user_obj, app_obj=None):
self.udid_info = udid_info self.udid_info = udid_info
self.app_obj = app_obj self.app_obj = app_obj
self.user_obj = user_obj self.user_obj = user_obj
@ -123,22 +124,22 @@ class IosUtils(object):
self.auth = auth self.auth = auth
def get_developer_user_by_app_udid(self): def get_developer_user_by_app_udid(self):
usedeviceobj = APPSuperSignUsedInfo.objects.filter(udid__udid=self.udid_info.get('udid'), #app_id=self.app_obj, usedeviceobj = APPSuperSignUsedInfo.objects.filter(udid__udid=self.udid_info.get('udid'),
user_id=self.user_obj).first() user_id=self.user_obj, developerid__is_actived=True,
#只要账户下面存在udid,就可以使用该苹果开发者账户,避免多个开发者账户下面出现同一个udid developerid__certid__isnull=False).first()
if usedeviceobj :#and usedeviceobj.developerid.use_number < usedeviceobj.developerid.usable_number: # 只要账户下面存在udid,就可以使用该苹果开发者账户,避免多个开发者账户下面出现同一个udid
if usedeviceobj:
developer_obj = usedeviceobj.developerid developer_obj = usedeviceobj.developerid
else: else:
developer_udid_obj = UDIDsyncDeveloper.objects.filter(udid=self.udid_info.get('udid')).first() developer_udid_obj = UDIDsyncDeveloper.objects.filter(udid=self.udid_info.get('udid'),
developerid__is_actived=True,
developerid__certid__isnull=False).first()
if developer_udid_obj: if developer_udid_obj:
developer_obj = developer_udid_obj.developerid developer_obj = developer_udid_obj.developerid
else: else:
# developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, is_actived=True,
# use_number__lt=F("usable_number")).order_by(
# "created_time").first()
for developer_obj in AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, for developer_obj in AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj,
is_actived=True, ).order_by("created_time"): is_actived=True, certid__isnull=False).order_by(
"created_time"):
usable_number = developer_obj.usable_number usable_number = developer_obj.usable_number
flyapp_used = get_developer_udided(developer_obj)[1] flyapp_used = get_developer_udided(developer_obj)[1]
if flyapp_used < usable_number: if flyapp_used < usable_number:
@ -164,14 +165,14 @@ class IosUtils(object):
def resign(self): def resign(self):
if AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).first().is_signed: if AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).first().is_signed:
apptodev_obj=APPToDeveloper.objects.filter(app_id=self.app_obj).first() apptodev_obj = APPToDeveloper.objects.filter(app_id=self.app_obj).first()
if apptodev_obj: if apptodev_obj:
release_obj = AppReleaseInfo.objects.filter(app_id=self.app_obj, is_master=True).first() release_obj = AppReleaseInfo.objects.filter(app_id=self.app_obj, is_master=True).first()
if release_obj.release_id == apptodev_obj.release_file: if release_obj.release_id == apptodev_obj.release_file:
return return
self.download_profile() self.download_profile()
file_format_path_name = file_format_path(self.user_obj,self.auth) file_format_path_name = file_format_path(self.user_obj, self.auth)
my_local_key = file_format_path_name + ".key" my_local_key = file_format_path_name + ".key"
app_dev_pem = file_format_path_name + ".pem" app_dev_pem = file_format_path_name + ".pem"
ResignAppObj = ResignApp(my_local_key, app_dev_pem) ResignAppObj = ResignApp(my_local_key, app_dev_pem)
@ -188,43 +189,49 @@ class IosUtils(object):
"is_signed": True, "is_signed": True,
"binary_file": random_file_name "binary_file": random_file_name
} }
#更新已经完成签名状态,设备消耗记录,和开发者已消耗数量 # 更新已经完成签名状态,设备消耗记录,和开发者已消耗数量
AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).update(**newdata) AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).update(**newdata)
appsupersign_obj=APPSuperSignUsedInfo.objects.filter(udid__udid=self.udid_info.get('udid'),developerid=self.developer_obj) appsupersign_obj = APPSuperSignUsedInfo.objects.filter(udid__udid=self.udid_info.get('udid'),
developerid=self.developer_obj)
if appsupersign_obj.count() == 0: if appsupersign_obj.count() == 0:
developer_obj = self.developer_obj developer_obj = self.developer_obj
developer_obj.use_number=developer_obj.use_number + 1 developer_obj.use_number = developer_obj.use_number + 1
developer_obj.save() developer_obj.save()
if not appsupersign_obj.filter(app_id=self.app_obj, user_id=self.user_obj).first(): if not appsupersign_obj.filter(app_id=self.app_obj, user_id=self.user_obj).first():
APPSuperSignUsedInfo.objects.create(app_id=self.app_obj, user_id=self.user_obj, developerid=self.developer_obj, APPSuperSignUsedInfo.objects.create(app_id=self.app_obj, user_id=self.user_obj,
udid=AppUDID.objects.filter(app_id=self.app_obj,udid=self.udid_info.get('udid')).first()) developerid=self.developer_obj,
udid=AppUDID.objects.filter(app_id=self.app_obj,
del_cache_response_by_short(self.app_obj.short,self.app_obj.app_id,udid=self.udid_info.get('udid')) udid=self.udid_info.get('udid')).first())
del_cache_response_by_short(self.app_obj.short, self.app_obj.app_id, udid=self.udid_info.get('udid'))
app_udid_obj = UDIDsyncDeveloper.objects.filter(developerid=self.developer_obj, udid=self.udid_info.get('udid')) app_udid_obj = UDIDsyncDeveloper.objects.filter(developerid=self.developer_obj, udid=self.udid_info.get('udid'))
if not app_udid_obj: if not app_udid_obj:
device=AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).values("serial", 'product', 'udid','version').first() device = AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).values("serial",
'product',
'udid',
'version').first()
UDIDsyncDeveloper.objects.create(developerid=self.developer_obj, **device) UDIDsyncDeveloper.objects.create(developerid=self.developer_obj, **device)
#创建 # 创建
apptodev_obj=APPToDeveloper.objects.filter(developerid=self.developer_obj,app_id=self.app_obj).first() apptodev_obj = APPToDeveloper.objects.filter(developerid=self.developer_obj, app_id=self.app_obj).first()
if apptodev_obj: if apptodev_obj:
storage = LocalStorage("localhost", False) storage = LocalStorage("localhost", False)
storage.del_file(apptodev_obj.binary_file+ ".ipa") storage.del_file(apptodev_obj.binary_file + ".ipa")
apptodev_obj.binary_file=random_file_name apptodev_obj.binary_file = random_file_name
apptodev_obj.release_file=release_obj.release_id apptodev_obj.release_file = release_obj.release_id
apptodev_obj.save() apptodev_obj.save()
else: else:
APPToDeveloper.objects.create(developerid=self.developer_obj,app_id=self.app_obj,binary_file=random_file_name,release_file=release_obj.release_id) APPToDeveloper.objects.create(developerid=self.developer_obj, app_id=self.app_obj,
binary_file=random_file_name, release_file=release_obj.release_id)
@staticmethod @staticmethod
def disable_udid(udid_obj,app_id): def disable_udid(udid_obj, app_id):
usedeviceobj=APPSuperSignUsedInfo.objects.filter(udid=udid_obj,app_id_id=app_id) usedeviceobj = APPSuperSignUsedInfo.objects.filter(udid=udid_obj, app_id_id=app_id)
if usedeviceobj: if usedeviceobj:
developer_obj = usedeviceobj.first().developerid developer_obj = usedeviceobj.first().developerid
auth = { auth = {
@ -234,13 +241,13 @@ class IosUtils(object):
} }
# 需要判断该设备在同一个账户下 的多个应用,若存在,则不操作 # 需要判断该设备在同一个账户下 的多个应用,若存在,则不操作
udid_lists=list(APPSuperSignUsedInfo.objects.values_list("udid__udid").filter(developerid=developer_obj)) udid_lists = list(APPSuperSignUsedInfo.objects.values_list("udid__udid").filter(developerid=developer_obj))
if udid_lists.count((udid_obj.udid,)) == 1: if udid_lists.count((udid_obj.udid,)) == 1:
app_api_obj = AppDeveloperApi(**auth) app_api_obj = AppDeveloperApi(**auth)
app_api_obj.set_device_status("disable",udid_obj.udid) app_api_obj.set_device_status("disable", udid_obj.udid)
if developer_obj.use_number > 0: if developer_obj.use_number > 0:
developer_obj.use_number=developer_obj.use_number-1 developer_obj.use_number = developer_obj.use_number - 1
developer_obj.save() developer_obj.save()
usedeviceobj.delete() usedeviceobj.delete()
@ -249,15 +256,14 @@ class IosUtils(object):
if APPSuperSignUsedInfo.objects.filter(developerid=developer_obj, app_id_id=app_id).count() == 0: if APPSuperSignUsedInfo.objects.filter(developerid=developer_obj, app_id_id=app_id).count() == 0:
app_api_obj = AppDeveloperApi(**auth) app_api_obj = AppDeveloperApi(**auth)
app_obj = Apps.objects.filter(pk=app_id).first() app_obj = Apps.objects.filter(pk=app_id).first()
app_api_obj.del_profile(app_obj.bundle_id,app_obj.app_id) app_api_obj.del_profile(app_obj.bundle_id, app_obj.app_id)
app_api_obj2 = AppDeveloperApi(**auth) app_api_obj2 = AppDeveloperApi(**auth)
app_api_obj2.del_app(app_obj.bundle_id,app_obj.app_id) app_api_obj2.del_app(app_obj.bundle_id, app_obj.app_id)
delete_app_to_dev_and_file(developer_obj, app_id) delete_app_to_dev_and_file(developer_obj, app_id)
delete_app_profile_file(developer_obj, app_obj) delete_app_profile_file(developer_obj, app_obj)
@staticmethod @staticmethod
def clean_udid_by_app_obj(app_obj,developer_obj): def clean_udid_by_app_obj(app_obj, developer_obj):
auth = { auth = {
"username": developer_obj.email, "username": developer_obj.email,
@ -265,7 +271,6 @@ class IosUtils(object):
"certid": developer_obj.certid "certid": developer_obj.certid
} }
# 需要判断该设备在同一个账户下 的多个应用,若存在,则不操作 # 需要判断该设备在同一个账户下 的多个应用,若存在,则不操作
udid_lists = list(APPSuperSignUsedInfo.objects.values_list("udid__udid").filter(developerid=developer_obj)) udid_lists = list(APPSuperSignUsedInfo.objects.values_list("udid__udid").filter(developerid=developer_obj))
@ -284,27 +289,26 @@ class IosUtils(object):
SuperSignUsed_obj.delete() SuperSignUsed_obj.delete()
@staticmethod @staticmethod
def clean_app_by_user_obj(app_obj,user_obj): def clean_app_by_user_obj(app_obj, user_obj):
''' '''
该APP为超级签删除app的时候需要清理一下开发者账户里面的profile bundleid 该APP为超级签删除app的时候需要清理一下开发者账户里面的profile bundleid
:param app_obj: :param app_obj:
:param user_obj: :param user_obj:
:return: :return:
''' '''
SuperSign_obj_lists=list(set(APPSuperSignUsedInfo.objects.values_list("developerid").filter(user_id=user_obj, app_id=app_obj))) SuperSign_obj_lists = list(
set(APPSuperSignUsedInfo.objects.values_list("developerid").filter(user_id=user_obj, app_id=app_obj)))
for SuperSign_obj in SuperSign_obj_lists: for SuperSign_obj in SuperSign_obj_lists:
developer_obj=AppIOSDeveloperInfo.objects.filter(pk=SuperSign_obj[0]).first() developer_obj = AppIOSDeveloperInfo.objects.filter(pk=SuperSign_obj[0]).first()
if developer_obj: if developer_obj:
IosUtils.clean_app_by_developer_obj(app_obj,developer_obj) IosUtils.clean_app_by_developer_obj(app_obj, developer_obj)
delete_app_to_dev_and_file(developer_obj, app_obj.id) delete_app_to_dev_and_file(developer_obj, app_obj.id)
IosUtils.clean_udid_by_app_obj(app_obj,developer_obj) IosUtils.clean_udid_by_app_obj(app_obj, developer_obj)
delete_app_profile_file(developer_obj, app_obj) delete_app_profile_file(developer_obj, app_obj)
@staticmethod @staticmethod
def clean_app_by_developer_obj(app_obj,developer_obj): def clean_app_by_developer_obj(app_obj, developer_obj):
auth = { auth = {
"username": developer_obj.email, "username": developer_obj.email,
"password": developer_obj.password, "password": developer_obj.password,
@ -313,21 +317,21 @@ class IosUtils(object):
app_api_obj = AppDeveloperApi(**auth) app_api_obj = AppDeveloperApi(**auth)
app_api_obj.del_profile(app_obj.bundle_id, app_obj.app_id) app_api_obj.del_profile(app_obj.bundle_id, app_obj.app_id)
app_api_obj2 = AppDeveloperApi(**auth) app_api_obj2 = AppDeveloperApi(**auth)
app_api_obj2.del_app(app_obj.bundle_id,app_obj.app_id) app_api_obj2.del_app(app_obj.bundle_id, app_obj.app_id)
@staticmethod @staticmethod
def clean_developer(developer_obj,user_obj): def clean_developer(developer_obj, user_obj):
''' '''
根据消耗记录 删除该苹果账户下所有信息 根据消耗记录 删除该苹果账户下所有信息
:param developer_obj: :param developer_obj:
:return: :return:
''' '''
for APPToDeveloper_obj in APPToDeveloper.objects.filter(developerid=developer_obj): for APPToDeveloper_obj in APPToDeveloper.objects.filter(developerid=developer_obj):
app_obj=APPToDeveloper_obj.app_id app_obj = APPToDeveloper_obj.app_id
IosUtils.clean_app_by_developer_obj(app_obj, developer_obj) IosUtils.clean_app_by_developer_obj(app_obj, developer_obj)
delete_app_to_dev_and_file(developer_obj,app_obj.id) delete_app_to_dev_and_file(developer_obj, app_obj.id)
IosUtils.clean_udid_by_app_obj(app_obj, developer_obj) IosUtils.clean_udid_by_app_obj(app_obj, developer_obj)
full_path=file_format_path(user_obj, email=developer_obj.email) full_path = file_format_path(user_obj, email=developer_obj.email)
try: try:
for root, dirs, files in os.walk(full_path, topdown=False): for root, dirs, files in os.walk(full_path, topdown=False):
for name in files: for name in files:
@ -338,9 +342,8 @@ class IosUtils(object):
except Exception as e: except Exception as e:
print(e) print(e)
@staticmethod @staticmethod
def active_developer(developer_obj,user_obj): def active_developer(developer_obj, user_obj):
''' '''
激活开发者账户 激活开发者账户
:param developer_obj: :param developer_obj:
@ -353,26 +356,23 @@ class IosUtils(object):
"certid": developer_obj.certid "certid": developer_obj.certid
} }
app_api_obj = AppDeveloperApi(**auth) app_api_obj = AppDeveloperApi(**auth)
status,result = app_api_obj.active(user_obj) status, result = app_api_obj.active(user_obj)
if status: if status:
developer_obj.is_actived=True developer_obj.is_actived = True
developer_obj.save() developer_obj.save()
if not developer_obj.certid : return status, result
IosUtils.create_developer_cert(developer_obj,user_obj)
IosUtils.get_device_from_developer(developer_obj, user_obj)
return status,result
@staticmethod @staticmethod
def create_developer_cert(developer_obj,user_obj): def create_developer_cert(developer_obj, user_obj):
auth = { auth = {
"username": developer_obj.email, "username": developer_obj.email,
"password": developer_obj.password, "password": developer_obj.password,
"certid": developer_obj.certid "certid": developer_obj.certid
} }
app_api_obj = AppDeveloperApi(**auth) app_api_obj = AppDeveloperApi(**auth)
status,result = app_api_obj.create_cert(user_obj) status, result = app_api_obj.create_cert(user_obj)
if status: if status:
file_format_path_name = file_format_path(user_obj,auth) file_format_path_name = file_format_path(user_obj, auth)
cert_info = None cert_info = None
try: try:
with open(file_format_path_name + '.info', "r") as f: with open(file_format_path_name + '.info', "r") as f:
@ -380,26 +380,26 @@ class IosUtils(object):
except Exception as e: except Exception as e:
print(e) print(e)
cert_id = re.findall(r'.*\n\tid=(.*),.*', cert_info)[0].replace('"', '') cert_id = re.findall(r'.*\n\tid=(.*),.*', cert_info)[0].replace('"', '')
developer_obj=AppIOSDeveloperInfo.objects.filter(user_id=user_obj, email=auth.get("username")).first() developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=user_obj, email=auth.get("username")).first()
developer_obj.is_actived=True developer_obj.is_actived = True
developer_obj.certid=cert_id developer_obj.certid = cert_id
developer_obj.save() developer_obj.save()
return status,result return status, result
@staticmethod @staticmethod
def get_device_from_developer(developer_obj,user_obj): def get_device_from_developer(developer_obj, user_obj):
auth = { auth = {
"username": developer_obj.email, "username": developer_obj.email,
"password": developer_obj.password, "password": developer_obj.password,
"certid": developer_obj.certid "certid": developer_obj.certid
} }
app_api_obj = AppDeveloperApi(**auth) app_api_obj = AppDeveloperApi(**auth)
status,result = app_api_obj.get_device(user_obj) status, result = app_api_obj.get_device(user_obj)
if status: if status:
file_format_path_name = file_format_path(user_obj,auth) file_format_path_name = file_format_path(user_obj, auth)
devices_info = "" devices_info = ""
try: try:
with open(file_format_path_name+".devices.info", "r") as f: with open(file_format_path_name + ".devices.info", "r") as f:
devices_info = f.read().replace("\n\t", "").replace("[", "").replace("]", "") devices_info = f.read().replace("\n\t", "").replace("[", "").replace("]", "")
except Exception as e: except Exception as e:
print(e) print(e)
@ -413,9 +413,9 @@ class IosUtils(object):
"udid": formatdevice[0][2], "udid": formatdevice[0][2],
"version": formatdevice[0][3], "version": formatdevice[0][3],
} }
app_udid_obj = UDIDsyncDeveloper.objects.filter(developerid=developer_obj,udid=device.get("udid")) app_udid_obj = UDIDsyncDeveloper.objects.filter(developerid=developer_obj, udid=device.get("udid"))
if app_udid_obj: if app_udid_obj:
pass pass
else: else:
UDIDsyncDeveloper.objects.create(developerid=developer_obj,**device) UDIDsyncDeveloper.objects.create(developerid=developer_obj, **device)
return status,result return status, result

@ -5,6 +5,7 @@ from api.models import Token, UserInfo
from fir_ser.settings import CACHE_KEY_TEMPLATE from fir_ser.settings import CACHE_KEY_TEMPLATE
import base64 import base64
class ExpiringTokenAuthentication(BaseAuthentication): class ExpiringTokenAuthentication(BaseAuthentication):
def authenticate(self, request): def authenticate(self, request):
@ -27,16 +28,16 @@ class ExpiringTokenAuthentication(BaseAuthentication):
cacheuserinfo = cache.get(auth_key) cacheuserinfo = cache.get(auth_key)
if not cacheuserinfo: if not cacheuserinfo:
raise AuthenticationFailed({"code": 1001, "error": "无效的token"}) raise AuthenticationFailed({"code": 1001, "error": "无效的token"})
if user_name != cacheuserinfo.get('username',None): if user_name != cacheuserinfo.get('username', None):
raise AuthenticationFailed({"code": 1001, "error": "token校验失败"}) raise AuthenticationFailed({"code": 1001, "error": "token校验失败"})
user_obj = UserInfo.objects.filter(uid=cacheuserinfo.get('uid',None),username=cacheuserinfo.get("username")).first() user_obj = UserInfo.objects.filter(uid=cacheuserinfo.get('uid', None),
username=cacheuserinfo.get("username")).first()
# token_obj = Token.objects.filter(access_token=auth_token).first() # token_obj = Token.objects.filter(access_token=auth_token).first()
if not user_obj: if not user_obj:
raise AuthenticationFailed({"code": 1001, "error": "无效的token"}) raise AuthenticationFailed({"code": 1001, "error": "无效的token"})
if user_obj.is_active: if user_obj.is_active:
cache.set(auth_key, cacheuserinfo, 3600 * 24 * 7) cache.set(auth_key, cacheuserinfo, 3600 * 24 * 7)
return user_obj,auth_token return user_obj, auth_token
else: else:
raise AuthenticationFailed({"code": 1001, "error": "用户被禁用"}) raise AuthenticationFailed({"code": 1001, "error": "用户被禁用"})

@ -1,5 +1,7 @@
from django.conf import settings from django.conf import settings
from api.utils.geetest import GeeTestLib from api.utils.geetest import GeeTestLib
def verify(verify_data, uid=None, extend_params=None): def verify(verify_data, uid=None, extend_params=None):
"""第三方滑动验证码校验. """第三方滑动验证码校验.
@ -44,4 +46,3 @@ def verify(verify_data, uid=None, extend_params=None):
return True if result else False return True if result else False
else: else:
return True return True

@ -11,7 +11,7 @@ from fir_ser.settings import CACHE_KEY_TEMPLATE
def sync_download_times(): def sync_download_times():
down_tem_key = CACHE_KEY_TEMPLATE.get("download_times_key") down_tem_key = CACHE_KEY_TEMPLATE.get("download_times_key")
key = "_".join([down_tem_key,'*']) key = "_".join([down_tem_key, '*'])
for app_download in cache.iter_keys(key): for app_download in cache.iter_keys(key):
app_id = app_download.split(down_tem_key)[1].strip('_') app_id = app_download.split(down_tem_key)[1].strip('_')
Apps.objects.filter(app_id=app_id).update(count_hits=cache.get(app_download)) Apps.objects.filter(app_id=app_id).update(count_hits=cache.get(app_download))
@ -20,12 +20,9 @@ def sync_download_times():
def sync_download_times_by_app_id(app_ids): def sync_download_times_by_app_id(app_ids):
app_id_lists = [] app_id_lists = []
for app_id in app_ids: for app_id in app_ids:
down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_times_key"),app_id.get("app_id")]) down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_times_key"), app_id.get("app_id")])
app_id_lists.append(down_tem_key) app_id_lists.append(down_tem_key)
down_times_lists = cache.get_many(app_id_lists) down_times_lists = cache.get_many(app_id_lists)
for k, v in down_times_lists.items(): for k, v in down_times_lists.items():
app_id = k.split(CACHE_KEY_TEMPLATE.get("download_times_key"))[1].strip('_') app_id = k.split(CACHE_KEY_TEMPLATE.get("download_times_key"))[1].strip('_')
Apps.objects.filter(app_id=app_id).update(count_hits=v) Apps.objects.filter(app_id=app_id).update(count_hits=v)

@ -196,4 +196,4 @@ class GeeTestLib(object):
for i in userresponse: for i in userresponse:
res += key.get(i, 0) res += key.get(i, 0)
res = res - self._decode_rand_base(challenge) res = res - self._decode_rand_base(challenge)
return res return res

@ -1,12 +1,10 @@
from django.utils.deprecation import MiddlewareMixin from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
def process_response(self,request,response): class CorsMiddleWare(MiddlewareMixin):
if request.method=="OPTIONS": def process_response(self, request, response):
if request.method == "OPTIONS":
response["Access-Control-Allow-Methods"] = "GET,POST,DELETE,PUT" response["Access-Control-Allow-Methods"] = "GET,POST,DELETE,PUT"
response["Access-Control-Allow-Headers"] = "Content-Type,AUTHORIZATION" response["Access-Control-Allow-Headers"] = "Content-Type,AUTHORIZATION"
@ -15,4 +13,4 @@ class CorsMiddleWare(MiddlewareMixin):
response["Cache-Control"] = "no-cache" response["Cache-Control"] = "no-cache"
return response return response

@ -1,5 +1,3 @@
from django.core.cache import cache from django.core.cache import cache
import datetime import datetime
@ -10,12 +8,12 @@ from api.models import Token
from rest_framework.permissions import BasePermission from rest_framework.permissions import BasePermission
class LoginUserPermission(BaseAuthentication): class LoginUserPermission(BaseAuthentication):
def has_permission(self,request,view): def has_permission(self, request, view):
if request.user: if request.user:
return True return True
else: else:
return False return False

@ -1,13 +1,9 @@
class BaseResponse(object): class BaseResponse(object):
def __init__(self): def __init__(self):
self.code=1000 self.code = 1000
self.msg="" self.msg = ""
self.data=None self.data = None
@property @property
def dict(self): def dict(self):
return self.__dict__ return self.__dict__

@ -4,19 +4,22 @@ from api.utils.app.apputils import bytes2human
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.utils import get_developer_udided from api.utils.utils import get_developer_udided
import os,json import os, json
token_obj = DownloadToken() token_obj = DownloadToken()
class UserInfoSerializer(serializers.ModelSerializer):
class UserInfoSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.UserInfo model = models.UserInfo
# fields="__all__" # fields="__all__"
# exclude = ["password","is_active","user_permissions","role",] # exclude = ["password","is_active","user_permissions","role",]
fields=["username","uid","qq","mobile","job","email","domain_name","last_login","first_name",'head_img'] fields = ["username", "uid", "qq", "mobile", "job", "email", "domain_name", "last_login", "first_name",
'head_img']
head_img = serializers.SerializerMethodField() head_img = serializers.SerializerMethodField()
def get_head_img(self,obj):
def get_head_img(self, obj):
storage = Storage(obj) storage = Storage(obj)
return storage.get_download_url(obj.head_img) return storage.get_download_url(obj.head_img)
@ -32,7 +35,7 @@ class AppsSerializer(serializers.ModelSerializer):
def get_has_combo(self, obj): def get_has_combo(self, obj):
if obj.has_combo: if obj.has_combo:
obj.has_combo.has_combo = None obj.has_combo.has_combo = None
return AppsSerializer(obj.has_combo,context=self.context).data return AppsSerializer(obj.has_combo, context=self.context).data
master_release = serializers.SerializerMethodField() master_release = serializers.SerializerMethodField()
@ -44,12 +47,12 @@ class AppsSerializer(serializers.ModelSerializer):
if master_release_obj: if master_release_obj:
icon_url = "" icon_url = ""
key='' key = ''
if self.context.get("key", None) and self.context.get("key") != "undefined": if self.context.get("key", None) and self.context.get("key") != "undefined":
key=self.context.get("key", '') key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined": if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None) storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url),600,key=key) icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url), 600, key=key)
datainfo = { datainfo = {
"app_version": master_release_obj.app_version, "app_version": master_release_obj.app_version,
"icon_url": icon_url, "icon_url": icon_url,
@ -60,16 +63,16 @@ class AppsSerializer(serializers.ModelSerializer):
"binary_size": bytes2human(master_release_obj.binary_size), "binary_size": bytes2human(master_release_obj.binary_size),
"release_id": master_release_obj.release_id, "release_id": master_release_obj.release_id,
"changelog": master_release_obj.changelog, "changelog": master_release_obj.changelog,
"binary_url":master_release_obj.binary_url, "binary_url": master_release_obj.binary_url,
} }
download_token = token_obj.make_token(master_release_obj.release_id,600,key=key) download_token = token_obj.make_token(master_release_obj.release_id, 600, key=key)
datainfo["download_token"] = download_token datainfo["download_token"] = download_token
udid_lists = [] udid_lists = []
try: try:
udid_data = eval(master_release_obj.udid) udid_data = eval(master_release_obj.udid)
for udid in udid_data: for udid in udid_data:
udid_lists.append({'udid':udid}) udid_lists.append({'udid': udid})
except Exception as e: except Exception as e:
pass pass
datainfo["udid"] = udid_lists datainfo["udid"] = udid_lists
@ -79,24 +82,25 @@ class AppsSerializer(serializers.ModelSerializer):
return {} return {}
class AppsShortSerializer(serializers.ModelSerializer): class AppsShortSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.Apps model = models.Apps
fields = ["app_id","name","short","has_combo","isshow","description","need_password",'master_release','type','issupersign'] fields = ["app_id", "name", "short", "has_combo", "isshow", "description", "need_password", 'master_release',
'type', 'issupersign']
need_password=serializers.SerializerMethodField() need_password = serializers.SerializerMethodField()
def get_need_password(self,obj): def get_need_password(self, obj):
if obj.password != '': if obj.password != '':
return True return True
return False return False
has_combo = serializers.SerializerMethodField() has_combo = serializers.SerializerMethodField()
def get_has_combo(self, obj): def get_has_combo(self, obj):
if obj.has_combo: if obj.has_combo:
obj.has_combo.has_combo = None obj.has_combo.has_combo = None
return AppsSerializer(obj.has_combo,context=self.context).data return AppsSerializer(obj.has_combo, context=self.context).data
master_release = serializers.SerializerMethodField() master_release = serializers.SerializerMethodField()
@ -108,12 +112,13 @@ class AppsShortSerializer(serializers.ModelSerializer):
if master_release_obj: if master_release_obj:
icon_url = "" icon_url = ""
key='' key = ''
if self.context.get("key", None) and self.context.get("key") != "undefined": if self.context.get("key", None) and self.context.get("key") != "undefined":
key=self.context.get("key", '') key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined": if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None) storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url),600,key=key,force_new=True) icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url), 600, key=key,
force_new=True)
datainfo = { datainfo = {
"app_version": master_release_obj.app_version, "app_version": master_release_obj.app_version,
"icon_url": icon_url, "icon_url": icon_url,
@ -123,10 +128,10 @@ class AppsShortSerializer(serializers.ModelSerializer):
"binary_size": bytes2human(master_release_obj.binary_size), "binary_size": bytes2human(master_release_obj.binary_size),
"release_id": master_release_obj.release_id, "release_id": master_release_obj.release_id,
"changelog": master_release_obj.changelog, "changelog": master_release_obj.changelog,
"binary_url":master_release_obj.binary_url, "binary_url": master_release_obj.binary_url,
} }
download_token = token_obj.make_token(master_release_obj.release_id,600,key=key,force_new=True) download_token = token_obj.make_token(master_release_obj.release_id, 600, key=key, force_new=True)
datainfo["download_token"] = download_token datainfo["download_token"] = download_token
return datainfo return datainfo
else: else:
@ -139,17 +144,18 @@ class AppReleaseSerializer(serializers.ModelSerializer):
fields = ["app_version", "icon_url", "build_version", fields = ["app_version", "icon_url", "build_version",
"release_type", "minimum_os_version", "release_type", "minimum_os_version",
"created_time", "binary_size", "release_id", "size", "type", "editing", "master_color", "changelog", "created_time", "binary_size", "release_id", "size", "type", "editing", "master_color", "changelog",
"is_master",'download_token','binary_url','udid'] "is_master", 'download_token', 'binary_url', 'udid']
download_token = serializers.SerializerMethodField() download_token = serializers.SerializerMethodField()
size = serializers.SerializerMethodField() size = serializers.SerializerMethodField()
type = serializers.SerializerMethodField() type = serializers.SerializerMethodField()
editing = serializers.SerializerMethodField() editing = serializers.SerializerMethodField()
master_color = serializers.SerializerMethodField() master_color = serializers.SerializerMethodField()
icon_url = serializers.SerializerMethodField() icon_url = serializers.SerializerMethodField()
binary_size= serializers.SerializerMethodField() binary_size = serializers.SerializerMethodField()
udid= serializers.SerializerMethodField() udid = serializers.SerializerMethodField()
def get_udid(self,obj): def get_udid(self, obj):
udid_lists = [] udid_lists = []
try: try:
udid_data = eval(obj.udid) udid_data = eval(obj.udid)
@ -159,23 +165,23 @@ class AppReleaseSerializer(serializers.ModelSerializer):
pass pass
return udid_lists return udid_lists
def get_binary_size(self,obj): def get_binary_size(self, obj):
return bytes2human(obj.binary_size) return bytes2human(obj.binary_size)
def get_download_token(self,obj): def get_download_token(self, obj):
download_token = token_obj.make_token(obj.release_id, 300) download_token = token_obj.make_token(obj.release_id, 300)
return download_token return download_token
def get_icon_url(self, obj): def get_icon_url(self, obj):
icon_url="" icon_url = ""
key = '' key = ''
if self.context.get("key", None) and self.context.get("key") != "undefined": if self.context.get("key", None) and self.context.get("key") != "undefined":
key = self.context.get("key", '') key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined": if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None) storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(obj.icon_url),600,key=key) icon_url = storage.get_download_url(os.path.basename(obj.icon_url), 600, key=key)
return icon_url return icon_url
@ -190,7 +196,7 @@ class AppReleaseSerializer(serializers.ModelSerializer):
return "primary" return "primary"
def get_editing(self, obj): def get_editing(self, obj):
return {"changelog":False,"binary_url":False} return {"changelog": False, "binary_url": False}
class StorageSerializer(serializers.ModelSerializer): class StorageSerializer(serializers.ModelSerializer):
@ -198,12 +204,12 @@ class StorageSerializer(serializers.ModelSerializer):
model = models.AppStorage model = models.AppStorage
exclude = ["user_id"] exclude = ["user_id"]
storage_type_display= serializers.CharField(source="get_storage_type_display",read_only=True) storage_type_display = serializers.CharField(source="get_storage_type_display", read_only=True)
additionalparameters=serializers.CharField(write_only=True) additionalparameters = serializers.CharField(write_only=True)
additionalparameter=serializers.SerializerMethodField(read_only=True) additionalparameter = serializers.SerializerMethodField(read_only=True)
def get_additionalparameter(self,obj): def get_additionalparameter(self, obj):
infos={} infos = {}
try: try:
infos = json.loads(obj.additionalparameters) infos = json.loads(obj.additionalparameters)
except Exception as e: except Exception as e:
@ -213,29 +219,32 @@ class StorageSerializer(serializers.ModelSerializer):
def create(self, validated_data): def create(self, validated_data):
if self.context.get("user_obj", None) and self.context.get("user_obj") != "undefined": if self.context.get("user_obj", None) and self.context.get("user_obj") != "undefined":
user_obj = self.context.get("user_obj", None) user_obj = self.context.get("user_obj", None)
storage_obj = models.AppStorage.objects.create(**validated_data,user_id=user_obj,) storage_obj = models.AppStorage.objects.create(**validated_data, user_id=user_obj, )
return storage_obj return storage_obj
return None return None
class DeveloperSerializer(serializers.ModelSerializer): class DeveloperSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.AppIOSDeveloperInfo model = models.AppIOSDeveloperInfo
# depth = 1 # depth = 1
exclude = ["password", "id","user_id"] exclude = ["password", "id", "user_id"]
developer_used_number = serializers.SerializerMethodField() developer_used_number = serializers.SerializerMethodField()
developer_used_other_number = serializers.SerializerMethodField() developer_used_other_number = serializers.SerializerMethodField()
def get_developer_used_number(self,obj):
def get_developer_used_number(self, obj):
return models.UDIDsyncDeveloper.objects.filter(developerid=obj).count() return models.UDIDsyncDeveloper.objects.filter(developerid=obj).count()
def get_developer_used_other_number(self,obj): def get_developer_used_other_number(self, obj):
return get_developer_udided(obj)[0] return get_developer_udided(obj)[0]
class SuperSignUsedSerializer(serializers.ModelSerializer): class SuperSignUsedSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.APPSuperSignUsedInfo model = models.APPSuperSignUsedInfo
# depth = 1 # depth = 1
fields = ["created_time","device_udid","device_name","developer_id","bundle_id","bundle_name"] fields = ["created_time", "device_udid", "device_name", "developer_id", "bundle_id", "bundle_name"]
device_udid = serializers.SerializerMethodField() device_udid = serializers.SerializerMethodField()
device_name = serializers.SerializerMethodField() device_name = serializers.SerializerMethodField()
@ -243,13 +252,13 @@ class SuperSignUsedSerializer(serializers.ModelSerializer):
bundle_id = serializers.SerializerMethodField() bundle_id = serializers.SerializerMethodField()
bundle_name = serializers.SerializerMethodField() bundle_name = serializers.SerializerMethodField()
def get_device_udid(self,obj): def get_device_udid(self, obj):
return obj.udid.udid return obj.udid.udid
def get_device_name(self,obj): def get_device_name(self, obj):
return obj.udid.product return obj.udid.product
def get_developer_id(self,obj): def get_developer_id(self, obj):
return obj.developerid.email return obj.developerid.email
def get_bundle_id(self, obj): def get_bundle_id(self, obj):
@ -263,7 +272,7 @@ class DeviceUDIDSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.AppUDID model = models.AppUDID
# depth = 1 # depth = 1
exclude = ["binary_file","updated_time","is_signed"] exclude = ["binary_file", "updated_time", "is_signed"]
bundle_id = serializers.SerializerMethodField() bundle_id = serializers.SerializerMethodField()
bundle_name = serializers.SerializerMethodField() bundle_name = serializers.SerializerMethodField()
@ -272,4 +281,4 @@ class DeviceUDIDSerializer(serializers.ModelSerializer):
return obj.app_id.bundle_id return obj.app_id.bundle_id
def get_bundle_name(self, obj): def get_bundle_name(self, obj):
return obj.app_id.name return obj.app_id.name

@ -4,7 +4,7 @@
# author: liuyu # author: liuyu
# date: 2020/3/22 # date: 2020/3/22
#pip install aliyun-python-sdk-sts oss2 # pip install aliyun-python-sdk-sts oss2
import json import json
import os import os
@ -40,31 +40,32 @@ class StsToken(object):
:param str security_token: 临时用户Token :param str security_token: 临时用户Token
:param str request_id: 请求ID :param str request_id: 请求ID
""" """
def __init__(self): def __init__(self):
self.access_key_id = '' self.access_key_id = ''
self.access_key_secret = '' self.access_key_secret = ''
self.expiration = 3600 self.expiration = 3600
self.security_token = '' self.security_token = ''
self.request_id = '' self.request_id = ''
self.bucket='' self.bucket = ''
self.endpoint='' self.endpoint = ''
class AliYunOss(object): class AliYunOss(object):
def __init__(self,access_key,secret_key,bucket_name,endpoint,sts_role_arn,is_https,domain_name=None): def __init__(self, access_key, secret_key, bucket_name, endpoint, sts_role_arn, is_https, domain_name=None):
self.access_key_id = access_key or os.getenv('OSS_TEST_STS_ID', 'LTAI4FeTyvz74CHKCbYuTDGc') self.access_key_id = access_key or os.getenv('OSS_TEST_STS_ID', 'LTAI4FeTyvz74CHKCbYuTDGc')
self.access_key_secret = secret_key or os.getenv('OSS_TEST_STS_KEY', 'uineAEE7tp1d1w4Mv0yLqxvV0IVNTy') self.access_key_secret = secret_key or os.getenv('OSS_TEST_STS_KEY', 'uineAEE7tp1d1w4Mv0yLqxvV0IVNTy')
self.bucket_name = bucket_name or os.getenv('OSS_TEST_BUCKET', 'fir-storage') self.bucket_name = bucket_name or os.getenv('OSS_TEST_BUCKET', 'fir-storage')
self.endpoint = endpoint or os.getenv('OSS_TEST_ENDPOINT', 'oss-cn-beijing.aliyuncs.com') self.endpoint = endpoint or os.getenv('OSS_TEST_ENDPOINT', 'oss-cn-beijing.aliyuncs.com')
self.sts_role_arn = sts_role_arn or os.getenv('OSS_TEST_STS_ARN', 'acs:ram::1622120977387033:role/appstorage') self.sts_role_arn = sts_role_arn or os.getenv('OSS_TEST_STS_ARN', 'acs:ram::1622120977387033:role/appstorage')
self.region_id = '-'.join( self.endpoint.split('.')[0].split("-")[1:3]) self.region_id = '-'.join(self.endpoint.split('.')[0].split("-")[1:3])
self.token = StsToken() self.token = StsToken()
self.is_https = is_https self.is_https = is_https
self.domain_name = domain_name self.domain_name = domain_name
self.get_auth_bucket('init', 900) self.get_auth_bucket('init', 900)
def fetch_sts_token(self, name, expires):
def fetch_sts_token(self,name,expires):
"""子用户角色扮演获取临时用户的密钥 """子用户角色扮演获取临时用户的密钥
:param access_key_id: 子用户的 access key id :param access_key_id: 子用户的 access key id
:param access_key_secret: 子用户的 access key secret :param access_key_secret: 子用户的 access key secret
@ -88,34 +89,34 @@ class AliYunOss(object):
self.token.security_token = j['Credentials']['SecurityToken'] self.token.security_token = j['Credentials']['SecurityToken']
self.token.request_id = j['RequestId'] self.token.request_id = j['RequestId']
self.token.expiration = oss2.utils.to_unixtime(j['Credentials']['Expiration'], '%Y-%m-%dT%H:%M:%SZ') self.token.expiration = oss2.utils.to_unixtime(j['Credentials']['Expiration'], '%Y-%m-%dT%H:%M:%SZ')
self.token.bucket=self.bucket_name self.token.bucket = self.bucket_name
self.token.endpoint=self.endpoint self.token.endpoint = self.endpoint
return self.token.__dict__ return self.token.__dict__
def get_upload_token(self,name,expires=1800): def get_upload_token(self, name, expires=1800):
return self.fetch_sts_token(name,expires) return self.fetch_sts_token(name, expires)
def get_auth_bucket(self,name,expires): def get_auth_bucket(self, name, expires):
self.fetch_sts_token(name,expires) self.fetch_sts_token(name, expires)
uri = 'http://' uri = 'http://'
if self.is_https: if self.is_https:
uri = 'https://' uri = 'https://'
url = self.endpoint url = self.endpoint
is_cname=False is_cname = False
if self.domain_name: if self.domain_name:
url = self.domain_name url = self.domain_name
is_cname=True is_cname = True
auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token) auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token)
self.bucket = oss2.Bucket(auth,uri+url,self.bucket_name,is_cname=is_cname) self.bucket = oss2.Bucket(auth, uri + url, self.bucket_name, is_cname=is_cname)
def get_download_url(self,name,expires=1800,ftype=None,force_new=False): def get_download_url(self, name, expires=1800, ftype=None, force_new=False):
# self.get_auth_bucket(name,expires) # self.get_auth_bucket(name,expires)
private_url=self.bucket.sign_url('GET',name,expires) private_url = self.bucket.sign_url('GET', name, expires)
return private_url return private_url
def del_file(self,name): def del_file(self, name):
# self.fetch_sts_token(name,expires=300) # self.fetch_sts_token(name,expires=300)
# auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token) # auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token)
# bucket = oss2.Bucket(auth, self.endpoint,self.bucket_name) # bucket = oss2.Bucket(auth, self.endpoint,self.bucket_name)
return self.bucket.delete_object(name) return self.bucket.delete_object(name)

@ -5,33 +5,39 @@
# date: 2020/4/7 # date: 2020/4/7
from django.core.cache import cache from django.core.cache import cache
from api.models import Apps,UserInfo,AppReleaseInfo,AppUDID,APPToDeveloper,APPSuperSignUsedInfo from api.models import Apps, UserInfo, AppReleaseInfo, AppUDID, APPToDeveloper, APPSuperSignUsedInfo
import time,os import time, os
from django.utils import timezone from django.utils import timezone
from fir_ser.settings import CACHE_KEY_TEMPLATE,SERVER_DOMAIN from fir_ser.settings import CACHE_KEY_TEMPLATE, SERVER_DOMAIN
from api.utils.storage.storage import Storage,LocalStorage from api.utils.storage.storage import Storage, LocalStorage
from api.utils.crontab.sync_cache import sync_download_times_by_app_id from api.utils.crontab.sync_cache import sync_download_times_by_app_id
from api.utils.utils import file_format_path from api.utils.utils import file_format_path
try: try:
from api.utils.crontab import run from api.utils.crontab import run
except Exception as e: except Exception as e:
print(e) print(e)
def get_download_url_by_cache(app_obj, filename, limit, isdownload=True,key='',udid=None):
def get_download_url_by_cache(app_obj, filename, limit, isdownload=True, key='', udid=None):
now = time.time() now = time.time()
if isdownload is None: if isdownload is None:
local_storage = LocalStorage(**SERVER_DOMAIN.get("IOS_PMFILE_DOWNLOAD_DOMAIN")) local_storage = LocalStorage(**SERVER_DOMAIN.get("IOS_PMFILE_DOWNLOAD_DOMAIN"))
download_url_type = 'plist' download_url_type = 'plist'
if not udid: if not udid:
if app_obj.get('issupersign',None): if app_obj.get('issupersign', None):
download_url_type = 'mobileconifg' download_url_type = 'mobileconifg'
else: else:
appudid_obj = AppUDID.objects.filter(app_id_id=app_obj.get("pk"),udid=udid,is_signed=True).first() appudid_obj = AppUDID.objects.filter(app_id_id=app_obj.get("pk"), udid=udid, is_signed=True).first()
if appudid_obj: if appudid_obj:
SuperSign_obj = APPSuperSignUsedInfo.objects.filter(udid__udid=udid,app_id_id=app_obj.get("pk")).first() SuperSign_obj = APPSuperSignUsedInfo.objects.filter(udid__udid=udid,
app_id_id=app_obj.get("pk")).first()
if SuperSign_obj: if SuperSign_obj:
APPToDeveloper_obj = APPToDeveloper.objects.filter(app_id_id=app_obj.get("pk"),developerid=SuperSign_obj.developerid).first() APPToDeveloper_obj = APPToDeveloper.objects.filter(app_id_id=app_obj.get("pk"),
developerid=SuperSign_obj.developerid).first()
if APPToDeveloper_obj: if APPToDeveloper_obj:
return local_storage.get_download_url(APPToDeveloper_obj.binary_file+"."+filename.split(".")[-1], limit, download_url_type) return local_storage.get_download_url(
APPToDeveloper_obj.binary_file + "." + filename.split(".")[-1], limit, download_url_type)
else: else:
return "" return ""
else: else:
@ -51,16 +57,17 @@ def get_download_url_by_cache(app_obj, filename, limit, isdownload=True,key='',u
return storage.get_download_url(filename, limit) return storage.get_download_url(filename, limit)
def get_app_instance_by_cache(app_id,password, limit,udid): def get_app_instance_by_cache(app_id, password, limit, udid):
if udid: if udid:
return Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type','password','issupersign').first() return Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type', 'password', 'issupersign').first()
app_key="_".join([CACHE_KEY_TEMPLATE.get("app_instance_key"),app_id]) app_key = "_".join([CACHE_KEY_TEMPLATE.get("app_instance_key"), app_id])
app_obj_cache = cache.get(app_key) app_obj_cache = cache.get(app_key)
if not app_obj_cache: if not app_obj_cache:
app_obj_cache = Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type','password','issupersign').first() app_obj_cache = Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type', 'password',
'issupersign').first()
cache.set(app_key, app_obj_cache, limit) cache.set(app_key, app_obj_cache, limit)
app_password=app_obj_cache.get("password") app_password = app_obj_cache.get("password")
if app_password != '': if app_password != '':
if password is None: if password is None:
@ -73,10 +80,10 @@ def get_app_instance_by_cache(app_id,password, limit,udid):
def set_app_download_by_cache(app_id, limit=900): def set_app_download_by_cache(app_id, limit=900):
down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_times_key"),app_id]) down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_times_key"), app_id])
download_times = cache.get(down_tem_key) download_times = cache.get(down_tem_key)
if not download_times: if not download_times:
download_times=Apps.objects.filter(app_id=app_id).values("count_hits").first().get('count_hits') download_times = Apps.objects.filter(app_id=app_id).values("count_hits").first().get('count_hits')
cache.set(down_tem_key, download_times + 1, limit) cache.set(down_tem_key, download_times + 1, limit)
else: else:
cache.incr(down_tem_key) cache.incr(down_tem_key)
@ -84,74 +91,81 @@ def set_app_download_by_cache(app_id, limit=900):
set_app_today_download_times(app_id) set_app_today_download_times(app_id)
return download_times + 1 return download_times + 1
def del_cache_response_by_short(short,app_id,udid=''):
cache.delete("_".join([CACHE_KEY_TEMPLATE.get("download_short_key"),short])) def del_cache_response_by_short(short, app_id, udid=''):
key = "_".join([CACHE_KEY_TEMPLATE.get("download_short_key"),short,'*']) cache.delete("_".join([CACHE_KEY_TEMPLATE.get("download_short_key"), short]))
key = "_".join([CACHE_KEY_TEMPLATE.get("download_short_key"), short, '*'])
for app_download_key in cache.iter_keys(key): for app_download_key in cache.iter_keys(key):
cache.delete(app_download_key) cache.delete(app_download_key)
cache.delete("_".join([CACHE_KEY_TEMPLATE.get("app_instance_key"),app_id])) cache.delete("_".join([CACHE_KEY_TEMPLATE.get("app_instance_key"), app_id]))
key='ShortDownloadView'.lower() key = 'ShortDownloadView'.lower()
master_release_dict = AppReleaseInfo.objects.filter(app_id__app_id=app_id,is_master=True).values('icon_url','release_id').first() master_release_dict = AppReleaseInfo.objects.filter(app_id__app_id=app_id, is_master=True).values('icon_url',
'release_id').first()
if master_release_dict: if master_release_dict:
download_val = CACHE_KEY_TEMPLATE.get('download_url_key') download_val = CACHE_KEY_TEMPLATE.get('download_url_key')
cache.delete("_".join([key, download_val, os.path.basename(master_release_dict.get("icon_url")),udid])) cache.delete("_".join([key, download_val, os.path.basename(master_release_dict.get("icon_url")), udid]))
cache.delete("_".join([key,download_val, master_release_dict.get('release_id'),udid])) cache.delete("_".join([key, download_val, master_release_dict.get('release_id'), udid]))
cache.delete("_".join([key, CACHE_KEY_TEMPLATE.get("make_token_key"), master_release_dict.get('release_id'),udid])) cache.delete(
"_".join([key, CACHE_KEY_TEMPLATE.get("make_token_key"), master_release_dict.get('release_id'), udid]))
def del_cache_by_app_id(app_id,user_obj): def del_cache_by_app_id(app_id, user_obj):
key='' key = ''
master_release_dict = AppReleaseInfo.objects.filter(app_id__app_id=app_id,is_master=True).values('icon_url','release_id').first() 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') 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, 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, 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')])) cache.delete(
cache.delete("_".join([key,download_val,user_obj.head_img])) "_".join([key.lower(), CACHE_KEY_TEMPLATE.get("make_token_key"), master_release_dict.get('release_id')]))
cache.delete("_".join([key, download_val, user_obj.head_img]))
def del_cache_storage(user_obj): def del_cache_storage(user_obj):
for app_obj in Apps.objects.filter(user_id=user_obj): for app_obj in Apps.objects.filter(user_id=user_obj):
del_cache_response_by_short(app_obj.short, app_obj.app_id) del_cache_response_by_short(app_obj.short, app_obj.app_id)
del_cache_by_app_id(app_obj.app_id,user_obj) del_cache_by_app_id(app_obj.app_id, user_obj)
storage_keys = "_".join([CACHE_KEY_TEMPLATE.get('user_storage_key'),user_obj.uid,'*']) storage_keys = "_".join([CACHE_KEY_TEMPLATE.get('user_storage_key'), user_obj.uid, '*'])
for storage_key in cache.iter_keys(storage_keys): for storage_key in cache.iter_keys(storage_keys):
cache.delete(storage_key) cache.delete(storage_key)
def set_app_today_download_times(app_id): def set_app_today_download_times(app_id):
now = timezone.now() now = timezone.now()
down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_today_times_key"), down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_today_times_key"),
str(now.year),str(now.month),str(now.day),app_id]) str(now.year), str(now.month), str(now.day), app_id])
if cache.get(down_tem_key): if cache.get(down_tem_key):
cache.incr(down_tem_key) cache.incr(down_tem_key)
else: else:
cache.set(down_tem_key,1,3600*24) cache.set(down_tem_key, 1, 3600 * 24)
def get_app_today_download_times(app_ids): def get_app_today_download_times(app_ids):
sync_download_times_by_app_id(app_ids) sync_download_times_by_app_id(app_ids)
now = timezone.now() now = timezone.now()
app_id_lists=[] app_id_lists = []
download_times_count=0 download_times_count = 0
for app_id in app_ids: for app_id in app_ids:
down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_today_times_key"), down_tem_key = "_".join([CACHE_KEY_TEMPLATE.get("download_today_times_key"),
str(now.year),str(now.month),str(now.day),app_id.get("app_id")]) str(now.year), str(now.month), str(now.day), app_id.get("app_id")])
app_id_lists.append(down_tem_key) app_id_lists.append(down_tem_key)
down_times_lists = cache.get_many(app_id_lists) down_times_lists = cache.get_many(app_id_lists)
for k, v in down_times_lists.items(): for k, v in down_times_lists.items():
download_times_count+=v download_times_count += v
return download_times_count return download_times_count
def developer_auth_code(act,user_obj,developer_email,code=None): def developer_auth_code(act, user_obj, developer_email, code=None):
auth_key=file_format_path(user_obj,email=developer_email) auth_key = file_format_path(user_obj, email=developer_email)
key = "_".join([CACHE_KEY_TEMPLATE.get("developer_auth_code_key"),auth_key]) key = "_".join([CACHE_KEY_TEMPLATE.get("developer_auth_code_key"), auth_key])
if act == "set": if act == "set":
cache.delete(key) cache.delete(key)
cache.set(key,code,60*10) cache.set(key, code, 60 * 10)
elif act == "get": elif act == "get":
return cache.get(key) return cache.get(key)
elif act == "del": elif act == "del":
cache.delete(key) cache.delete(key)

@ -10,31 +10,31 @@ from api.utils.TokenManager import DownloadToken
from fir_ser import settings from fir_ser import settings
import os import os
class LocalStorage(object): class LocalStorage(object):
def __init__(self,domain_name,is_https): def __init__(self, domain_name, is_https):
self.domain_name = domain_name self.domain_name = domain_name
self.is_https = is_https self.is_https = is_https
def get_upload_token(self,name,expires): def get_upload_token(self, name, expires):
dtoken = DownloadToken() dtoken = DownloadToken()
return dtoken.make_token(name,expires) return dtoken.make_token(name, expires)
def get_download_url(self,name,expires=1800,ftype=None,force_new=False): def get_download_url(self, name, expires=1800, ftype=None, force_new=False):
dtoken = DownloadToken() dtoken = DownloadToken()
base_url = '/'.join([self.domain_name,'download', name]) base_url = '/'.join([self.domain_name, 'download', name])
uri='http://' uri = 'http://'
if self.is_https: if self.is_https:
uri='https://' uri = 'https://'
download_url = uri+ base_url + "?token=" + dtoken.make_token(name,expires,force_new=force_new) download_url = uri + base_url + "?token=" + dtoken.make_token(name, expires, force_new=force_new)
if ftype: if ftype:
download_url = download_url + '&ftype=' + ftype download_url = download_url + '&ftype=' + ftype
return download_url return download_url
def del_file(self,name): def del_file(self, name):
try: try:
os.remove(os.path.join(settings.MEDIA_ROOT, name)) os.remove(os.path.join(settings.MEDIA_ROOT, name))
return True return True
except Exception as e: except Exception as e:
print(e) print(e)
return False return False

@ -9,16 +9,17 @@
from qiniu import Auth from qiniu import Auth
from qiniu import BucketManager from qiniu import BucketManager
class QiNiuOss(object): class QiNiuOss(object):
def __init__(self,access_key,secret_key,bucket_name,domain_name,is_https): def __init__(self, access_key, secret_key, bucket_name, domain_name, is_https):
access_key=access_key access_key = access_key
secret_key=secret_key secret_key = secret_key
self.bucket_name = bucket_name self.bucket_name = bucket_name
self.domain_name = domain_name self.domain_name = domain_name
self.is_https = is_https self.is_https = is_https
self.qiniu_obj = Auth(access_key,secret_key) self.qiniu_obj = Auth(access_key, secret_key)
def get_upload_token(self,name,expires=1800): def get_upload_token(self, name, expires=1800):
# 生成上传 Token,可以指定过期时间等 # 生成上传 Token,可以指定过期时间等
# 上传策略示例 # 上传策略示例
# https://developer.qiniu.com/kodo/manual/1206/put-policy # https://developer.qiniu.com/kodo/manual/1206/put-policy
@ -32,21 +33,20 @@ class QiNiuOss(object):
# print(token) # print(token)
return token return token
def get_download_url(self,name,expires=1800,ftype=None,force_new=False): def get_download_url(self, name, expires=1800, ftype=None, force_new=False):
#有两种方式构造base_url的形式 # 有两种方式构造base_url的形式
uri = 'http://' uri = 'http://'
if self.is_https: if self.is_https:
uri = 'https://' uri = 'https://'
base_url = '%s%s/%s' % (uri,self.domain_name, name) base_url = '%s%s/%s' % (uri, self.domain_name, name)
#或者直接输入url的方式下载 # 或者直接输入url的方式下载
#可以设置token过期时间 # 可以设置token过期时间
private_url = self.qiniu_obj.private_download_url(base_url, expires=expires) private_url = self.qiniu_obj.private_download_url(base_url, expires=expires)
return private_url return private_url
def del_file(self,name): def del_file(self, name):
# 初始化BucketManager # 初始化BucketManager
bucket = BucketManager(self.qiniu_obj) bucket = BucketManager(self.qiniu_obj)
# 删除bucket_name 中的文件 key # 删除bucket_name 中的文件 key
ret, info = bucket.delete(self.bucket_name, name) ret, info = bucket.delete(self.bucket_name, name)
return ret return ret

@ -18,13 +18,13 @@ class Storage(object):
try: try:
self.storage = self.get_storage(user) self.storage = self.get_storage(user)
except Exception as e: except Exception as e:
self.storage=None self.storage = None
def get_upload_token(self, filename, expires=900): def get_upload_token(self, filename, expires=900):
if self.storage: if self.storage:
return self.storage.get_upload_token(filename, expires) return self.storage.get_upload_token(filename, expires)
def get_download_url(self, filename, expires=900, ftype=None, key='',force_new=False): def get_download_url(self, filename, expires=900, ftype=None, key='', force_new=False):
if self.storage: if self.storage:
now = time.time() now = time.time()
down_key = "_".join([key.lower(), CACHE_KEY_TEMPLATE.get('download_url_key'), filename]) down_key = "_".join([key.lower(), CACHE_KEY_TEMPLATE.get('download_url_key'), filename])
@ -33,7 +33,7 @@ class Storage(object):
if download_val.get("time") > now - 60: if download_val.get("time") > now - 60:
return download_val.get("download_url") return download_val.get("download_url")
download_url = self.storage.get_download_url(filename, expires, ftype,force_new=False) download_url = self.storage.get_download_url(filename, expires, ftype, force_new=False)
cache.set(down_key, {"download_url": download_url, "time": now + expires}, expires) cache.set(down_key, {"download_url": download_url, "time": now + expires}, expires)
return download_url return download_url
@ -50,7 +50,7 @@ class Storage(object):
self.storage_obj = user.storage self.storage_obj = user.storage
if self.storage_obj: if self.storage_obj:
auth = self.get_storage_auth(self.storage_obj) auth = self.get_storage_auth(self.storage_obj)
storage_key = "_".join([CACHE_KEY_TEMPLATE.get('user_storage_key'),user.uid, storage_key = "_".join([CACHE_KEY_TEMPLATE.get('user_storage_key'), user.uid,
base64.b64encode(json.dumps(auth).encode("utf-8")).decode("utf-8")[0:64]]) base64.b64encode(json.dumps(auth).encode("utf-8")).decode("utf-8")[0:64]])
storage_type = self.storage_obj.storage_type storage_type = self.storage_obj.storage_type
new_storage_obj = cache.get(storage_key) new_storage_obj = cache.get(storage_key)
@ -70,7 +70,7 @@ class Storage(object):
else: else:
return self.get_default_storage(user) return self.get_default_storage(user)
def get_default_storage(self,user): def get_default_storage(self, user):
admin_obj = UserInfo.objects.filter(is_superuser=True).order_by('pk').first() admin_obj = UserInfo.objects.filter(is_superuser=True).order_by('pk').first()
if admin_obj and admin_obj.storage: if admin_obj and admin_obj.storage:
return self.get_storage(admin_obj) return self.get_storage(admin_obj)
@ -80,7 +80,7 @@ class Storage(object):
if storage.get("active", None): if storage.get("active", None):
storage_type = storage.get('type', None) storage_type = storage.get('type', None)
auth = storage.get('auth', {}) auth = storage.get('auth', {})
storage_key = "_".join([CACHE_KEY_TEMPLATE.get('user_storage_key'),user.uid, storage_key = "_".join([CACHE_KEY_TEMPLATE.get('user_storage_key'), user.uid,
base64.b64encode(json.dumps(auth).encode("utf-8")).decode("utf-8")[0:64]]) base64.b64encode(json.dumps(auth).encode("utf-8")).decode("utf-8")[0:64]])
new_storage_obj = cache.get(storage_key) new_storage_obj = cache.get(storage_key)
if new_storage_obj: if new_storage_obj:

@ -3,15 +3,15 @@
# project: 5月 # project: 5月
# author: liuyu # author: liuyu
# date: 2020/5/7 # date: 2020/5/7
import os import os
from fir_ser.settings import SUPER_SIGN_ROOT from fir_ser.settings import SUPER_SIGN_ROOT
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo,Apps,APPToDeveloper,UDIDsyncDeveloper from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper
from api.utils.app.randomstrings import make_app_uuid from api.utils.app.randomstrings import make_app_uuid
from api.utils.storage.localApi import LocalStorage from api.utils.storage.localApi import LocalStorage
from django.db.models import Sum from django.db.models import Sum
def file_format_path(user_obj, auth=None, email=None): def file_format_path(user_obj, auth=None, email=None):
if email: if email:
cert_dir_name = make_app_uuid(user_obj, email) cert_dir_name = make_app_uuid(user_obj, email)
@ -48,16 +48,15 @@ def delete_app_profile_file(developer_obj, app_obj):
def get_developer_udided(developer_obj): def get_developer_udided(developer_obj):
SuperSignUsed_obj = APPSuperSignUsedInfo.objects.filter(developerid=developer_obj ) SuperSignUsed_obj = APPSuperSignUsedInfo.objects.filter(developerid=developer_obj)
UDIDsyncDeveloper_obj = UDIDsyncDeveloper.objects.filter(developerid=developer_obj) UDIDsyncDeveloper_obj = UDIDsyncDeveloper.objects.filter(developerid=developer_obj)
develoer_udid_lists=[] develoer_udid_lists = []
supersign_udid_lists=[] supersign_udid_lists = []
if UDIDsyncDeveloper_obj: if UDIDsyncDeveloper_obj:
develoer_udid_lists=list(UDIDsyncDeveloper_obj.values_list("udid")) develoer_udid_lists = list(UDIDsyncDeveloper_obj.values_list("udid"))
if SuperSignUsed_obj: if SuperSignUsed_obj:
supersign_udid_lists=list(SuperSignUsed_obj.values_list("udid__udid")) supersign_udid_lists = list(SuperSignUsed_obj.values_list("udid__udid"))
return len(set(develoer_udid_lists)-set(supersign_udid_lists)),len(develoer_udid_lists) return len(set(develoer_udid_lists) - set(supersign_udid_lists)), len(develoer_udid_lists)
def get_developer_devices(developer_obj_lists): def get_developer_devices(developer_obj_lists):

@ -8,17 +8,18 @@ from rest_framework.views import APIView
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from api.utils.auth import ExpiringTokenAuthentication from api.utils.auth import ExpiringTokenAuthentication
from rest_framework.response import Response from rest_framework.response import Response
from django.db.models import Sum,F from django.db.models import Sum, F
import os import os
from fir_ser import settings from fir_ser import settings
from api.utils.app.supersignutils import IosUtils from api.utils.app.supersignutils import IosUtils
from api.utils.app.randomstrings import make_from_user_uuid from api.utils.app.randomstrings import make_from_user_uuid
from api.utils.storage.storage import Storage 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.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times
from api.models import Apps, AppReleaseInfo,APPToDeveloper from api.models import Apps, AppReleaseInfo, APPToDeveloper
from api.utils.serializer import AppsSerializer, AppReleaseSerializer, UserInfoSerializer from api.utils.serializer import AppsSerializer, AppReleaseSerializer, UserInfoSerializer
from rest_framework.pagination import PageNumberPagination from rest_framework.pagination import PageNumberPagination
class AppsPageNumber(PageNumberPagination): class AppsPageNumber(PageNumberPagination):
page_size = 20 # 每页显示多少条 page_size = 20 # 每页显示多少条
page_size_query_param = 'size' # URL中每页显示条数的参数 page_size_query_param = 'size' # URL中每页显示条数的参数
@ -59,7 +60,6 @@ class AppsView(APIView):
else: else:
res.hdata["all_hits_count"] = 0 res.hdata["all_hits_count"] = 0
if app_type == "android": if app_type == "android":
filter_data = {"user_id": request.user, "type": 0} filter_data = {"user_id": request.user, "type": 0}
@ -104,7 +104,7 @@ class AppInfoView(APIView):
userserializer = UserInfoSerializer(request.user) userserializer = UserInfoSerializer(request.user)
res.userinfo = {} res.userinfo = {}
res.userinfo = userserializer.data res.userinfo = userserializer.data
count=APPToDeveloper.objects.filter(app_id=apps_obj).count() count = APPToDeveloper.objects.filter(app_id=apps_obj).count()
res.data["count"] = count res.data["count"] = count
return Response(res.dict) return Response(res.dict)
@ -120,9 +120,9 @@ class AppInfoView(APIView):
storage = Storage(request.user) storage = Storage(request.user)
has_combo = apps_obj.has_combo has_combo = apps_obj.has_combo
if has_combo: if has_combo:
del_cache_response_by_short(apps_obj.has_combo.short,apps_obj.has_combo.app_id) del_cache_response_by_short(apps_obj.has_combo.short, apps_obj.has_combo.app_id)
apps_obj.has_combo.has_combo = None apps_obj.has_combo.has_combo = None
del_cache_response_by_short(apps_obj.short,apps_obj.app_id) del_cache_response_by_short(apps_obj.short, apps_obj.app_id)
for appreleaseobj in AppReleaseInfo.objects.filter(app_id=apps_obj).all(): for appreleaseobj in AppReleaseInfo.objects.filter(app_id=apps_obj).all():
storage.delete_file(appreleaseobj.release_id, appreleaseobj.release_type) storage.delete_file(appreleaseobj.release_id, appreleaseobj.release_type)
storage.delete_file(appreleaseobj.icon_url) storage.delete_file(appreleaseobj.icon_url)
@ -136,10 +136,10 @@ class AppInfoView(APIView):
if app_id: if app_id:
data = request.data data = request.data
clean = data.get("clean",None) clean = data.get("clean", None)
if clean : if clean:
apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first() apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
IosUtils.clean_app_by_user_obj(apps_obj,request.user) IosUtils.clean_app_by_user_obj(apps_obj, request.user)
return Response(res.dict) return Response(res.dict)
has_combo = data.get("has_combo", None) has_combo = data.get("has_combo", None)
@ -161,8 +161,8 @@ class AppInfoView(APIView):
has_combo.update(**{"has_combo": apps_obj.first()}) has_combo.update(**{"has_combo": apps_obj.first()})
else: else:
pass pass
del_cache_response_by_short(apps_obj.first().short,apps_obj.first().app_id) del_cache_response_by_short(apps_obj.first().short, apps_obj.first().app_id)
del_cache_response_by_short(has_combo.first().short,has_combo.first().app_id) del_cache_response_by_short(has_combo.first().short, has_combo.first().app_id)
except Exception as e: except Exception as e:
res.code = 1004 res.code = 1004
@ -171,7 +171,7 @@ class AppInfoView(APIView):
try: try:
apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first() apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
apps_obj.description = data.get("description", apps_obj.description) apps_obj.description = data.get("description", apps_obj.description)
del_cache_response_by_short(apps_obj.short,apps_obj.app_id) del_cache_response_by_short(apps_obj.short, apps_obj.app_id)
apps_obj.short = data.get("short", apps_obj.short) apps_obj.short = data.get("short", apps_obj.short)
apps_obj.name = data.get("name", apps_obj.name) apps_obj.name = data.get("name", apps_obj.name)
apps_obj.password = data.get("password", apps_obj.password) apps_obj.password = data.get("password", apps_obj.password)
@ -236,7 +236,7 @@ class AppInfoView(APIView):
release_obj.icon_url = release_obj.icon_url.replace(old_file_name.split(".")[0], release_obj.icon_url = release_obj.icon_url.replace(old_file_name.split(".")[0],
random_file_name) random_file_name)
release_obj.save() release_obj.save()
del_cache_response_by_short(apps_obj.short,apps_obj.app_id) del_cache_response_by_short(apps_obj.short, apps_obj.app_id)
storage = Storage(request.user) storage = Storage(request.user)
storage.delete_file(old_file_name) storage.delete_file(old_file_name)
@ -295,7 +295,7 @@ class AppReleaseinfoView(APIView):
apps_obj.delete() apps_obj.delete()
else: else:
pass pass
del_cache_response_by_short(apps_obj.short,apps_obj.app_id) del_cache_response_by_short(apps_obj.short, apps_obj.app_id)
return Response(res.dict) return Response(res.dict)
@ -330,7 +330,7 @@ class AppReleaseinfoView(APIView):
res.msg = "更新失败" res.msg = "更新失败"
return Response(res.dict) return Response(res.dict)
del_cache_response_by_short(apps_obj.short,apps_obj.app_id) del_cache_response_by_short(apps_obj.short, apps_obj.app_id)
app_serializer = AppsSerializer(apps_obj) app_serializer = AppsSerializer(apps_obj)
res.data["currentapp"] = app_serializer.data res.data["currentapp"] = app_serializer.data

@ -10,32 +10,36 @@ from fir_ser import settings
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
from api.utils.app.randomstrings import make_random_uuid from api.utils.app.randomstrings import make_random_uuid
from api.utils.app.apputils import make_resigned from api.utils.app.apputils import make_resigned
from api.utils.app.supersignutils import make_udid_mobileconfig,get_post_udid_url from api.utils.app.supersignutils import make_udid_mobileconfig, get_post_udid_url
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.storage.caches import get_app_instance_by_cache,get_download_url_by_cache,set_app_download_by_cache,del_cache_response_by_short from api.utils.storage.caches import get_app_instance_by_cache, get_download_url_by_cache, set_app_download_by_cache, \
del_cache_response_by_short
import os import os
from rest_framework_extensions.cache.decorators import cache_response from rest_framework_extensions.cache.decorators import cache_response
from api.utils.serializer import AppsShortSerializer from api.utils.serializer import AppsShortSerializer
from api.models import Apps,AppReleaseInfo,APPToDeveloper,APPSuperSignUsedInfo from api.models import Apps, AppReleaseInfo, APPToDeveloper, APPSuperSignUsedInfo
from django.http import FileResponse from django.http import FileResponse
class DownloadView(APIView): class DownloadView(APIView):
''' '''
文件下载接口,适用于本地存储和所有plist文件下载 文件下载接口,适用于本地存储和所有plist文件下载
''' '''
# authentication_classes = [ExpiringTokenAuthentication, ] # authentication_classes = [ExpiringTokenAuthentication, ]
# parser_classes = (MultiPartParser,) # parser_classes = (MultiPartParser,)
def get(self,request,filename): def get(self, request, filename):
res = BaseResponse() res = BaseResponse()
downtoken = request.query_params.get("token", None) downtoken = request.query_params.get("token", None)
ftype = request.query_params.get("ftype",None) ftype = request.query_params.get("ftype", None)
if not downtoken: if not downtoken:
res.code=1004 res.code = 1004
res.msg="缺失token" res.msg = "缺失token"
return Response(res.dict) return Response(res.dict)
dtoken = DownloadToken() dtoken = DownloadToken()
if dtoken.verify_token(downtoken,filename): if dtoken.verify_token(downtoken, filename):
if not ftype: if not ftype:
file_path = os.path.join(settings.MEDIA_ROOT, filename) file_path = os.path.join(settings.MEDIA_ROOT, filename)
try: try:
@ -51,7 +55,7 @@ class DownloadView(APIView):
release_id = filename.split('.')[0] release_id = filename.split('.')[0]
apptodev_obj = APPToDeveloper.objects.filter(binary_file=release_id).first() apptodev_obj = APPToDeveloper.objects.filter(binary_file=release_id).first()
if apptodev_obj: if apptodev_obj:
release_obj = AppReleaseInfo.objects.filter(is_master=True,app_id=apptodev_obj.app_id).first() release_obj = AppReleaseInfo.objects.filter(is_master=True, app_id=apptodev_obj.app_id).first()
else: else:
release_obj = AppReleaseInfo.objects.filter(release_id=release_id).first() release_obj = AppReleaseInfo.objects.filter(release_id=release_id).first()
if release_obj: if release_obj:
@ -59,7 +63,9 @@ class DownloadView(APIView):
bundle_id = release_obj.app_id.bundle_id bundle_id = release_obj.app_id.bundle_id
app_version = release_obj.app_version app_version = release_obj.app_version
name = release_obj.app_id.name 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,app_version,name) ios_plist_bytes = make_resigned(storage.get_download_url(filename),
storage.get_download_url(release_obj.icon_url), bundle_id,
app_version, name)
response = FileResponse(ios_plist_bytes) response = FileResponse(ios_plist_bytes)
response['Content-Type'] = "application/x-plist" response['Content-Type'] = "application/x-plist"
response['Content-Disposition'] = 'attachment; filename=' + make_random_uuid() response['Content-Disposition'] = 'attachment; filename=' + make_random_uuid()
@ -69,93 +75,98 @@ class DownloadView(APIView):
release_obj = AppReleaseInfo.objects.filter(release_id=filename.split('.')[0]).first() release_obj = AppReleaseInfo.objects.filter(release_id=filename.split('.')[0]).first()
if release_obj: if release_obj:
bundle_id = release_obj.app_id.bundle_id bundle_id = release_obj.app_id.bundle_id
udid_url = get_post_udid_url(request,release_obj.app_id.short) udid_url = get_post_udid_url(request, release_obj.app_id.short)
ios_udid_mobileconfig = make_udid_mobileconfig(udid_url, bundle_id) ios_udid_mobileconfig = make_udid_mobileconfig(udid_url, bundle_id)
response = FileResponse(ios_udid_mobileconfig) response = FileResponse(ios_udid_mobileconfig)
response['Content-Type'] = "application/x-apple-aspen-config" response['Content-Type'] = "application/x-apple-aspen-config"
response['Content-Disposition'] = 'attachment; filename=' + make_random_uuid() +'.mobileconfig' response['Content-Disposition'] = 'attachment; filename=' + make_random_uuid() + '.mobileconfig'
return response return response
res.msg = "mobileconifg release_id error" res.msg = "mobileconifg release_id error"
res.code=1004 res.code = 1004
res.msg="token校验失败" res.msg = "token校验失败"
return Response(res.dict) return Response(res.dict)
class ShortDownloadView(APIView): class ShortDownloadView(APIView):
''' '''
根据下载短链接获取应用信息 根据下载短链接获取应用信息
''' '''
@cache_response(timeout=600-60, cache="default",key_func='calculate_cache_key',cache_errors=False) @cache_response(timeout=600 - 60, cache="default", key_func='calculate_cache_key', cache_errors=False)
def get(self,request,short): def get(self, request, short):
res = BaseResponse() res = BaseResponse()
release_id = request.query_params.get("release_id", None) release_id = request.query_params.get("release_id", None)
udid = request.query_params.get("udid", None) udid = request.query_params.get("udid", None)
app_obj = Apps.objects.filter(short=short).first() app_obj = Apps.objects.filter(short=short).first()
if not app_obj: if not app_obj:
res.code=1003 res.code = 1003
res.msg="该应用不存在" res.msg = "该应用不存在"
return Response(res.dict) return Response(res.dict)
if udid: if udid:
del_cache_response_by_short(short,app_obj.app_id,udid=udid) del_cache_response_by_short(short, app_obj.app_id, udid=udid)
if not app_obj.isshow: if not app_obj.isshow:
res.code=1004 res.code = 1004
res.msg="您没有权限访问该应用" res.msg = "您没有权限访问该应用"
return Response(res.dict) return Response(res.dict)
app_serializer = AppsShortSerializer(app_obj,context={"key":"ShortDownloadView","release_id":release_id,"storage":Storage(app_obj.user_id)}) app_serializer = AppsShortSerializer(app_obj, context={"key": "ShortDownloadView", "release_id": release_id,
"storage": Storage(app_obj.user_id)})
res.data = app_serializer.data res.data = app_serializer.data
res.udid = udid res.udid = udid
return Response(res.dict) return Response(res.dict)
#key的设置 # key的设置
def calculate_cache_key(self, view_instance, view_method, def calculate_cache_key(self, view_instance, view_method,
request, args, kwargs): request, args, kwargs):
release_id = request.query_params.get("release_id", '') release_id = request.query_params.get("release_id", '')
udid = request.query_params.get("udid", None) udid = request.query_params.get("udid", None)
time = request.query_params.get("time", None) time = request.query_params.get("time", None)
if udid and time: if udid and time:
udid=time udid = time
if not udid: if not udid:
udid="" udid = ""
return "_".join(
[settings.CACHE_KEY_TEMPLATE.get("download_short_key"), kwargs.get("short", ''), release_id, udid])
return "_".join([settings.CACHE_KEY_TEMPLATE.get("download_short_key"), kwargs.get("short", ''),release_id,udid])
class InstallView(APIView): class InstallView(APIView):
''' '''
安装操作前端通过token 认证认证成功之后返回 下载连接并且 让下载次数加一 安装操作前端通过token 认证认证成功之后返回 下载连接并且 让下载次数加一
''' '''
def get(self,request,app_id): def get(self, request, app_id):
res = BaseResponse() res = BaseResponse()
downtoken = request.query_params.get("token", None) downtoken = request.query_params.get("token", None)
short = request.query_params.get("short",None) short = request.query_params.get("short", None)
release_id = request.query_params.get("release_id",None) release_id = request.query_params.get("release_id", None)
isdownload = request.query_params.get("isdownload",None) isdownload = request.query_params.get("isdownload", None)
password = request.query_params.get("password",None) password = request.query_params.get("password", None)
udid = request.query_params.get("udid",None) udid = request.query_params.get("udid", None)
if not downtoken or not short or not release_id: if not downtoken or not short or not release_id:
res.code=1004 res.code = 1004
res.msg="参数丢失" res.msg = "参数丢失"
return Response(res.dict) return Response(res.dict)
dtoken = DownloadToken() dtoken = DownloadToken()
if dtoken.verify_token(downtoken,release_id): if dtoken.verify_token(downtoken, release_id):
app_obj = get_app_instance_by_cache(app_id,password,900,udid) app_obj = get_app_instance_by_cache(app_id, password, 900, udid)
if app_obj: if app_obj:
if app_obj.get("type") == 0: if app_obj.get("type") == 0:
apptype = '.apk' apptype = '.apk'
download_url = get_download_url_by_cache(app_obj,release_id + apptype,600) download_url = get_download_url_by_cache(app_obj, release_id + apptype, 600)
else: else:
apptype = '.ipa' apptype = '.ipa'
if isdownload : if isdownload:
download_url = get_download_url_by_cache(app_obj,release_id + apptype, 600,udid=udid) download_url = get_download_url_by_cache(app_obj, release_id + apptype, 600, udid=udid)
else: else:
download_url = get_download_url_by_cache(app_obj,release_id + apptype,600,isdownload,udid=udid) download_url = get_download_url_by_cache(app_obj, release_id + apptype, 600, isdownload,
udid=udid)
res.data={"download_url":download_url} res.data = {"download_url": download_url}
if download_url != "" and not download_url.endswith("mobileconifg"): if download_url != "" and not download_url.endswith("mobileconifg"):
set_app_download_by_cache(app_id) set_app_download_by_cache(app_id)
return Response(res.dict) return Response(res.dict)
else: else:
@ -166,5 +177,3 @@ class InstallView(APIView):
res.code = 1006 res.code = 1006
res.msg = "该应用不存在" res.msg = "该应用不存在"
return Response(res.dict) return Response(res.dict)

@ -5,16 +5,19 @@ from api.utils.serializer import UserInfoSerializer
from django.core.cache import cache from django.core.cache import cache
from rest_framework.views import APIView from rest_framework.views import APIView
import binascii import binascii
import os,datetime import os, datetime
from api.utils.TokenManager import DownloadToken,generateNumericTokenOfLength from api.utils.TokenManager import DownloadToken, generateNumericTokenOfLength
from api.utils.auth import ExpiringTokenAuthentication from api.utils.auth import ExpiringTokenAuthentication
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from django.middleware import csrf from django.middleware import csrf
from fir_ser.settings import CACHE_KEY_TEMPLATE from fir_ser.settings import CACHE_KEY_TEMPLATE
def get_token(request): def get_token(request):
token = csrf.get_token(request) token = csrf.get_token(request)
return {'csrf_token': token} return {'csrf_token': token}
class LoginView(APIView): class LoginView(APIView):
def generate_key(self): def generate_key(self):
return binascii.hexlify(os.urandom(32)).decode() return binascii.hexlify(os.urandom(32)).decode()
@ -32,7 +35,7 @@ class LoginView(APIView):
username = receive.get("username") username = receive.get("username")
password = receive.get("password") password = receive.get("password")
user = auth.authenticate(username=username, password=password) user = auth.authenticate(username=username, password=password)
print(username,password,user) print(username, password, user)
if user is not None: if user is not None:
if user.is_active: if user.is_active:
@ -41,11 +44,11 @@ class LoginView(APIView):
now = datetime.datetime.now() now = datetime.datetime.now()
user_info = UserInfo.objects.get(pk=user.pk) user_info = UserInfo.objects.get(pk=user.pk)
auth_key = "_".join([CACHE_KEY_TEMPLATE.get('user_auth_token_key'),key]) auth_key = "_".join([CACHE_KEY_TEMPLATE.get('user_auth_token_key'), key])
cache.set(auth_key,{'uid':user_info.uid,'username':user_info.username},3600*24*7) cache.set(auth_key, {'uid': user_info.uid, 'username': user_info.username}, 3600 * 24 * 7)
Token.objects.create(user=user, **{"access_token": key, "created": now}) Token.objects.create(user=user, **{"access_token": key, "created": now})
serializer = UserInfoSerializer(user_info,) serializer = UserInfoSerializer(user_info, )
data = serializer.data data = serializer.data
response.msg = "验证成功!" response.msg = "验证成功!"
response.userinfo = data response.userinfo = data
@ -68,43 +71,44 @@ class LoginView(APIView):
return Response(response.dict) return Response(response.dict)
def get(self,request): def get(self, request):
response = BaseResponse() response = BaseResponse()
csrf=get_token(request) csrf = get_token(request)
response.data=csrf response.data = csrf
return Response(response.dict) return Response(response.dict)
class UserInfoView(APIView): class UserInfoView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ] authentication_classes = [ExpiringTokenAuthentication, ]
def get(self,request): def get(self, request):
res = BaseResponse() res = BaseResponse()
serializer = UserInfoSerializer(request.user) serializer = UserInfoSerializer(request.user)
res.data = serializer.data res.data = serializer.data
act = request.query_params.get("act",None) act = request.query_params.get("act", None)
if act and act == "sms": if act and act == "sms":
sms_token_obj=DownloadToken() sms_token_obj = DownloadToken()
sms_code=generateNumericTokenOfLength(6) sms_code = generateNumericTokenOfLength(6)
sms_token=sms_token_obj.make_token([sms_code]) sms_token = sms_token_obj.make_token([sms_code])
res.data["sms_token"] = sms_token res.data["sms_token"] = sms_token
res.data["sms_code"] = sms_code res.data["sms_code"] = sms_code
return Response(res.dict) return Response(res.dict)
def put(self,request): def put(self, request):
res = BaseResponse() res = BaseResponse()
request.user.qq=request.data.get("qq",request.user.qq) request.user.qq = request.data.get("qq", request.user.qq)
request.user.job=request.data.get("job", request.user.job) request.user.job = request.data.get("job", request.user.job)
request.user.first_name=request.data.get("first_name", request.user.first_name) request.user.first_name = request.data.get("first_name", request.user.first_name)
oldpassword=request.data.get("oldpassword",None) oldpassword = request.data.get("oldpassword", None)
surepassword=request.data.get("surepassword",None) surepassword = request.data.get("surepassword", None)
if oldpassword and surepassword: if oldpassword and surepassword:
user = auth.authenticate(username=request.user.username, password=oldpassword) user = auth.authenticate(username=request.user.username, password=oldpassword)
if user is not None: if user is not None:
user.set_password(surepassword) user.set_password(surepassword)
user.save() user.save()
res.msg="密码修改成功" res.msg = "密码修改成功"
auth_token = request.auth auth_token = request.auth
for token_obj in Token.objects.filter(user=user): for token_obj in Token.objects.filter(user=user):
@ -118,15 +122,14 @@ class UserInfoView(APIView):
res.msg = "老密码校验失败" res.msg = "老密码校验失败"
else: else:
sms_token = request.data.get("sms_token",None) sms_token = request.data.get("sms_token", None)
if sms_token: if sms_token:
sms_token_obj=DownloadToken() sms_token_obj = DownloadToken()
if sms_token_obj.verify_token(sms_token,request.data.get("sms_code",None)): if sms_token_obj.verify_token(sms_token, request.data.get("sms_code", None)):
request.user.mobile=request.data.get("mobile", request.user.mobile) request.user.mobile = request.data.get("mobile", request.user.mobile)
request.user.save() request.user.save()
serializer = UserInfoSerializer(request.user) serializer = UserInfoSerializer(request.user)
res.data = serializer.data res.data = serializer.data
return Response(res.dict) return Response(res.dict)
return Response(res.dict) return Response(res.dict)

@ -15,5 +15,5 @@ class LogoutView(APIView):
user = request.user.pk user = request.user.pk
auth_token = request.auth auth_token = request.auth
cache.delete(auth_token) cache.delete(auth_token)
Token.objects.filter(user=user,access_token=auth_token).delete() Token.objects.filter(user=user, access_token=auth_token).delete()
return Response({"code": 1000}) return Response({"code": 1000})

@ -4,23 +4,25 @@
# author: liuyu # author: liuyu
# date: 2020/3/6 # date: 2020/3/6
from api.utils.app.supersignutils import udid_bytes_to_dict,get_redirect_server_domain,IosUtils from api.utils.app.supersignutils import udid_bytes_to_dict, get_redirect_server_domain, IosUtils
from api.models import Apps,AppUDID from api.models import Apps, AppUDID
from django.views import View from django.views import View
from django.http import HttpResponsePermanentRedirect,Http404 from django.http import HttpResponsePermanentRedirect, Http404
class IosUDIDView(View): class IosUDIDView(View):
def post(self,request,short): def post(self, request, short):
stream_f = str(request.body) stream_f = str(request.body)
format_udid_info = udid_bytes_to_dict(stream_f) format_udid_info = udid_bytes_to_dict(stream_f)
try: try:
app_info=Apps.objects.filter(short=short).first() app_info = Apps.objects.filter(short=short).first()
if app_info : if app_info:
if app_info.issupersign: if app_info.issupersign:
AppUDID.objects.update_or_create(app_id=app_info,**format_udid_info,defaults={'udid':format_udid_info.get('udid')}) AppUDID.objects.update_or_create(app_id=app_info, **format_udid_info,
ios_obj = IosUtils(format_udid_info,app_info.user_id,app_info) defaults={'udid': format_udid_info.get('udid')})
ios_obj = IosUtils(format_udid_info, app_info.user_id, app_info)
ios_obj.resign() ios_obj.resign()
else: else:
return Http404 return Http404
@ -30,6 +32,4 @@ class IosUDIDView(View):
except Exception as e: except Exception as e:
print(e) print(e)
server_domain = get_redirect_server_domain(request) server_domain = get_redirect_server_domain(request)
return HttpResponsePermanentRedirect("%s/%s?udid=%s"%(server_domain,short,format_udid_info.get("udid"))) return HttpResponsePermanentRedirect("%s/%s?udid=%s" % (server_domain, short, format_udid_info.get("udid")))

@ -10,7 +10,7 @@ from api.utils.auth import ExpiringTokenAuthentication
from rest_framework.response import Response from rest_framework.response import Response
import json import json
from api.utils.storage.caches import del_cache_storage from api.utils.storage.caches import del_cache_storage
from api.models import AppStorage,UserInfo from api.models import AppStorage, UserInfo
from api.utils.serializer import StorageSerializer from api.utils.serializer import StorageSerializer
@ -36,7 +36,7 @@ class StorageView(APIView):
if use_storage_obj: if use_storage_obj:
res.storage = use_storage_obj.id res.storage = use_storage_obj.id
else: else:
res.storage = -1 # 默认存储 res.storage = -1 # 默认存储
res.storage_list = [] res.storage_list = []
storage_org_list = list(AppStorage.storage_choices) storage_org_list = list(AppStorage.storage_choices)
@ -45,7 +45,7 @@ class StorageView(APIView):
res.storage_list.append({'id': storage_t[0], 'name': storage_t[1]}) res.storage_list.append({'id': storage_t[0], 'name': storage_t[1]})
admin_storage = UserInfo.objects.filter(is_superuser=True).order_by('pk').first() admin_storage = UserInfo.objects.filter(is_superuser=True).order_by('pk').first()
res.is_admin_storage=False res.is_admin_storage = False
if admin_storage.uid == request.user.uid: if admin_storage.uid == request.user.uid:
res.is_admin_storage = True res.is_admin_storage = True
return Response(res.dict) return Response(res.dict)
@ -72,7 +72,7 @@ class StorageView(APIView):
res = BaseResponse() res = BaseResponse()
data = request.data data = request.data
use_storage_id=data.get("use_storage_id",None) use_storage_id = data.get("use_storage_id", None)
if use_storage_id: if use_storage_id:
try: try:
if use_storage_id == -1: if use_storage_id == -1:
@ -82,8 +82,8 @@ class StorageView(APIView):
del_cache_storage(request.user) del_cache_storage(request.user)
except Exception as e: except Exception as e:
print(e) print(e)
res.code=1006 res.code = 1006
res.msg='修改失败' res.msg = '修改失败'
return Response(res.dict) return Response(res.dict)
try: try:

@ -8,15 +8,14 @@ from rest_framework.views import APIView
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from api.utils.auth import ExpiringTokenAuthentication from api.utils.auth import ExpiringTokenAuthentication
from rest_framework.response import Response from rest_framework.response import Response
from api.models import AppIOSDeveloperInfo,APPSuperSignUsedInfo,AppUDID from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID
from api.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer,DeviceUDIDSerializer from api.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer
from rest_framework.pagination import PageNumberPagination from rest_framework.pagination import PageNumberPagination
from api.utils.app.supersignutils import IosUtils from api.utils.app.supersignutils import IosUtils
from api.utils.utils import get_developer_devices from api.utils.utils import get_developer_devices
from api.utils.storage.caches import developer_auth_code from api.utils.storage.caches import developer_auth_code
class AppsPageNumber(PageNumberPagination): class AppsPageNumber(PageNumberPagination):
page_size = 10 # 每页显示多少条 page_size = 10 # 每页显示多少条
page_size_query_param = 'size' # URL中每页显示条数的参数 page_size_query_param = 'size' # URL中每页显示条数的参数
@ -33,45 +32,54 @@ class DeveloperView(APIView):
appid = request.query_params.get("appid", None) appid = request.query_params.get("appid", None)
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user) developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user)
res.use_num=get_developer_devices(developer_obj) res.use_num = get_developer_devices(developer_obj)
if appid: if appid:
developer_obj=developer_obj.filter(email=appid) developer_obj = developer_obj.filter(email=appid)
page_obj = AppsPageNumber() page_obj = AppsPageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=developer_obj.order_by("-updated_time"), request=request, app_page_serializer = page_obj.paginate_queryset(queryset=developer_obj.order_by("-updated_time"),
request=request,
view=self) view=self)
Developer_serializer = DeveloperSerializer(app_page_serializer, many=True,) Developer_serializer = DeveloperSerializer(app_page_serializer, many=True, )
res.data = Developer_serializer.data res.data = Developer_serializer.data
res.count=developer_obj.count() res.count = developer_obj.count()
return Response(res.dict) return Response(res.dict)
def put(self,request): def put(self, request):
data = request.data data = request.data
email=data.get("email",None) email = data.get("email", None)
if email: if email:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user,email=email).first() developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user, email=email).first()
if developer_obj: if developer_obj:
act = data.get("act", None) act = data.get("act", None)
if act: if act:
res = BaseResponse() res = BaseResponse()
if act == "preactive": if act == "preactive":
developer_auth_code("del", request.user, developer_obj.email) developer_auth_code("del", request.user, developer_obj.email)
status,result = IosUtils.active_developer(developer_obj,request.user) status, result = IosUtils.active_developer(developer_obj, request.user)
if status: if status:
if not developer_obj.certid:
status, result = IosUtils.create_developer_cert(developer_obj, request.user)
if status:
IosUtils.get_device_from_developer(developer_obj, request.user)
else:
res.code = 1008
res.msg = result.get("err_info")
return Response(res.dict)
return self.get(request) return self.get(request)
else: else:
res.code = 1008 res.code = 1008
res.msg = result.get("return_info") res.msg = result.get("return_info")
return Response(res.dict) return Response(res.dict)
elif act == "nowactive" : elif act == "nowactive":
code = data.get("code", None) code = data.get("code", None)
if code: if code:
developer_auth_code("set",request.user,developer_obj.email,code) developer_auth_code("set", request.user, developer_obj.email, code)
elif act == "ioscert": elif act == "ioscert":
if not developer_obj.certid: if not developer_obj.certid:
status,result=IosUtils.create_developer_cert(developer_obj, request.user) status, result = IosUtils.create_developer_cert(developer_obj, request.user)
if status: if status:
IosUtils.get_device_from_developer(developer_obj, request.user) IosUtils.get_device_from_developer(developer_obj, request.user)
else: else:
@ -79,11 +87,25 @@ class DeveloperView(APIView):
res.msg = result.get("err_info") res.msg = result.get("err_info")
return Response(res.dict) return Response(res.dict)
elif act == "syncdevice": elif act == "syncdevice":
IosUtils.get_device_from_developer(developer_obj,request.user) status, result = IosUtils.get_device_from_developer(developer_obj, request.user)
if status:
IosUtils.get_device_from_developer(developer_obj, request.user)
else:
res.code = 1008
res.msg = result.get("err_info")
return Response(res.dict)
elif act == "checkauth":
developer_auth_code("del", request.user, developer_obj.email)
status, result = IosUtils.active_developer(developer_obj, request.user)
if status:
return self.get(request)
else:
res.code = 1008
res.msg = result.get("return_info")
return Response(res.dict)
else: else:
try: try:
usable_number=int(data.get("usable_number",developer_obj.usable_number)) usable_number = int(data.get("usable_number", developer_obj.usable_number))
if usable_number >= 0 and usable_number <= 100: if usable_number >= 0 and usable_number <= 100:
developer_obj.usable_number = usable_number developer_obj.usable_number = usable_number
except Exception as e: except Exception as e:
@ -91,41 +113,42 @@ class DeveloperView(APIView):
developer_obj.description = data.get("description", developer_obj.description) developer_obj.description = data.get("description", developer_obj.description)
password = data.get("password", developer_obj.password) password = data.get("password", developer_obj.password)
if password != "" and password != developer_obj.password: if password != "" and password != developer_obj.password:
developer_obj.password=password developer_obj.password = password
developer_obj.is_actived=False developer_obj.is_actived = False
developer_obj.save() developer_obj.save()
return self.get(request) return self.get(request)
def post(self,request): def post(self, request):
data = request.data data = request.data
datainfo={ datainfo = {
"usable_number" : data.get("usable_number", ""), "usable_number": data.get("usable_number", ""),
"description" : data.get("description", ""), "description": data.get("description", ""),
"password" : data.get("password", ""), "password": data.get("password", ""),
"email" : data.get("email", ""), "email": data.get("email", ""),
} }
try: try:
AppIOSDeveloperInfo.objects.create(user_id=request.user,**datainfo) AppIOSDeveloperInfo.objects.create(user_id=request.user, **datainfo)
except Exception as e: except Exception as e:
print(e) print(e)
res = BaseResponse() res = BaseResponse()
res.code=1005 res.code = 1005
res.msg="添加失败" res.msg = "添加失败"
return Response(res.dict) return Response(res.dict)
return self.get(request) return self.get(request)
def delete(self,request): def delete(self, request):
email=request.query_params.get("email",None) email = request.query_params.get("email", None)
if email: if email:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user,email=email).first() developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user, email=email).first()
if developer_obj: if developer_obj:
IosUtils.clean_developer(developer_obj,request.user) IosUtils.clean_developer(developer_obj, request.user)
developer_obj.delete() developer_obj.delete()
return self.get(request) return self.get(request)
class SuperSignUsedView(APIView): class SuperSignUsedView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ] authentication_classes = [ExpiringTokenAuthentication, ]
@ -136,23 +159,25 @@ class SuperSignUsedView(APIView):
bundleid = request.query_params.get("bundleid", None) bundleid = request.query_params.get("bundleid", None)
developerid = request.query_params.get("appid", None) developerid = request.query_params.get("appid", None)
SuperSignUsed_obj = APPSuperSignUsedInfo.objects.filter(user_id=request.user,) SuperSignUsed_obj = APPSuperSignUsedInfo.objects.filter(user_id=request.user, )
if developerid: if developerid:
SuperSignUsed_obj=SuperSignUsed_obj.filter(developerid__email=developerid) SuperSignUsed_obj = SuperSignUsed_obj.filter(developerid__email=developerid)
if udid: if udid:
SuperSignUsed_obj = SuperSignUsed_obj.filter(udid__udid=udid) SuperSignUsed_obj = SuperSignUsed_obj.filter(udid__udid=udid)
if bundleid: if bundleid:
SuperSignUsed_obj = SuperSignUsed_obj.filter(app_id__bundle_id=bundleid) SuperSignUsed_obj = SuperSignUsed_obj.filter(app_id__bundle_id=bundleid)
page_obj = AppsPageNumber() page_obj = AppsPageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=SuperSignUsed_obj.order_by("-created_time"), request=request, app_page_serializer = page_obj.paginate_queryset(queryset=SuperSignUsed_obj.order_by("-created_time"),
request=request,
view=self) view=self)
app_serializer = SuperSignUsedSerializer(app_page_serializer, many=True, ) app_serializer = SuperSignUsedSerializer(app_page_serializer, many=True, )
res.data = app_serializer.data res.data = app_serializer.data
res.count=SuperSignUsed_obj.count() res.count = SuperSignUsed_obj.count()
return Response(res.dict) return Response(res.dict)
class AppUDIDUsedView(APIView): class AppUDIDUsedView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ] authentication_classes = [ExpiringTokenAuthentication, ]
@ -163,23 +188,24 @@ class AppUDIDUsedView(APIView):
bundleid = request.query_params.get("bundleid", None) bundleid = request.query_params.get("bundleid", None)
AppUDID_obj = AppUDID.objects.filter(app_id__user_id_id=request.user) AppUDID_obj = AppUDID.objects.filter(app_id__user_id_id=request.user)
if udid: if udid:
AppUDID_obj = AppUDID_obj.filter(udid=udid) AppUDID_obj = AppUDID_obj.filter(udid=udid)
if bundleid: if bundleid:
AppUDID_obj = AppUDID_obj.filter(app_id__bundle_id=bundleid) AppUDID_obj = AppUDID_obj.filter(app_id__bundle_id=bundleid)
page_obj = AppsPageNumber() page_obj = AppsPageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=AppUDID_obj.order_by("-created_time"), request=request, app_page_serializer = page_obj.paginate_queryset(queryset=AppUDID_obj.order_by("-created_time"),
request=request,
view=self) view=self)
app_serializer = DeviceUDIDSerializer(app_page_serializer, many=True,) app_serializer = DeviceUDIDSerializer(app_page_serializer, many=True, )
res.data = app_serializer.data res.data = app_serializer.data
res.count=AppUDID_obj.count() res.count = AppUDID_obj.count()
return Response(res.dict) return Response(res.dict)
def delete(self,request): def delete(self, request):
res = BaseResponse() res = BaseResponse()
id = request.query_params.get("id", None) id = request.query_params.get("id", None)
app_id = request.query_params.get("aid", None) app_id = request.query_params.get("aid", None)
app_udid_obj=AppUDID.objects.filter(app_id__user_id_id=request.user,pk=id) app_udid_obj = AppUDID.objects.filter(app_id__user_id_id=request.user, pk=id)
IosUtils.disable_udid(app_udid_obj.first(),app_id) IosUtils.disable_udid(app_udid_obj.first(), app_id)
app_udid_obj.delete() app_udid_obj.delete()
return Response(res.dict) return Response(res.dict)

@ -4,10 +4,10 @@
# author: liuyu # author: liuyu
# date: 2020/3/6 # date: 2020/3/6
from api.utils.app.apputils import get_random_short,SaveAppInfos from api.utils.app.apputils import get_random_short, SaveAppInfos
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short from api.utils.storage.caches import del_cache_response_by_short
from api.models import Apps,AppReleaseInfo from api.models import Apps, AppReleaseInfo
from api.utils.app.randomstrings import make_app_uuid from api.utils.app.randomstrings import make_app_uuid
from rest_framework.views import APIView from rest_framework.views import APIView
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
@ -16,10 +16,10 @@ from api.utils.app.randomstrings import make_from_user_uuid
from rest_framework.response import Response from rest_framework.response import Response
from fir_ser import settings from fir_ser import settings
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
import os,json import os, json
class AppAnalyseView(APIView):
class AppAnalyseView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ] authentication_classes = [ExpiringTokenAuthentication, ]
def post(self, request): def post(self, request):
@ -31,67 +31,67 @@ class AppAnalyseView(APIView):
if bundleid and app_type: if bundleid and app_type:
ap = 'apk' ap = 'apk'
if app_type == 'iOS': if app_type == 'iOS':
ap='ipa' ap = 'ipa'
app_uuid = make_app_uuid(request.user, bundleid + ap) app_uuid = make_app_uuid(request.user, bundleid + ap)
release_id = make_from_user_uuid(request.user) release_id = make_from_user_uuid(request.user)
png_id = make_from_user_uuid(request.user) png_id = make_from_user_uuid(request.user)
app_obj = Apps.objects.filter(app_id=app_uuid).first() app_obj = Apps.objects.filter(app_id=app_uuid).first()
binary_url='' binary_url = ''
if app_obj: if app_obj:
is_new=False is_new = False
short = app_obj.short short = app_obj.short
app_release_obj=AppReleaseInfo.objects.filter(app_id=app_obj,is_master=True).first() app_release_obj = AppReleaseInfo.objects.filter(app_id=app_obj, is_master=True).first()
if app_release_obj: if app_release_obj:
binary_url = app_release_obj.binary_url binary_url = app_release_obj.binary_url
else: else:
is_new=True is_new = True
short = get_random_short() short = get_random_short()
if app_type == 'iOS': if app_type == 'iOS':
upload_key = release_id+'.ipa' upload_key = release_id + '.ipa'
else: else:
upload_key = release_id+'.apk' upload_key = release_id + '.apk'
png_key = png_id+'.png' png_key = png_id + '.png'
storage = Storage(request.user) storage = Storage(request.user)
storage_type =storage.get_storage_type() storage_type = storage.get_storage_type()
if storage_type == 1: if storage_type == 1:
upload_token = storage.get_upload_token(upload_key) upload_token = storage.get_upload_token(upload_key)
png_token = storage.get_upload_token(png_key) png_token = storage.get_upload_token(png_key)
elif storage_type == 2: elif storage_type == 2:
png_token=upload_token = storage.get_upload_token(upload_key) png_token = upload_token = storage.get_upload_token(upload_key)
else: else:
upload_token = storage.get_upload_token(upload_key) upload_token = storage.get_upload_token(upload_key)
png_token = storage.get_upload_token(png_key) png_token = storage.get_upload_token(png_key)
res.data = {"app_uuid": app_uuid, "short": short, res.data = {"app_uuid": app_uuid, "short": short,
"domain_name": request.user.domain_name, "domain_name": request.user.domain_name,
"upload_token":upload_token, "upload_token": upload_token,
"upload_key":upload_key, "upload_key": upload_key,
"png_token":png_token, "png_token": png_token,
"png_key":png_key, "png_key": png_key,
"storage":storage_type, "storage": storage_type,
"is_new":is_new,"binary_url":binary_url} "is_new": is_new, "binary_url": binary_url}
else: else:
res.code = 1003 res.code = 1003
return Response(res.dict) return Response(res.dict)
def put(self,request): def put(self, request):
res = BaseResponse() res = BaseResponse()
data=request.data data = request.data
appinfo={ appinfo = {
"labelname":data.get("appname"), "labelname": data.get("appname"),
"version":data.get("buildversion"), "version": data.get("buildversion"),
"versioncode":data.get("version"), "versioncode": data.get("version"),
"release_type":data.get("release_type"), "release_type": data.get("release_type"),
"miniOSversion":data.get("miniosversion"), "miniOSversion": data.get("miniosversion"),
"changelog":data.get("changelog",''), "changelog": data.get("changelog", ''),
"udid": data.get("udid", ''), "udid": data.get("udid", ''),
} }
try: try:
SaveAppInfos(data.get("upload_key"), request.user, appinfo, SaveAppInfos(data.get("upload_key"), request.user, appinfo,
data.get("bundleid"), data.get("png_key"), data.get("short"), data.get('filesize')) data.get("bundleid"), data.get("png_key"), data.get("short"), data.get('filesize'))
except Exception as e: except Exception as e:
print(e) print(e)
res.code = 10003 res.code = 10003
@ -104,14 +104,14 @@ class UploadView(APIView):
''' '''
authentication_classes = [ExpiringTokenAuthentication, ] authentication_classes = [ExpiringTokenAuthentication, ]
def get(self,request): def get(self, request):
res = BaseResponse() res = BaseResponse()
storage = Storage(request.user) storage = Storage(request.user)
request_upload_key=request.query_params.get("upload_key",None) request_upload_key = request.query_params.get("upload_key", None)
app_id=request.query_params.get("app_id",None) app_id = request.query_params.get("app_id", None)
ftype = request.query_params.get("ftype",None) ftype = request.query_params.get("ftype", None)
if ftype and app_id and request_upload_key : if ftype and app_id and request_upload_key:
if ftype =='app': if ftype == 'app':
app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first() app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first()
elif ftype and ftype == 'head': elif ftype and ftype == 'head':
@ -120,25 +120,25 @@ class UploadView(APIView):
res.msg = '该用户不存在' res.msg = '该用户不存在'
return Response(res.dict) return Response(res.dict)
else: else:
app_obj=True app_obj = True
else: else:
app_obj=False app_obj = False
if app_obj: if app_obj:
app_type = request_upload_key.split(".")[-1] app_type = request_upload_key.split(".")[-1]
if app_type not in ["apk", "ipa", 'png', 'jpeg', 'jpg']: if app_type not in ["apk", "ipa", 'png', 'jpeg', 'jpg']:
res.code = 1006 res.code = 1006
res.msg='类型不允许' res.msg = '类型不允许'
else: else:
upload_key = make_from_user_uuid(request.user)+'.'+app_type upload_key = make_from_user_uuid(request.user) + '.' + app_type
upload_token = storage.get_upload_token(upload_key) upload_token = storage.get_upload_token(upload_key)
storage_type = storage.get_storage_type() storage_type = storage.get_storage_type()
res.data = {"domain_name": request.user.domain_name, res.data = {"domain_name": request.user.domain_name,
"upload_token": upload_token, "upload_token": upload_token,
"upload_key": upload_key, "upload_key": upload_key,
"storage": storage_type, "storage": storage_type,
"app_id":app_id, "app_id": app_id,
"ftype":ftype} "ftype": ftype}
else: else:
res.code = 1006 res.code = 1006
res.msg = '该应用不存在' res.msg = '该应用不存在'
@ -146,8 +146,6 @@ class UploadView(APIView):
res.code = 1006 res.code = 1006
return Response(res.dict) return Response(res.dict)
def post(self, request): def post(self, request):
res = BaseResponse() res = BaseResponse()
@ -168,10 +166,11 @@ class UploadView(APIView):
return Response(res.dict) return Response(res.dict)
token_obj = DownloadToken() token_obj = DownloadToken()
if token_obj.verify_token(token=certinfo.get("upload_token",None),release_id=certinfo.get("upload_key",None)): if token_obj.verify_token(token=certinfo.get("upload_token", None),
release_id=certinfo.get("upload_key", None)):
app_id = certinfo.get("app_id", None) app_id = certinfo.get("app_id", None)
ftype = certinfo.get("ftype",None) ftype = certinfo.get("ftype", None)
if ftype and ftype == 'app': if ftype and ftype == 'app':
pass pass
# app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first() # app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first()
@ -189,11 +188,11 @@ class UploadView(APIView):
res.msg = '该请求不存在' res.msg = '该请求不存在'
return Response(res.dict) return Response(res.dict)
if not files: if not files:
res.msg="文件不存在" res.msg = "文件不存在"
for file_obj in files: for file_obj in files:
try: try:
app_type = file_obj.name.split(".")[-1] app_type = file_obj.name.split(".")[-1]
if app_type not in ["apk","ipa",'png','jpeg','jpg']: if app_type not in ["apk", "ipa", 'png', 'jpeg', 'jpg']:
raise TypeError raise TypeError
except Exception as e: except Exception as e:
print(e) print(e)
@ -202,7 +201,7 @@ class UploadView(APIView):
return Response(res.dict) return Response(res.dict)
random_file_name = make_from_user_uuid(request.user) random_file_name = make_from_user_uuid(request.user)
local_file = os.path.join(settings.MEDIA_ROOT,certinfo.get("upload_key",random_file_name)) local_file = os.path.join(settings.MEDIA_ROOT, certinfo.get("upload_key", random_file_name))
# 读取传入的文件 # 读取传入的文件
try: try:
destination = open(local_file, 'wb+') destination = open(local_file, 'wb+')
@ -224,23 +223,23 @@ class UploadView(APIView):
return Response(res.dict) return Response(res.dict)
def put(self,request): def put(self, request):
res = BaseResponse() res = BaseResponse()
certinfo = request.data.get('certinfo',None) certinfo = request.data.get('certinfo', None)
if certinfo: if certinfo:
app_id = certinfo.get("app_id", None) app_id = certinfo.get("app_id", None)
ftype = certinfo.get('ftype',None) ftype = certinfo.get('ftype', None)
storage = Storage(request.user) storage = Storage(request.user)
if ftype and ftype == 'app': if ftype and ftype == 'app':
app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first() app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first()
if app_obj: if app_obj:
release_obj = AppReleaseInfo.objects.filter(app_id=app_obj,is_master=True).first() release_obj = AppReleaseInfo.objects.filter(app_id=app_obj, is_master=True).first()
if release_obj: if release_obj:
old_file_key = release_obj.icon_url old_file_key = release_obj.icon_url
release_obj.icon_url = certinfo.get("upload_key") release_obj.icon_url = certinfo.get("upload_key")
release_obj.save() release_obj.save()
del_cache_response_by_short(app_obj.short,app_id) del_cache_response_by_short(app_obj.short, app_id)
storage.delete_file(old_file_key) storage.delete_file(old_file_key)
return Response(res.dict) return Response(res.dict)
elif ftype and ftype == 'head': elif ftype and ftype == 'head':
@ -259,7 +258,3 @@ class UploadView(APIView):
pass pass
res.code = 1008 res.code = 1008
return Response(res.dict) return Response(res.dict)

@ -15,7 +15,6 @@ import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
@ -27,7 +26,6 @@ DEBUG = True
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
@ -38,7 +36,7 @@ INSTALLED_APPS = [
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'api.apps.ApiConfig', 'api.apps.ApiConfig',
'django_apscheduler',#定时执行任务 'django_apscheduler', # 定时执行任务
'rest_framework', 'rest_framework',
] ]
@ -46,7 +44,7 @@ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
@ -74,7 +72,6 @@ TEMPLATES = [
WSGI_APPLICATION = 'fir_ser.wsgi.application' WSGI_APPLICATION = 'fir_ser.wsgi.application'
# Database # Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
@ -90,13 +87,12 @@ DATABASES = {
'PASSWORD': 'KGzKjZpWBp4R4RSa', 'PASSWORD': 'KGzKjZpWBp4R4RSa',
'HOST': '127.0.0.1', 'HOST': '127.0.0.1',
'PORT': '3306', 'PORT': '3306',
#设置MySQL的驱动 # 设置MySQL的驱动
'OPTIONS': {'init_command': 'SET storage_engine=INNODB'} 'OPTIONS': {'init_command': 'SET storage_engine=INNODB'}
} }
} }
# Password validation # Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
@ -133,24 +129,21 @@ USE_L10N = True
USE_TZ = False USE_TZ = False
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/ # https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATICFILES_DIRS=[ STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static") os.path.join(BASE_DIR, "static")
] ]
# Media配置 # Media配置
MEDIA_URL = "files/" MEDIA_URL = "files/"
MEDIA_ROOT = os.path.join(BASE_DIR, "files") MEDIA_ROOT = os.path.join(BASE_DIR, "files")
#supersign配置 # supersign配置
SUPER_SIGN_ROOT = os.path.join(BASE_DIR, "supersign") SUPER_SIGN_ROOT = os.path.join(BASE_DIR, "supersign")
AUTH_USER_MODEL="api.UserInfo" AUTH_USER_MODEL = "api.UserInfo"
GEE_TEST = { GEE_TEST = {
"gee_test_access_id": "37ca5631edd1e882721808d35163b3ad", "gee_test_access_id": "37ca5631edd1e882721808d35163b3ad",
@ -161,8 +154,6 @@ GEE_TEST = {
], # 不用验证的用户(存放着用户的uid) ], # 不用验证的用户(存放着用户的uid)
} }
CACHES = { CACHES = {
"default": { "default": {
"BACKEND": "django_redis.cache.RedisCache", "BACKEND": "django_redis.cache.RedisCache",
@ -171,12 +162,11 @@ CACHES = {
"CLIENT_CLASS": "django_redis.client.DefaultClient", "CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100}, "CONNECTION_POOL_KWARGS": {"max_connections": 100},
"PASSWORD": "nineven", "PASSWORD": "nineven",
"DECODE_RESPONSES":True "DECODE_RESPONSES": True
} }
}, },
} }
# DRF扩展缓存时间 # DRF扩展缓存时间
REST_FRAMEWORK_EXTENSIONS = { REST_FRAMEWORK_EXTENSIONS = {
# 缓存时间 # 缓存时间
@ -200,10 +190,10 @@ THIRD_PART_CONFIG = {
'name': 'local', 'name': 'local',
'type': 0, 'type': 0,
'auth': { 'auth': {
'domain_name': '127.0.0.1:8000', # 正式环境需要填写正式的访问域名 'domain_name': 'fly.harmonygames.cn', # 正式环境需要填写正式的访问域名
'is_https':False, 'is_https': True,
}, },
'active': False 'active': True
}, },
{ {
'name': 'aliyun', 'name': 'aliyun',
@ -212,12 +202,12 @@ THIRD_PART_CONFIG = {
'access_key': 'LTAI4FkbTRqejBAzB1yQZpjR', 'access_key': 'LTAI4FkbTRqejBAzB1yQZpjR',
'secret_key': '2WzCsKjYXxOvU4wPtTmrrXnxiLIxy9', 'secret_key': '2WzCsKjYXxOvU4wPtTmrrXnxiLIxy9',
'bucket_name': 'fly-app-storage', 'bucket_name': 'fly-app-storage',
'sts_role_arn':'acs:ram::1886562303345632:role/fly-app-storage', 'sts_role_arn': 'acs:ram::1886562303345632:role/fly-app-storage',
'endpoint':'oss-cn-beijing.aliyuncs.com', 'endpoint': 'oss-cn-beijing.aliyuncs.com',
'is_https':True, 'is_https': True,
'domain_name':'ali.storage.dvcloud.xin' 'domain_name': 'ali.storage.dvcloud.xin'
}, },
'active': True 'active': False
}, },
{ {
'name': 'qiniuyun', 'name': 'qiniuyun',
@ -234,28 +224,28 @@ THIRD_PART_CONFIG = {
] ]
} }
CACHE_KEY_TEMPLATE={ CACHE_KEY_TEMPLATE = {
'download_times_key':'app_download_times', 'download_times_key': 'app_download_times',
'make_token_key':'make_token', 'make_token_key': 'make_token',
'download_short_key':'download_short', 'download_short_key': 'download_short',
'app_instance_key':'app_instance', 'app_instance_key': 'app_instance',
'download_url_key':'download_url', 'download_url_key': 'download_url',
'user_storage_key':'storage_auth', 'user_storage_key': 'storage_auth',
'user_auth_token_key':'user_auth_token', 'user_auth_token_key': 'user_auth_token',
'download_today_times_key':'download_today_times', 'download_today_times_key': 'download_today_times',
'developer_auth_code_key': 'developer_auth_code', 'developer_auth_code_key': 'developer_auth_code',
} }
SYNC_CACHE_TO_DATABASE={ SYNC_CACHE_TO_DATABASE = {
'download_times':10 #下载次数同步时间 'download_times': 10 # 下载次数同步时间
} }
SERVER_DOMAIN={ SERVER_DOMAIN = {
'IOS_PMFILE_DOWNLOAD_DOMAIN':{ 'IOS_PMFILE_DOWNLOAD_DOMAIN': {
"domain_name":'fly.harmonygames.cn', "domain_name": 'fly.harmonygames.cn',
'is_https':True, 'is_https': True,
}, # ios 描述文件和plist文件下载域名,该域名用于后端,一般为api访问域名 }, # ios 描述文件和plist文件下载域名,该域名用于后端,一般为api访问域名
'POST_UDID_DOMAIN':'https://fly.harmonygames.cn', #超级签名 安装签名时 向该域名 发送udid数据,该域名用于后端,一般为 api 访问域名 'POST_UDID_DOMAIN': 'https://fly.harmonygames.cn', # 超级签名 安装签名时 向该域名 发送udid数据,该域名用于后端,一般为 api 访问域名
'REDIRECT_UDID_DOMAIN': 'https://fly.harmonygames.cn', # 超级签名 安装完成之后,跳转域名,该域名为前端web访问域名 'REDIRECT_UDID_DOMAIN': 'https://fly.harmonygames.cn', # 超级签名 安装完成之后,跳转域名,该域名为前端web访问域名
} }

@ -14,7 +14,7 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path,re_path,include from django.urls import path, re_path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
# from api.views.course import CourseView,CourseDetailView,CourseCategoryView # from api.views.course import CourseView,CourseDetailView,CourseCategoryView
from api.views.login import LoginView from api.views.login import LoginView
@ -32,10 +32,9 @@ from api.views.captcha import CaptchaView
# router.register("course/category", CourseCategoryView) # router.register("course/category", CourseCategoryView)
from django.views.static import serve from django.views.static import serve
from fir_ser import settings from fir_ser import settings
from api.views.download import DownloadView,InstallView from api.views.download import DownloadView, InstallView
from api.views.receiveudids import IosUDIDView from api.views.receiveudids import IosUDIDView
urlpatterns = [ urlpatterns = [
path('fly.admin/', admin.site.urls), path('fly.admin/', admin.site.urls),
# path("",include(router.urls)), # path("",include(router.urls)),
@ -49,7 +48,7 @@ urlpatterns = [
# re_path("api/v1/trade/alipay/",AlipayTradeView), # re_path("api/v1/trade/alipay/",AlipayTradeView),
# media路径配置 # media路径配置
re_path(r'files/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), 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("download/(?P<filename>\w+\.\w+)$", DownloadView.as_view(), name="download"),
re_path("install/(?P<app_id>\w+)$", InstallView.as_view(), name="install"), re_path("install/(?P<app_id>\w+)$", InstallView.as_view(), name="install"),
re_path("^udid/(?P<short>\w+)$", IosUDIDView.as_view()), re_path("^udid/(?P<short>\w+)$", IosUDIDView.as_view()),
] ]

@ -1,9 +1,9 @@
import requests import requests
import random import random
short=["bgql","wjbu","vnfg","bgql"]
udid_lists=[ short = ["bgql", "wjbu", "vnfg", "bgql"]
udid_lists = [
"f55df38afe5c1242b8bc478d0182bbd0d7d08929", "f55df38afe5c1242b8bc478d0182bbd0d7d08929",
"f55df38afe5c1242b8bc478d0182bbd0d7d08929", "f55df38afe5c1242b8bc478d0182bbd0d7d08929",
"f55df38afe5c1242b8bc478d0182bbd0d7d08922", "f55df38afe5c1242b8bc478d0182bbd0d7d08922",
@ -34,12 +34,10 @@ udid_lists=[
"f55df38afe5c1242b8bc478d0182bbd0d7dsfe08929", "f55df38afe5c1242b8bc478d0182bbd0d7dsfe08929",
] ]
for udid in udid_lists: for udid in udid_lists:
data='<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>PRODUCT</key>\n\t<string>iPhone9,1</string>\n\t<key>SERIAL</key>\n\t<string>F71YD58GHG74</string>\n\t<key>UDID</key>\n\t<string>%s</string>\n\t<key>VERSION</key>\n\t<string>17E262</string>\n</dict>\n</plist>\n' %(udid) data = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n\t<key>PRODUCT</key>\n\t<string>iPhone9,1</string>\n\t<key>SERIAL</key>\n\t<string>F71YD58GHG74</string>\n\t<key>UDID</key>\n\t<string>%s</string>\n\t<key>VERSION</key>\n\t<string>17E262</string>\n</dict>\n</plist>\n' % (
udid)
uri = "https://fly.harmonygames.cn/udid/%s" % (random.choice(short)) uri = "https://fly.harmonygames.cn/udid/%s" % (random.choice(short))
# uri = "https://fly.harmonygames.cn/udid/%s" % ("bgql") # uri = "https://fly.harmonygames.cn/udid/%s" % ("bgql")
req=requests.post(uri,data=data ) req = requests.post(uri, data=data)
print(req.status_code) print(req.status_code)

Loading…
Cancel
Save