优化代码

super_signature
nineven 5 years ago
parent a4e9579236
commit ff81f62d95
  1. 15
      fir_client/src/App.vue
  2. 9
      fir_client/src/assets/icon/iconfont.css
  3. 41
      fir_client/src/assets/icon/iconfont.svg
  4. 10
      fir_client/src/components/FirAppInfosBase.vue
  5. 8
      fir_client/src/components/FirAppInfosbaseinfo.vue
  6. 7
      fir_client/src/components/FirAppInfosdevices.vue
  7. 7
      fir_client/src/components/FirAppInfossecurity.vue
  8. 15
      fir_client/src/components/FirApps.vue
  9. 36
      fir_client/src/components/FirDownload.vue
  10. 8
      fir_client/src/components/FirHeader.vue
  11. 189
      fir_client/src/components/FirSuperSignBase.vue
  12. 12
      fir_client/src/components/FirUserProfileBase.vue
  13. 6
      fir_client/src/components/FirUserProfileChangePwd.vue
  14. 7
      fir_client/src/components/FirUserProfileInfo.vue
  15. 20
      fir_client/src/components/FirUserProfileStorage.vue
  16. 1
      fir_client/src/main.js
  17. 61
      fir_client/src/restful/index.js
  18. 8
      fir_client/src/utils/index.js
  19. 2
      fir_ser/api/admin.py
  20. 97
      fir_ser/api/migrations/0001_initial.py
  21. 1
      fir_ser/api/migrations/0002_auto_20200503_1120.py
  22. 8
      fir_ser/api/migrations/0003_apptodeveloper.py
  23. 1
      fir_ser/api/migrations/0004_auto_20200504_2054.py
  24. 1
      fir_ser/api/migrations/0005_apptodeveloper_release_file.py
  25. 5
      fir_ser/api/migrations/0006_udidsyncdeveloper.py
  26. 1
      fir_ser/api/urls.py
  27. 6
      fir_ser/api/utils/TokenManager.py
  28. 1
      fir_ser/api/utils/ali/__init__.py
  29. 1
      fir_ser/api/utils/ali/api.py
  30. 1
      fir_ser/api/utils/ali/client/__init__.py
  31. 1
      fir_ser/api/utils/ali/client/api/__init__.py
  32. 1
      fir_ser/api/utils/ali/client/basic.py
  33. 1
      fir_ser/api/utils/ali/pay/__init__.py
  34. 1
      fir_ser/api/utils/ali/pay/api/base.py
  35. 1
      fir_ser/api/utils/ali/yun/api/base.py
  36. 1
      fir_ser/api/utils/ali/yun/api/sms.py
  37. 1
      fir_ser/api/utils/ali/yun/api/vod.py
  38. 2
      fir_ser/api/utils/ali/yun/basic.py
  39. 8
      fir_ser/api/utils/app/apputils.py
  40. 4
      fir_ser/api/utils/app/dadf.py
  41. 8
      fir_ser/api/utils/app/firApi.py
  42. 10
      fir_ser/api/utils/app/iossignapi.py
  43. 7
      fir_ser/api/utils/app/randomstrings.py
  44. 3
      fir_ser/api/utils/app/raqc.py
  45. 26
      fir_ser/api/utils/app/shellcmds.py
  46. 50
      fir_ser/api/utils/app/supersignutils.py
  47. 5
      fir_ser/api/utils/auth.py
  48. 3
      fir_ser/api/utils/captcha_verify.py
  49. 3
      fir_ser/api/utils/crontab/sync_cache.py
  50. 4
      fir_ser/api/utils/middlewares.py
  51. 4
      fir_ser/api/utils/permission.py
  52. 6
      fir_ser/api/utils/response.py
  53. 19
      fir_ser/api/utils/serializer.py
  54. 3
      fir_ser/api/utils/storage/aliyunApi.py
  55. 30
      fir_ser/api/utils/storage/caches.py
  56. 2
      fir_ser/api/utils/storage/localApi.py
  57. 2
      fir_ser/api/utils/storage/qiniuApi.py
  58. 5
      fir_ser/api/utils/utils.py
  59. 2
      fir_ser/api/views/apps.py
  60. 23
      fir_ser/api/views/download.py
  61. 5
      fir_ser/api/views/login.py
  62. 6
      fir_ser/api/views/receiveudids.py
  63. 36
      fir_ser/api/views/supersign.py
  64. 11
      fir_ser/api/views/uploads.py
  65. 20
      fir_ser/fir_ser/settings.py
  66. 1
      fir_ser/fir_ser/urls.py
  67. 8
      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,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') format('woff2'),
url('data:application/x-font-woff2;charset=utf-8;base64,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') 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,10 +1,9 @@
@font-face {font-family: "iconfont"; @font-face {
font-family: "iconfont";
src: url('iconfont.eot?t=1583637102320'); /* IE9 */ src: url('iconfont.eot?t=1583637102320'); /* IE9 */
src: url('iconfont.eot?t=1583637102320#iefix') format('embedded-opentype'), /* IE6-IE8 */ src: url('iconfont.eot?t=1583637102320#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff2;charset=utf-8;base64,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') 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('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 {

@ -20,34 +20,51 @@ Created by iconfont
/> />
<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;"
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="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" /> <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"/>
<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="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="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" /> <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"/>
<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="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="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" /> <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"/>
<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="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="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" />
<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> </font>
</defs></svg> </defs>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@ -113,7 +113,11 @@
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({
"name": 'FirSuperSignBase',
params: {act: "useddevices"},
query: {bundleid: this.appinfos.bundle_id}
})
} else { } else {
this.$router.push({name: 'FirAppInfosdevices'}); this.$router.push({name: 'FirAppInfosdevices'});
} }
@ -131,9 +135,7 @@
return ftype return ftype
}, },
}, },
computed: { computed: {}, mounted() {
}, mounted() {
getappinfos(data => { getappinfos(data => {
if (data.code === 1000) { if (data.code === 1000) {

@ -191,9 +191,11 @@
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 {

@ -35,9 +35,7 @@
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) {
@ -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>

@ -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>
@ -270,8 +272,7 @@
'$store.state.currentapp': function () { '$store.state.currentapp': function () {
this.appinit(); this.appinit();
}, },
},computed:{ }, computed: {}
}
} }
</script> </script>

@ -371,7 +371,8 @@
<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"
icon="el-icon-loading"
circle></el-button> 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"
@ -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) {
@ -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);

@ -32,11 +32,14 @@
</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 }}
@ -60,14 +64,23 @@
<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>
@ -203,8 +216,7 @@
} }
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({
@ -319,8 +331,7 @@
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',
@ -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">
@ -45,6 +47,7 @@
<script> <script>
import {logout} from '../restful' import {logout} from '../restful'
export default { export default {
name: "FirHeader", name: "FirHeader",
data() { data() {
@ -64,8 +67,7 @@ import {logout} from '../restful'
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("退出成功");

@ -1,7 +1,8 @@
<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;">
@ -21,8 +22,15 @@
<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 v-if="isedit && editdeveloperinfo.is_actived && !editdeveloperinfo.certid" size="small"
@click="isocertcert">手动创建证书
</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="updateorcreate">保存</el-button>
<el-button @click="canceledit">取消</el-button> <el-button @click="canceledit">取消</el-button>
</div> </div>
@ -37,14 +45,20 @@
: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
@ -52,13 +66,19 @@
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>
@ -91,19 +113,41 @@
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>
@ -143,11 +187,13 @@
<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,7 +201,31 @@
</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"
@ -172,7 +242,9 @@
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"
@ -226,7 +298,9 @@
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
@ -286,7 +360,8 @@
<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>
@ -333,7 +408,8 @@
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: {
@ -359,37 +435,47 @@
}, },
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",
inputcode(developer){ "data": {"email": this.editdeveloperinfo.email, "act": "ioscert"}
this.$prompt('请输入验证码', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
closeOnClickModal:false,
}).then(({ value }) => {
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: '取消激活'
}); });
},
inputcode() {
this.authcode = this.authcode.replace(/^\s+|\s+$/g, "");
if (this.authcode.toString().length > 5 && IsNum(this.authcode)) {
this.iosdeveloperFun({
"methods": "PUT",
"data": {"email": this.authemail, "act": "nowactive", "code": this.authcode}
}); });
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;
@ -441,8 +527,8 @@
} 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})
} }
@ -497,15 +583,20 @@
this.$message.success("操作成功"); this.$message.success("操作成功");
this.activeName = "iosdeveloper"; this.activeName = "iosdeveloper";
this.editdeveloperinfo = {}; this.editdeveloperinfo = {};
} }
if (!this.edit && this.editdeveloperinfo.email) {
this.$message.success("添加成功");
this.activeName = "iosdeveloper";
this.editdeveloperinfo = {};
} }
else if(data.code === 1008){ } else if (data.code === 1008) {
this.$message.error(data.msg); this.$message.error(data.msg);
} } else {
else {
this.$message.error("操作失败") this.$message.error("操作失败")
} }
if (this.codeactiveVisible) {
this.codeactiveVisible = false;
}
}, params) }, params)
}, },
iosdevicesudidFun(action, data) { iosdevicesudidFun(action, data) {

@ -148,11 +148,13 @@
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!');
} }
@ -188,9 +190,7 @@
'$store.state.userInfoIndex': function () { '$store.state.userInfoIndex': function () {
this.autoSetInfoIndex(); this.autoSetInfoIndex();
}, },
},filters:{ }, filters: {}, computed: {
},computed:{
getuppicurl() { getuppicurl() {
return getuserpicurl() return getuserpicurl()
} }

@ -66,10 +66,12 @@
} 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() {

@ -1,7 +1,8 @@
<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;">
@ -38,7 +39,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='disabled' v-model="editstorageinfo.additionalparameter.endpoint"></el-input> <el-input :disabled='disabled'
v-model="editstorageinfo.additionalparameter.endpoint"></el-input>
</el-form-item> </el-form-item>
</div> </div>
@ -71,7 +73,9 @@
</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>-->
@ -84,7 +88,8 @@
<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="备注">
@ -175,7 +181,9 @@
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>

@ -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,6 +12,8 @@ Axios.defaults.httpsAgent = new https.Agent({
const DOMAIN = 'https://fly.harmonygames.cn'; const DOMAIN = 'https://fly.harmonygames.cn';
// const DOMAIN = 'https://testapp.harmonygames.cn';
// const DOMAIN = 'http://172.16.133.34:8000';
const APIPATH = '/api/v1/fir/server'; const APIPATH = '/api/v1/fir/server';
let USERSEVER = DOMAIN + APIPATH; let USERSEVER = DOMAIN + APIPATH;
@ -41,20 +44,7 @@ export function set_auth_token() {
set_auth_token(); set_auth_token();
function getData(methods = true, url, params = {}, callBack, load, isCode = false) { function ErrorMsg(error) {
if (methods === "DELETE") {
Axios
.delete(url, {params:params})
.then(function (response) {
if (isCode) {
callBack(response.data);
} else {
callBack(response.data.data);
}
})
.catch(function (error) {
if (error && error.response) { if (error && error.response) {
switch (error.response.status) { switch (error.response.status) {
case 400: case 400:
@ -96,16 +86,35 @@ function getData(methods = true, url, params = {}, callBack, load, isCode = fals
} else { } else {
error.message = '连接服务器失败!'; error.message = '连接服务器失败!';
} }
if (error.response && error.response.status === 403) {
router.push({name: 'FirLogin'});
}
if (error.message === 'Network Error') { if (error.message === 'Network Error') {
alert('网络连接失败'); alert('网络连接失败');
} else { } else {
alert(error) alert(error)
} }
}
function getData(methods = true, url, params = {}, callBack, load, isCode = false) {
if (methods === "DELETE") {
Axios
.delete(url, {params: params})
.then(function (response) {
if (isCode) {
callBack(response.data);
} else {
callBack(response.data.data);
}
})
.catch(function (error) {
ErrorMsg(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,8 +141,7 @@ 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 {
@ -148,11 +151,8 @@ function getData(methods = true, url, params = {}, callBack, load, isCode = fals
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);
}); });
} }
@ -349,6 +349,7 @@ 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
} }

@ -14,7 +14,6 @@ export function getScrollTop(){
} }
//文档的总高度 //文档的总高度
export function getScrollHeight() { export function getScrollHeight() {
let scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0; let scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;
@ -173,6 +172,7 @@ export function uploadaliyunoss(file,certinfo,app,successcallback,processcallbac
import {uploadstorage} from '../restful' import {uploadstorage} from '../restful'
export function uploadlocalstorage(file, certinfo, app, successcallback, processcallback) { export function uploadlocalstorage(file, certinfo, app, successcallback, processcallback) {
uploadstorage(certinfo, file, 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;
} }

@ -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开发平台同步设备信息',

@ -27,7 +27,6 @@ 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)

@ -16,6 +16,7 @@ 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):
@ -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基类

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

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

@ -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
@ -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网关地址均从使用的接口定义

@ -9,8 +9,8 @@ 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 = {}
@ -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,8 +95,8 @@ 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))
@ -105,7 +107,6 @@ def get_random_short():
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
@ -176,4 +177,3 @@ def SaveAppInfos(app_file_name,user_obj,appinfo,bundle_id,app_img,short,size):
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()

@ -26,6 +26,7 @@ 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)
@ -39,7 +40,6 @@ 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():
@ -47,6 +47,7 @@ def get_ios_info_path( ipaobj):
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():
@ -54,6 +55,7 @@ def get_ios_icon_path( ipaobj):
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)

@ -24,7 +24,6 @@ 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
@ -59,7 +58,6 @@ 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)
@ -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)
@ -366,6 +364,7 @@ class QrCode(object):
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"
@ -382,4 +381,3 @@ if __name__ == '__main__':
# 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())

@ -9,6 +9,7 @@ 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"
@ -26,14 +27,15 @@ def exec_shell(cmd,remote=False,timeout=None):
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
@ -67,7 +69,8 @@ class AppDeveloperApi(object):
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):
@ -107,6 +110,5 @@ class ResignApp(object):
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): def sign(self, new_profile, org_ipa, new_ipa):
self.cmd = self.cmd + " -p '%s' -o '%s' '%s'" % (new_profile, new_ipa, org_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,6 +5,7 @@
# 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]
@ -13,16 +14,14 @@ def make_from_user_uuid(userinfo):
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,11 +13,11 @@ Python生成二维码 v1.0
''' '''
import qrcode import qrcode
from PIL import Image from PIL import Image
import os import os
# 生成二维码图片 # 生成二维码图片
def make_qr(str, save): def make_qr(str, save):
qr = qrcode.QRCode( qr = qrcode.QRCode(
@ -87,5 +87,4 @@ if __name__=='__main__':
str = "https://fir.im/luy4" str = "https://fir.im/luy4"
make_logo_qr(str, logo, save_path) make_logo_qr(str, logo, save_path)

@ -11,6 +11,7 @@ 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'}
@ -33,8 +34,6 @@ def portisonline(host,port):
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
@ -66,7 +65,6 @@ class SSHConnection(object):
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:
@ -87,11 +85,14 @@ 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:
@ -104,13 +105,13 @@ def pshell_command(cmdstrs,user_obj,developer_email,timeout=60*10):
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:
@ -123,13 +124,13 @@ def pshell_command(cmdstrs,user_obj,developer_email,timeout=60*10):
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
@ -152,7 +153,7 @@ def shell_command(cmdstrs,timeout):
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,6 +162,7 @@ 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)
@ -180,9 +182,7 @@ def use_user_pass(hostip,port,user,passwd,cmdstrs):
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,7 +7,8 @@
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
@ -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,
developerid__certid__isnull=False).first()
# 只要账户下面存在udid,就可以使用该苹果开发者账户,避免多个开发者账户下面出现同一个udid # 只要账户下面存在udid,就可以使用该苹果开发者账户,避免多个开发者账户下面出现同一个udid
if usedeviceobj :#and usedeviceobj.developerid.use_number < usedeviceobj.developerid.usable_number: 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:
@ -191,22 +192,27 @@ class IosUtils(object):
# 更新已经完成签名状态,设备消耗记录,和开发者已消耗数量 # 更新已经完成签名状态,设备消耗记录,和开发者已消耗数量
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,
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')) 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)
# 创建 # 创建
@ -219,7 +225,8 @@ class IosUtils(object):
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):
@ -255,7 +262,6 @@ class IosUtils(object):
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):
@ -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,8 +289,6 @@ 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):
''' '''
@ -294,7 +297,8 @@ class IosUtils(object):
: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:
@ -338,7 +342,6 @@ 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):
''' '''
@ -357,9 +360,6 @@ class IosUtils(object):
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 :
IosUtils.create_developer_cert(developer_obj,user_obj)
IosUtils.get_device_from_developer(developer_obj, user_obj)
return status, result return status, result
@staticmethod @staticmethod

@ -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):
@ -30,7 +31,8 @@ class ExpiringTokenAuthentication(BaseAuthentication):
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"})
@ -39,4 +41,3 @@ class ExpiringTokenAuthentication(BaseAuthentication):
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

@ -26,6 +26,3 @@ def sync_download_times_by_app_id(app_ids):
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)

@ -1,11 +1,9 @@
from django.utils.deprecation import MiddlewareMixin from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
class CorsMiddleWare(MiddlewareMixin):
def process_response(self, request, response): def process_response(self, request, response):
if request.method == "OPTIONS": 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"

@ -1,5 +1,3 @@
from django.core.cache import cache from django.core.cache import cache
import datetime import datetime
@ -10,6 +8,7 @@ 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):
@ -18,4 +17,3 @@ class LoginUserPermission(BaseAuthentication):
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__

@ -8,14 +8,17 @@ 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)
@ -79,11 +82,11 @@ 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()
@ -91,6 +94,7 @@ class AppsShortSerializer(serializers.ModelSerializer):
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):
@ -113,7 +117,8 @@ class AppsShortSerializer(serializers.ModelSerializer):
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,
@ -140,6 +145,7 @@ class AppReleaseSerializer(serializers.ModelSerializer):
"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()
@ -217,6 +223,7 @@ class StorageSerializer(serializers.ModelSerializer):
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
@ -225,12 +232,14 @@ class DeveloperSerializer(serializers.ModelSerializer):
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

@ -40,6 +40,7 @@ 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 = ''
@ -49,6 +50,7 @@ class StsToken(object):
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):
@ -63,7 +65,6 @@ class AliYunOss(object):
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

@ -12,10 +12,13 @@ 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:
@ -27,11 +30,14 @@ def get_download_url_by_cache(app_obj, filename, limit, isdownload=True,key='',u
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:
@ -57,7 +63,8 @@ def get_app_instance_by_cache(app_id,password, limit,udid):
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")
@ -84,6 +91,7 @@ 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=''): def del_cache_response_by_short(short, app_id, udid=''):
cache.delete("_".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, '*']) key = "_".join([CACHE_KEY_TEMPLATE.get("download_short_key"), short, '*'])
@ -93,21 +101,25 @@ def del_cache_response_by_short(short,app_id,udid=''):
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(
"_".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])) cache.delete("_".join([key, download_val, user_obj.head_img]))
@ -120,6 +132,7 @@ def del_cache_storage(user_obj):
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"),
@ -129,6 +142,7 @@ def set_app_today_download_times(app_id):
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)

@ -10,6 +10,7 @@ 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
@ -37,4 +38,3 @@ class LocalStorage(object):
except Exception as e: except Exception as e:
print(e) print(e)
return False return False

@ -9,6 +9,7 @@
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
@ -49,4 +50,3 @@ class QiNiuOss(object):
# 删除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

@ -5,13 +5,13 @@
# 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)
@ -59,7 +59,6 @@ def get_developer_udided(developer_obj):
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):
other_used_sum = 0 other_used_sum = 0
flyapp_used_sum = 0 flyapp_used_sum = 0

@ -19,6 +19,7 @@ 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}

@ -12,16 +12,20 @@ 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,)
@ -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()
@ -81,6 +87,7 @@ class DownloadView(APIView):
res.msg = "token校验失败" res.msg = "token校验失败"
return Response(res.dict) return Response(res.dict)
class ShortDownloadView(APIView): class ShortDownloadView(APIView):
''' '''
根据下载短链接获取应用信息 根据下载短链接获取应用信息
@ -103,7 +110,8 @@ class ShortDownloadView(APIView):
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)
@ -119,7 +127,9 @@ class ShortDownloadView(APIView):
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):
''' '''
@ -152,7 +162,8 @@ class InstallView(APIView):
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"):
@ -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)

@ -12,9 +12,12 @@ 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()
@ -74,6 +77,7 @@ class LoginView(APIView):
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, ]
@ -129,4 +133,3 @@ class UserInfoView(APIView):
return Response(res.dict) return Response(res.dict)
return Response(res.dict) return Response(res.dict)

@ -9,6 +9,7 @@ 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):
@ -19,7 +20,8 @@ class IosUDIDView(View):
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,
defaults={'udid': format_udid_info.get('udid')})
ios_obj = IosUtils(format_udid_info, app_info.user_id, app_info) ios_obj = IosUtils(format_udid_info, app_info.user_id, app_info)
ios_obj.resign() ios_obj.resign()
else: else:
@ -31,5 +33,3 @@ class IosUDIDView(View):
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")))

@ -16,7 +16,6 @@ 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中每页显示条数的参数
@ -38,7 +37,8 @@ class DeveloperView(APIView):
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, )
@ -59,6 +59,14 @@ class DeveloperView(APIView):
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
@ -79,8 +87,22 @@ 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":
status, result = IosUtils.get_device_from_developer(developer_obj, request.user)
if status:
IosUtils.get_device_from_developer(developer_obj, request.user) 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))
@ -126,6 +148,7 @@ class DeveloperView(APIView):
return self.get(request) return self.get(request)
class SuperSignUsedView(APIView): class SuperSignUsedView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ] authentication_classes = [ExpiringTokenAuthentication, ]
@ -146,13 +169,15 @@ class SuperSignUsedView(APIView):
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, ]
@ -168,7 +193,8 @@ class AppUDIDUsedView(APIView):
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

@ -18,8 +18,8 @@ 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):
@ -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,7 +166,8 @@ 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)
@ -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 = [
@ -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
@ -96,7 +93,6 @@ DATABASES = {
} }
# 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,7 +129,6 @@ 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/
@ -150,8 +145,6 @@ 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",
"gee_test_access_key": "7eb11ccf3e0953bdd060ed8b60b0c4f5", "gee_test_access_key": "7eb11ccf3e0953bdd060ed8b60b0c4f5",
@ -161,8 +154,6 @@ GEE_TEST = {
], # 不用验证的用户(存放着用户的uid) ], # 不用验证的用户(存放着用户的uid)
} }
CACHES = { CACHES = {
"default": { "default": {
"BACKEND": "django_redis.cache.RedisCache", "BACKEND": "django_redis.cache.RedisCache",
@ -176,7 +167,6 @@ CACHES = {
}, },
} }
# 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',
@ -217,7 +207,7 @@ THIRD_PART_CONFIG = {
'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',

@ -35,7 +35,6 @@ 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)),

@ -1,6 +1,6 @@
import requests import requests
import random import random
short = ["bgql", "wjbu", "vnfg", "bgql"] short = ["bgql", "wjbu", "vnfg", "bgql"]
udid_lists = [ udid_lists = [
@ -34,11 +34,9 @@ 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)

Loading…
Cancel
Save