Browse Source

提交代码,解决冲突。

Signed-off-by: zouap <zouap@pcl.ac.cn>
tags/v1.22.3.2^2
zouap 3 years ago
parent
commit
78ce5f5e1b
100 changed files with 27104 additions and 769 deletions
  1. +3
    -0
      README.md
  2. +0
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep
  3. +0
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep 3
  4. +2317
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css
  5. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.eot
  6. +1
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.glyph.json
  7. +2319
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.less
  8. +6835
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.svg
  9. +11356
    -0
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.symbol.svg
  10. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.ttf
  11. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff
  12. BIN
      custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff2
  13. +157
    -16
      custom/public/css/git.openi.css
  14. +13
    -0
      custom/public/swiper/swiper-bundle.min.css
  15. +14
    -0
      custom/public/swiper/swiper-bundle.min.js
  16. +3
    -1
      go.mod
  17. +9
    -41
      go.sum
  18. +19
    -0
      models/action.go
  19. +13
    -0
      models/attachment.go
  20. +44
    -4
      models/cloudbrain.go
  21. +13
    -0
      models/error.go
  22. +8
    -0
      models/models.go
  23. +51
    -0
      models/repo.go
  24. +163
    -0
      models/repo_tag.go
  25. +5
    -2
      models/repo_watch.go
  26. +134
    -53
      models/user_business_analysis.go
  27. +267
    -0
      models/user_business_struct.go
  28. +4
    -0
      modules/auth/org.go
  29. +148
    -12
      modules/cloudbrain/cloudbrain.go
  30. +6
    -0
      modules/context/context.go
  31. +8
    -0
      modules/context/repo.go
  32. +13
    -16
      modules/modelarts/modelarts.go
  33. +3
    -3
      modules/modelarts/resty.go
  34. +10
    -2
      modules/repository/elk_pagedata.go
  35. +24
    -8
      modules/setting/setting.go
  36. +4
    -0
      modules/storage/local.go
  37. +28
    -0
      modules/storage/minio.go
  38. +1
    -0
      modules/storage/storage.go
  39. +10
    -0
      modules/util/util.go
  40. +46
    -1
      options/locale/locale_en-US.ini
  41. +48
    -1
      options/locale/locale_zh-CN.ini
  42. +5
    -0
      package-lock.json
  43. +1
    -0
      package.json
  44. +442
    -0
      public/home/home.js
  45. +13
    -10
      routers/actionnotification.go
  46. +8
    -2
      routers/api/v1/api.go
  47. +6
    -11
      routers/api/v1/repo/modelarts.go
  48. +48
    -9
      routers/home.go
  49. +87
    -0
      routers/notice/notice.go
  50. +8
    -0
      routers/org/home.go
  51. +90
    -0
      routers/org/tag.go
  52. +49
    -7
      routers/repo/ai_model_manage.go
  53. +52
    -8
      routers/repo/blame.go
  54. +158
    -79
      routers/repo/cloudbrain.go
  55. +5
    -0
      routers/repo/issue.go
  56. +160
    -74
      routers/repo/modelarts.go
  57. +126
    -0
      routers/repo/user_data_analysis.go
  58. +13
    -7
      routers/routes/routes.go
  59. +1
    -2
      services/repository/repository.go
  60. +5
    -0
      services/socketwrap/client.go
  61. +46
    -11
      services/socketwrap/clientManager.go
  62. +7
    -0
      templates/base/footer_content.tmpl
  63. +6
    -0
      templates/base/footer_content_fluid.tmpl
  64. +44
    -2
      templates/base/head.tmpl
  65. +43
    -0
      templates/base/head_fluid.tmpl
  66. +13
    -10
      templates/base/head_home.tmpl
  67. +10
    -0
      templates/base/head_navbar.tmpl
  68. +8
    -0
      templates/base/head_navbar_fluid.tmpl
  69. +8
    -0
      templates/base/head_navbar_home.tmpl
  70. +8
    -0
      templates/base/head_navbar_pro.tmpl
  71. +44
    -0
      templates/base/head_pro.tmpl
  72. +1
    -1
      templates/base/paginate.tmpl
  73. +13
    -13
      templates/explore/repo_list.tmpl
  74. +1
    -1
      templates/explore/repo_orgtop.tmpl
  75. +1
    -0
      templates/explore/repo_search.tmpl
  76. +132
    -192
      templates/home.tmpl
  77. +5
    -4
      templates/org/home.tmpl
  78. +3
    -2
      templates/org/member/members.tmpl
  79. +37
    -5
      templates/org/navber.tmpl
  80. +319
    -0
      templates/org/select_pro.tmpl
  81. +3
    -3
      templates/org/team/teams.tmpl
  82. +20
    -3
      templates/repo/cloudbrain/new.tmpl
  83. +147
    -46
      templates/repo/debugjob/index.tmpl
  84. +3
    -3
      templates/repo/header.tmpl
  85. +1
    -0
      templates/repo/issue/list.tmpl
  86. +6
    -24
      templates/repo/modelarts/trainjob/index.tmpl
  87. +142
    -8
      templates/repo/modelarts/trainjob/show.tmpl
  88. +18
    -6
      templates/repo/modelmanage/index.tmpl
  89. +265
    -66
      templates/repo/modelmanage/showinfo.tmpl
  90. +12
    -0
      vendor/github.com/elliotchance/orderedmap/.editorconfig
  91. +1
    -0
      vendor/github.com/elliotchance/orderedmap/.gitignore
  92. +9
    -0
      vendor/github.com/elliotchance/orderedmap/.travis.yml
  93. +21
    -0
      vendor/github.com/elliotchance/orderedmap/LICENSE
  94. +102
    -0
      vendor/github.com/elliotchance/orderedmap/README.md
  95. +33
    -0
      vendor/github.com/elliotchance/orderedmap/element.go
  96. +5
    -0
      vendor/github.com/elliotchance/orderedmap/go.mod
  97. +15
    -0
      vendor/github.com/elliotchance/orderedmap/go.sum
  98. +150
    -0
      vendor/github.com/elliotchance/orderedmap/orderedmap.go
  99. +9
    -0
      vendor/github.com/patrickmn/go-cache/CONTRIBUTORS
  100. +19
    -0
      vendor/github.com/patrickmn/go-cache/LICENSE

+ 3
- 0
README.md View File

@@ -46,3 +46,6 @@
- 点击[这里](https://git.openi.org.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**)
- 加入微信群实时交流,获得进一步的支持
<img src="https://git.openi.org.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px />

## 启智社区小白训练营:
- 结合案例给大家详细讲解如何使用社区平台,帮助无技术背景的小白成长为启智社区达人 (https://git.openi.org.cn/zeizei/OpenI_Learning)

+ 0
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep View File


+ 0
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/.keep 3 View File


+ 2317
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css
File diff suppressed because it is too large
View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.eot View File


+ 1
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.glyph.json
File diff suppressed because it is too large
View File


+ 2319
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.less
File diff suppressed because it is too large
View File


+ 6835
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.svg
File diff suppressed because it is too large
View File


+ 11356
- 0
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.symbol.svg
File diff suppressed because it is too large
View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.ttf View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff View File


BIN
custom/public/RemixIcon_Fonts_v2.5.0/fonts/remixicon.woff2 View File


+ 157
- 16
custom/public/css/git.openi.css View File

@@ -24,11 +24,27 @@
.am-pt-20{ padding-top: 2.0rem !important;}
.am-pt-30{ padding-top: 3.0rem !important;}
.am-pl-30{ padding-left: 3.0rem !important;}
.am-pl-50{ padding-left: 5.0em !important;}
.am-ml-10{ margin-left: 1.0rem !important;}
.am-ml-30{ margin-left: 3.0rem !important;}
.am-pr-30{ padding-right: 3.0rem !important;}
.am-mr-30{ margin-right: 3.0rem !important;}
.am-lh-18{ line-height: 1.8em;}

.nowrap{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.nowrap-2 {
max-height: 2.837em;
line-height: 1.4285em;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}

.opacity5{ opacity:0.5;}
.radius15{ border-radius:1.5rem !important; }
.radius10{ border-radius:1.0rem !important; }
@@ -42,12 +58,15 @@
box-shadow: 0 2px 4px 0 rgba(34,36,38,.3);
}

.ui.blue {
color: #0366d6;
}

.ui.secondary.hometop.segment{
background: #DFE9F0;
padding-top: 0;
border: none;
margin-bottom: 90px;
margin-bottom: 11em;
}
.ui.secondary.hometop.segment #navbar{
z-index: 10;
@@ -68,6 +87,7 @@
.homebanner{
position: relative;
padding: 100px 32px 80px;
padding-bottom: 0;
z-index: 9;
}
.homebanner .ui.header .sub.header{
@@ -75,10 +95,15 @@
}
.bannerpic{
position: absolute;
right: 50px;
right: 0px;
bottom: -64px;
width: 560px;
z-index: 6;
}
.homebanner .ui.button{
font-weight: normal;
}

.ui[class*="very padded"].segment.i-code{
padding-left: 6.0rem;
}
@@ -115,25 +140,141 @@
.i-env .ui.cards>.card>.content{
border-top: none;
}
.leftline01{

#homenews{
position: relative;
z-index: 9;
bottom: -6em;
}
#homenews > p{
color: #BBBBBB;
margin-left: 2.3em;
}
.homenews{
border-radius: 2em;
background-color: rgba(16, 16, 16, .9);
position: relative;
padding-left: 2.3em !important;
}
.homeorg, .homepro, .homemodel, .i-env{
position: relative;
padding-bottom: 5em;
}
.homenews::before{
content: '';
position: absolute;
left: 3.0rem;
left: 3em;
top: 0;
bottom: 0;
border-left: 2px solid #505559;
border-bottom: 2px solid #505559;
border-radius: 0 0 0 2.0rem;
width: 2.0rem;
background-color: rgba(105, 192, 255, .4);
width: 2px;
}
.homenews .time-since{
padding-left: 1em;
color: #888888;
}
.homenews a{
color: #69C0FF;
}
.leftline02{
.homenews .ui.list>.item>.content{
color: #E8E8E8;
line-height: 1.8em;
width: calc(100% - 3.25em) !important;
}
.homenews .ui.list>.item{
padding: 0;
}
.newslist{
height: 325px;
overflow: hidden;
}

.leftline01, .leftline03, .leftline04{
position: absolute;
left: 5rem;
top: calc(-5.0rem - 2px);
border-top: 2px solid #505559;
border-right: 2px solid #505559;
border-radius: 0 2.0rem 0 0;
width: 17.5rem;
height: 6.0rem;
width: 5em;
border-radius: 0 0 0 4.0em;
border-left: 2px solid #3291F8;
border-bottom: 2px solid #3291F8;
top: -5em;
bottom: 0;
left: 2em;
z-index: 6;
}
.leftline02, .leftline02-2 {
position: absolute;
left: 7.0em;
top: -2px;
bottom: 2px;
height: auto;
border-top: 2px solid #3291F8;
border-right: 2px solid #3291F8;
border-bottom: 2px solid #3291F8;
border-radius: 0 4.0em 4.0em 0;
width: 10em;
z-index: 6;
}
.leftline03{
border-radius: 4.0em 0 0 0;
border-top: 2px solid #3291F8;
border-bottom:none;
top: -2.0em;
}
.leftline02-2{
border-color: rgba(105, 192, 255, .4);
width: 7em;
z-index: 5;
}
.leftline04{
border-radius: 0;
border-top: none;
border-bottom: none;
}

.homeorg-tit{
padding-left: 5em !important;
}
.homeorg-tit::after{
content: '';
position: absolute;
width: 1.6em;
height: 1.6em;
background-color: #FFF;
border: 2px solid #3291F8;
left: 2.3em;
top: 1.3em;
border-radius: 1em;
z-index: 9;
}
.homeorg-list .card{
background-image: linear-gradient(#FFF, #FFF 60%, #DFF0EF) !important;
box-shadow: none !important;
}
.homeorg-list .card .ui.small.header .content{
width: calc(100% - 3.25em);
}
.homepro-list{
position: relative;
z-index: 9;
padding: 1.0em 1.0em 3.0em;
overflow: hidden;
}
.homepro-list .ui.card{
border-radius: 15px;
background-color: #FFF;
box-shadow: 0px 5px 10px 0px rgba(105, 192, 255, 30);
border: 1px solid rgba(105, 192, 255, 40);
min-height: 10.8em;
}
.homepro-list .ui.card>.content>.header{
line-height: 40px !important;
}

.homepro-list .swiper-pagination-bullet-active{
width: 40px;
border-radius: 4px;
}
.i-env > div{
position: relative;
}

@media only screen and (max-width: 767px) {


+ 13
- 0
custom/public/swiper/swiper-bundle.min.css
File diff suppressed because it is too large
View File


+ 14
- 0
custom/public/swiper/swiper-bundle.min.js
File diff suppressed because it is too large
View File


+ 3
- 1
go.mod View File

@@ -32,6 +32,7 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dustin/go-humanize v1.0.0
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1
github.com/elliotchance/orderedmap v1.4.0
github.com/emirpasic/gods v1.12.0
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
@@ -87,6 +88,7 @@ require (
github.com/niklasfasching/go-org v0.1.9
github.com/oliamb/cutter v0.2.2
github.com/olivere/elastic/v7 v7.0.9
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.2.0
github.com/prometheus/client_golang v1.1.0
@@ -99,7 +101,7 @@ require (
github.com/sergi/go-diff v1.1.0
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
github.com/stretchr/testify v1.4.0
github.com/stretchr/testify v1.7.0
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect
github.com/tinylib/msgp v1.1.2 // indirect
github.com/tstranex/u2f v1.0.0


+ 9
- 41
go.sum View File

@@ -39,11 +39,9 @@ gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Y
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a h1:aOKEXkDTnh4euoH0so/THLXeHtQuqHmDPb1xEk6Ehok=
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM=
gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827/go.mod h1:/rvxMjIkOq4BM8uPUb+VHuU02ZfAO6R4+wD//tiCiRw=
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA=
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs=
gitea.com/macaron/macaron v1.4.0 h1:FY1QDGqyuUzs21K6ChkbYbRUfwL7v2aUrhNEJ0IgsAw=
gitea.com/macaron/macaron v1.4.0/go.mod h1:P7hfDbQjcW22lkYkXlxdRIfWOXxH2+K4EogN4Q0UlLY=
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705 h1:mvkQGAlON1Z6Y8pqa/+FpYIskk54mazuECUfZK5oTg0=
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705/go.mod h1:1ujH0jD6Ca4iK9NL0Q2a7fG2chvXx5hVa7hBfABwpkA=
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d h1:XLww3CvnFZkXVwauN67fniDaIpIqsE+9KVcxlZKlvLU=
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d/go.mod h1:FanKy3WjWb5iw/iZBPk4ggoQT9FcM6bkBPvmDmsH6tY=
@@ -70,7 +68,6 @@ github.com/RichardKnop/machinery v1.6.9 h1:dQu1c7ENgPFrN9qWweEe7xDDvNYGSqEyprK0G
github.com/RichardKnop/machinery v1.6.9/go.mod h1:BO7MG/5tvdpgMVkOT8V94SEf8x8H8aceRzTt8Tx1IMc=
github.com/RichardKnop/redsync v1.2.0 h1:gK35hR3zZkQigHKm8wOGb9MpJ9BsrW6MzxezwjTcHP0=
github.com/RichardKnop/redsync v1.2.0/go.mod h1:9b8nBGAX3bE2uCfJGSnsDvF23mKyHTZzmvmj5FH3Tp0=
github.com/RoaringBitmap/roaring v0.4.21 h1:WJ/zIlNX4wQZ9x8Ey33O1UaD9TCTakYsdLFSBcTwH+8=
github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo=
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
@@ -140,11 +137,9 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d h1:XMf4E1U+b9E3ElF0mjvfXZdflBRZz4gLp16nQ/QSHQM=
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 h1:vZryARwW4PSFXd9arwegEywvMTvPuXL3/oa+4L5NTe8=
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b h1:bZ9rKU2/V8sY+NulSfxDOnXTWcs1rySqdF1sVepihvo=
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 h1:0WMIDtuXCKEm4wtAJgAAXa/qtM5O9MariLwgHaRlYmk=
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
@@ -169,7 +164,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 h1:bpWCJ5MddHsv4Xtl3azkK89mZzd/vvut32mvAnKbyUA=
github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
@@ -185,8 +179,9 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 h1:mhPg/0hGebcpiiQLqJD2PWWyoHRLEdZ3sXKaEvT1EQU=
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1/go.mod h1:/LuhWJiQ9Gvo1DhVpa4ssm5qeg8rrztdtI7j/iCie2k=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A=
github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a h1:M1bRpaZAn4GSsqu3hdK2R8H0AH9O6vqCTCbm2oAFGfE=
@@ -306,7 +301,6 @@ github.com/go-swagger/go-swagger v0.21.0 h1:AX9mdfzp6eJtUe92nFrWmbK7ocRgkCDPJs0F
github.com/go-swagger/go-swagger v0.21.0/go.mod h1:tDb8PdDVFcaE8EPXkMOsuxpL3UEPiwu1UDZar9Z/1RY=
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0=
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
@@ -330,13 +324,11 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
@@ -349,7 +341,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -375,7 +366,6 @@ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -406,7 +396,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY=
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
@@ -458,7 +447,6 @@ github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY=
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0=
github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
@@ -472,7 +460,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@@ -545,7 +532,6 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA=
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
@@ -580,6 +566,8 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
@@ -588,7 +576,6 @@ github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -715,12 +702,13 @@ github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9 h1:wR6aLKdbJ5E8m+NZ
github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@@ -731,7 +719,6 @@ github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
@@ -746,7 +733,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/unknwon/cae v1.0.0 h1:i39lOFaBXZxhGjQOy/RNbi8uzettCs6OQxpR0xXohGU=
github.com/unknwon/cae v1.0.0/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
@@ -772,7 +758,6 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE=
github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK2vjGh6yI=
github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.25 h1:isv+Q6HQAmmL2Ofcmg8QauBmDPlUUnSoNhEcC940Rds=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -813,16 +798,15 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -832,9 +816,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -865,7 +847,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@@ -876,7 +857,6 @@ golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -915,13 +895,10 @@ golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190907184412-d223b2b6db03/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -932,7 +909,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -955,14 +931,11 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200225230052-807dcd883420 h1:4RJNOV+2rLxMEfr6QIpC7GEv9MjD6ApGXTCLrNF9+eA=
golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ=
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -984,7 +957,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo=
google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
@@ -1016,7 +988,6 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
@@ -1027,7 +998,6 @@ gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1058,12 +1028,12 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1078,13 +1048,11 @@ sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM=
xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
xorm.io/xorm v1.0.1 h1:/lITxpJtkZauNpdzj+L9CN/3OQxZaABrbergMcJu+Cw=
xorm.io/xorm v1.0.1/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY=

+ 19
- 0
models/action.go View File

@@ -346,6 +346,25 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
return actions, nil
}

func GetLast20PublicFeeds() ([]*Action, error) {
cond := builder.NewCond()
cond = cond.And(builder.Eq{"is_private": false})
cond = cond.And(builder.Eq{"is_deleted": false})


actions := make([]*Action, 0, 20)

if err := x.Limit(20).Desc("id").Where(cond).Find(&actions); err != nil {
return nil, fmt.Errorf("Find: %v", err)
}

if err := ActionList(actions).LoadAttributes(); err != nil {
return nil, fmt.Errorf("LoadAttributes: %v", err)
}

return actions, nil
}

func GetUnTransformedActions() ([]*Action, error) {
actions := make([]*Action, 0, 10)
err := x.Where("op_type = ?", ActionCommitRepo).


+ 13
- 0
models/attachment.go View File

@@ -439,6 +439,19 @@ func GetModelArtsUserAttachments(userID int64) ([]*AttachmentUsername, error) {
return getModelArtsUserAttachments(x, userID)
}

func getModelArtsTrainAttachments(e Engine, userID int64) ([]*AttachmentUsername, error) {
attachments := make([]*AttachmentUsername, 0, 10)
if err := e.Table("attachment").Join("LEFT", "`user`", "attachment.uploader_id "+
"= `user`.id").Where("attachment.type = ? and (uploader_id= ? or is_private = ?) and attachment.decompress_state = ?", TypeCloudBrainTwo, userID, false, DecompressStateDone).Find(&attachments); err != nil {
return nil, err
}
return attachments, nil
}

func GetModelArtsTrainAttachments(userID int64) ([]*AttachmentUsername, error) {
return getModelArtsTrainAttachments(x, userID)
}

func CanDelAttachment(isSigned bool, user *User, attach *Attachment) bool {
if !isSigned {
return false


+ 44
- 4
models/cloudbrain.go View File

@@ -19,6 +19,9 @@ type JobType string
type ModelArtsJobStatus string

const (
NPUResource = "NPU"
GPUResource = "CPU/GPU"

JobWaiting CloudbrainStatus = "WAITING"
JobStopped CloudbrainStatus = "STOPPED"
JobSucceeded CloudbrainStatus = "SUCCEEDED"
@@ -88,6 +91,9 @@ type Cloudbrain struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
Duration int64
TrainJobDuration string
Image string //GPU镜像名称
GpuQueue string //GPU类型即GPU队列
ResourceSpecId int //GPU规格id
DeletedAt time.Time `xorm:"deleted"`
CanDebug bool `xorm:"-"`
CanDel bool `xorm:"-"`
@@ -204,6 +210,7 @@ type CloudbrainsOptions struct {
JobType string
VersionName string
IsLatestVersion string
JobTypeNot bool
}

type TaskPod struct {
@@ -888,9 +895,15 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
}

if (opts.JobType) != "" {
cond = cond.And(
builder.Eq{"cloudbrain.job_type": opts.JobType},
)
if opts.JobTypeNot {
cond = cond.And(
builder.Neq{"cloudbrain.job_type": opts.JobType},
)
} else {
cond = cond.And(
builder.Eq{"cloudbrain.job_type": opts.JobType},
)
}
}

if (opts.IsLatestVersion) != "" {
@@ -962,7 +975,9 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) {
cond = cond.And(
builder.Eq{"Status": "COMPLETED"},
)

cond = cond.And(
builder.Eq{"job_type": "TRAIN"},
)
cloudbrains := make([]*CloudbrainInfo, 0)
if err := sess.Select("job_id,job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC").
Find(&cloudbrains); err != nil {
@@ -1195,3 +1210,28 @@ func GetCloudbrainTrainJobCountByUserID(userID int64) (int, error) {
And("job_type = ? and user_id = ? and type = ?", JobTypeTrain, userID, TypeCloudBrainTwo).Count(new(Cloudbrain))
return int(count), err
}

func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) {
sess := x.NewSession()
defer sess.Close()

if err = sess.Begin(); err != nil {
return err
}

if _, err = sess.Delete(old); err != nil {
sess.Rollback()
return err
}

if _, err = sess.Insert(new); err != nil {
sess.Rollback()
return err
}

if err = sess.Commit(); err != nil {
return err
}

return nil
}

+ 13
- 0
models/error.go View File

@@ -1999,3 +1999,16 @@ func IsErrJobNotExist(err error) bool {
func (err ErrJobNotExist) Error() string {
return fmt.Sprintf("the job does not exist")
}

type ErrTagNotExist struct {
TagID int64
}

func (err ErrTagNotExist) Error() string {
return fmt.Sprintf("the tag does not exist")
}

func IsErrTagNotExist(err error) bool {
_, ok := err.(ErrTagNotExist)
return ok
}

+ 8
- 0
models/models.go View File

@@ -134,6 +134,8 @@ func init() {
new(BlockChain),
new(RecommendOrg),
new(AiModelManage),
new(OfficialTag),
new(OfficialTagRepos),
)

tablesStatistic = append(tablesStatistic,
@@ -141,6 +143,12 @@ func init() {
new(SummaryStatistic),
new(UserBusinessAnalysis),
new(UserBusinessAnalysisAll),
new(UserBusinessAnalysisCurrentYear),
new(UserBusinessAnalysisLast30Day),
new(UserBusinessAnalysisLastMonth),
new(UserBusinessAnalysisCurrentMonth),
new(UserBusinessAnalysisCurrentWeek),
new(UserBusinessAnalysisYesterday),
new(UserLoginLog),
)



+ 51
- 0
models/repo.go View File

@@ -6,6 +6,7 @@
package models

import (
"code.gitea.io/gitea/modules/git"
"context"
"crypto/md5"
"errors"
@@ -2519,3 +2520,53 @@ func UpdateRepositoryCommitNum(repo *Repository) error {

return nil
}

type RepoFile struct {
CommitId string
Content []byte
}

// ReadLatestFileInRepo read latest version of file in repository
// return a RepoFile
func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFile, error) {
var err error
repoPath := RepoPath(userName, repoName)
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
log.Error("ReadLatestFileInRepo error when OpenRepository,error=%v", err)
return nil, err
}
commitID, err := gitRepo.GetBranchCommitID(refName)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBranchCommitID,error=%v", err)
return nil, err
}
commit, err := gitRepo.GetBranchCommit(refName)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBranchCommit,error=%v", err)
return nil, err
}

blob, err := commit.GetBlobByPath(treePath)
if err != nil {
log.Error("ReadLatestFileInRepo error when GetBlobByPath,error=%v", err)
return nil, err
}

reader, err := blob.DataAsync()
if err != nil {
return nil, err
}
defer func() {
if err = reader.Close(); err != nil {
log.Error("ReadLatestFileInRepo: Close: %v", err)
}
}()

buf := make([]byte, 1024)
n, _ := reader.Read(buf)
if n >= 0 {
buf = buf[:n]
}
return &RepoFile{CommitId: commitID, Content: buf}, nil
}

+ 163
- 0
models/repo_tag.go View File

@@ -0,0 +1,163 @@
package models

import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"fmt"
)

type OfficialTag struct {
ID int64 `xorm:"pk autoincr"`
Name string `xorm:"NOT NULL"`
Code string `xorm:"NOT NULL"`
Limit int `xorm:"NOT NULL default(-1)"`
Status int `xorm:"NOT NULL default(0)"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}

type OfficialTagRepos struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"NOT NULL INDEX"`
TagID int64 `xorm:"NOT NULL"`
RepoID int64 `xorm:"NOT NULL INDEX"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}

type TagReposBrief struct {
RepoID int64
RepoName string
TagID int64
}

type TagReposSelected struct {
RepoID int64
RepoName string
Selected bool
}

type TagsDetail struct {
TagId int64
TagName string
TagLimit int
RepoList []Repository
}

func GetTagByID(id int64) (*OfficialTag, error) {
r := &OfficialTag{
ID: id,
}
has, err := x.Get(r)
if err != nil {
return nil, err
} else if !has {
return nil, ErrTagNotExist{0}
}
return r, nil
}

func UpdateTagReposByID(tagID, orgID int64, repoIdList []int64) error {
sess := x.NewSession()
defer sess.Close()

if err := sess.Begin(); err != nil {
return fmt.Errorf("UpdateTagReposByID[tagId: %d, orgID: %d,error:%v", tagID, orgID, err)
}
//delete old tag repos
r := &OfficialTagRepos{
TagID: tagID,
OrgID: orgID,
}
_, err := sess.Delete(r)
if err != nil {
return err
}

if len(repoIdList) == 0 {
return sess.Commit()
}

//add new tag repos
data := make([]*OfficialTagRepos, 0)
for _, repoId := range repoIdList {
data = append(data, &OfficialTagRepos{
OrgID: orgID,
TagID: tagID,
RepoID: repoId,
})
}
_, err = sess.Insert(&data)
if err != nil {
sess.Rollback()
return err
}
return sess.Commit()
}

func GetTagRepos(tagID, orgID int64) ([]TagReposSelected, error) {
t := make([]TagReposBrief, 0)
const SQLCmd = "select t1.id as repo_id,t1.name as repo_name,t2.id as tag_id from repository t1 left join official_tag_repos t2 on (t1.id = t2.repo_id and t2.tag_id = ?) where t1.owner_id = ? and t1.is_private = false order by t1.updated_unix desc"

if err := x.SQL(SQLCmd, tagID, orgID).Find(&t); err != nil {
return nil, err
}
r := make([]TagReposSelected, 0)
for _, v := range t {
selected := false
if v.TagID > 0 {
selected = true
}
r = append(r, TagReposSelected{
RepoID: v.RepoID,
RepoName: v.RepoName,
Selected: selected,
})
}
return r, nil
}

func GetAllOfficialTagRepos(orgID int64, isOwner bool) ([]TagsDetail, error) {
result := make([]TagsDetail, 0)
tags, err := GetAllOfficialTags()
if err != nil {
return nil, err
}
for _, tag := range tags {
repos, err := GetOfficialTagDetail(orgID, tag.ID)
if err != nil {
return nil, err
}
if len(repos) == 0 && !isOwner {
continue
}
result = append(result, TagsDetail{
TagId: tag.ID,
TagName: tag.Name,
TagLimit: tag.Limit,
RepoList: repos,
})
}
return result, nil
}

func GetOfficialTagDetail(orgID, tagId int64) ([]Repository, error) {
t := make([]Repository, 0)
const SQLCmd = "select t2.* from official_tag_repos t1 inner join repository t2 on t1.repo_id = t2.id where t1.org_id = ? and t1.tag_id=? order by t2.updated_unix desc"

if err := x.SQL(SQLCmd, orgID, tagId).Find(&t); err != nil {
return nil, err
}
return t, nil
}

func GetAllOfficialTags() ([]OfficialTag, error) {
//todo redis?
o := make([]OfficialTag, 0)
err := x.Where("status = ?", 0).OrderBy("updated_unix desc").Find(&o)
if err != nil {
log.Error("GetAllOfficialTags error,%v", err)
return nil, err
}
return o, nil
}

+ 5
- 2
models/repo_watch.go View File

@@ -280,13 +280,16 @@ func notifyWatchers(e Engine, actions ...*Action) error {
// NotifyWatchers creates batch of actions for every watcher.
func NotifyWatchers(actions ...*Action) error {

error := notifyWatchers(x, actions...)
producer(actions...)
return notifyWatchers(x, actions...)
return error
}

func producer(actions ...*Action) {
for _, action := range actions {
ActionChan <- action
if !action.IsPrivate{
ActionChan <- action
}
}
}



+ 134
- 53
models/user_business_analysis.go View File

@@ -10,10 +10,12 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
"xorm.io/xorm"
)

const (
Page_SIZE = 2000
PAGE_SIZE = 2000
BATCH_INSERT_SIZE = 50
)

type UserBusinessAnalysisAll struct {
@@ -163,14 +165,6 @@ func (ulist UserBusinessAnalysisList) Less(i, j int) bool {
return ulist[i].ID > ulist[j].ID
}

type UserBusinessAnalysisAllList []*UserBusinessAnalysisAll

func (ulist UserBusinessAnalysisAllList) Swap(i, j int) { ulist[i], ulist[j] = ulist[j], ulist[i] }
func (ulist UserBusinessAnalysisAllList) Len() int { return len(ulist) }
func (ulist UserBusinessAnalysisAllList) Less(i, j int) bool {
return ulist[i].ID > ulist[j].ID
}

func getLastCountDate() int64 {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
@@ -189,6 +183,29 @@ func getLastCountDate() int64 {
return pageStartTime.Unix()
}

func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, queryObj interface{}, userName string) ([]*UserBusinessAnalysisAll, int64) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
var cond = builder.NewCond()
if len(userName) > 0 {
cond = cond.And(
builder.Like{"name", userName},
)
}
allCount, err := statictisSess.Where(cond).Count(queryObj)
if err != nil {
log.Info("query error." + err.Error())
return nil, 0
}
log.Info("query return total:" + fmt.Sprint(allCount))
userBusinessAnalysisAllList := make([]*UserBusinessAnalysisAll, 0)
if err := statictisSess.Table(tableName).Where(cond).OrderBy("commit_count desc,id desc").Limit(pageSize, start).
Find(&userBusinessAnalysisAllList); err != nil {
return nil, 0
}
return userBusinessAnalysisAllList, allCount
}

func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusinessAnalysisAll, int64) {
log.Info("query startTime =" + fmt.Sprint(opts.StartTime) + " endTime=" + fmt.Sprint(opts.EndTime) + " isAll=" + fmt.Sprint(opts.IsAll))

@@ -202,9 +219,9 @@ func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusi
}
log.Info("query return total:" + fmt.Sprint(allCount))

pageSize := 1000
pageSize := PAGE_SIZE
totalPage := int(allCount) / pageSize
userBusinessAnalysisReturnList := UserBusinessAnalysisAllList{}
userBusinessAnalysisReturnList := make([]*UserBusinessAnalysisAll, 0)
for i := 0; i <= int(totalPage); i++ {
userBusinessAnalysisAllList := make([]*UserBusinessAnalysisAll, 0)
if err := statictisSess.Table("user_business_analysis_all").OrderBy("id desc").Limit(pageSize, i*pageSize).
@@ -217,7 +234,6 @@ func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusi
}
}

sort.Sort(userBusinessAnalysisReturnList)
log.Info("return size=" + fmt.Sprint(len(userBusinessAnalysisReturnList)))
return userBusinessAnalysisReturnList, allCount
}
@@ -337,28 +353,24 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus
return userBusinessAnalysisReturnList, count
}

func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats) {

func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats, tableName string, pageStartTime time.Time, pageEndTime time.Time) {
sess := x.NewSession()
defer sess.Close()

statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
log.Info("truncate all data from table: user_business_analysis_all")
statictisSess.Exec("TRUNCATE TABLE user_business_analysis_all")
log.Info("truncate all data from table: " + tableName)
statictisSess.Exec("TRUNCATE TABLE " + tableName)

currentTimeNow := time.Now()

startTime := currentTimeNow.AddDate(0, 0, -1)

pageStartTime := time.Date(2021, 11, 5, 0, 0, 0, 0, currentTimeNow.Location())
log.Info("pageStartTime:" + pageStartTime.Format("2006-01-02 15:04:05"))
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
log.Info("pageEndTime time:" + pageEndTime.Format("2006-01-02 15:04:05"))

start_unix := pageStartTime.Unix()
end_unix := pageEndTime.Unix()

currentTimeNow := time.Now()
startTime := currentTimeNow.AddDate(0, 0, -1)

CodeMergeCountMap := queryPullRequest(start_unix, end_unix)
CommitCountMap := queryCommitAction(start_unix, end_unix, 5)
IssueCountMap := queryCreateIssue(start_unix, end_unix)
@@ -385,12 +397,14 @@ func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap ma
}
var indexTotal int64
indexTotal = 0
insertCount := 0
dateRecordBatch := make([]UserBusinessAnalysisAll, 0)
for {
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userList := make([]*User, 0)
sess.Find(&userList)
for i, userRecord := range userList {
log.Info("insert all static, i=" + fmt.Sprint(i) + " userName=" + userRecord.Name)
for _, userRecord := range userList {
var dateRecordAll UserBusinessAnalysisAll
dateRecordAll.ID = userRecord.ID
dateRecordAll.Email = userRecord.Email
@@ -484,18 +498,85 @@ func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap ma
}

dateRecordAll.CommitModelCount = 0
_, err = statictisSess.Insert(&dateRecordAll)
if err != nil {
log.Info("insert all data failed." + err.Error())

dateRecordBatch = append(dateRecordBatch, dateRecordAll)
if len(dateRecordBatch) >= BATCH_INSERT_SIZE {
insertTable(dateRecordBatch, tableName, statictisSess)
insertCount += BATCH_INSERT_SIZE
if err != nil {
log.Info("insert all data failed." + err.Error())
}
dateRecordBatch = make([]UserBusinessAnalysisAll, 0)
}
}
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
if len(dateRecordBatch) > 0 {
insertTable(dateRecordBatch, tableName, statictisSess)
insertCount += len(dateRecordBatch)
if err != nil {
log.Info("insert all data failed." + err.Error())
}
}

log.Info("refresh data finished.tableName=" + tableName + " total record:" + fmt.Sprint(insertCount))
}

func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, statictisSess *xorm.Session) {

insertBatchSql := "INSERT INTO public." + tableName +
"(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " +
"commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date) " +
"VALUES"

for i, record := range dateRecords {
insertBatchSql += "(" + fmt.Sprint(record.ID) + ", " + fmt.Sprint(record.CountDate) + ", " + fmt.Sprint(record.CodeMergeCount) + ", " + fmt.Sprint(record.CommitCount) +
", " + fmt.Sprint(record.IssueCount) + ", " + fmt.Sprint(record.CommentCount) + ", " + fmt.Sprint(record.FocusRepoCount) + ", " + fmt.Sprint(record.StarRepoCount) +
", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) +
", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) +
", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "')"
if i < (len(dateRecords) - 1) {
insertBatchSql += ","
}
}

statictisSess.Exec(insertBatchSql)
}

func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats) {
currentTimeNow := time.Now()
pageStartTime := time.Date(2021, 11, 5, 0, 0, 0, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_all", pageStartTime, pageEndTime)
log.Info("refresh all data finished.")

pageStartTime = time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_year", pageStartTime, pageEndTime)

thisMonth := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_month", thisMonth, pageEndTime)

offset := int(time.Monday - currentTimeNow.Weekday())
if offset > 0 {
offset = -6
}
pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_week", pageStartTime, pageEndTime)

pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_last30_day", pageStartTime, pageEndTime)

pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_yesterday", pageStartTime, pageEndTime)

pageStartTime = thisMonth.AddDate(0, -1, 0)
pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_last_month", pageStartTime, pageEndTime)

}

func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, endTime time.Time, isReCount bool) error {
@@ -550,7 +631,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
var indexTotal int64
indexTotal = 0
for {
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userList := make([]*User, 0)
sess.Find(&userList)

@@ -660,7 +741,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
}
}

indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -700,7 +781,7 @@ func querySolveIssue(start_unix int64, end_unix int64) map[int64]int {
issueAssigneesList := make([]*IssueAssignees, 0)
sess.Select("issue_assignees.*").Table("issue_assignees").
Join("inner", "issue", "issue.id=issue_assignees.issue_id").
Where(cond).OrderBy("issue_assignees.id asc").Limit(Page_SIZE, int(indexTotal))
Where(cond).OrderBy("issue_assignees.id asc").Limit(PAGE_SIZE, int(indexTotal))

sess.Find(&issueAssigneesList)

@@ -712,7 +793,7 @@ func querySolveIssue(start_unix int64, end_unix int64) map[int64]int {
resultMap[issueAssigneesRecord.AssigneeID] += 1
}
}
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -735,7 +816,7 @@ func queryPullRequest(start_unix int64, end_unix int64) map[int64]int {
indexTotal = 0
for {
issueList := make([]*Issue, 0)
sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).OrderBy("issue.id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).OrderBy("issue.id asc").Limit(PAGE_SIZE, int(indexTotal))
sess.Find(&issueList)
log.Info("query issue(PR) size=" + fmt.Sprint(len(issueList)))
for _, issueRecord := range issueList {
@@ -745,7 +826,7 @@ func queryPullRequest(start_unix int64, end_unix int64) map[int64]int {
resultMap[issueRecord.PosterID] += 1
}
}
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -768,7 +849,7 @@ func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[i
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
actionList := make([]*Action, 0)
sess.Find(&actionList)

@@ -781,7 +862,7 @@ func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[i
}
}

indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -805,7 +886,7 @@ func queryCreateIssue(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,poster_id").Table("issue").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,poster_id").Table("issue").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
issueList := make([]*Issue, 0)
sess.Find(&issueList)
log.Info("query issue size=" + fmt.Sprint(len(issueList)))
@@ -816,7 +897,7 @@ func queryCreateIssue(start_unix int64, end_unix int64) map[int64]int {
resultMap[issueRecord.PosterID] += 1
}
}
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -839,7 +920,7 @@ func queryComment(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,type,poster_id").Table("comment").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,type,poster_id").Table("comment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
commentList := make([]*Comment, 0)
sess.Find(&commentList)
log.Info("query Comment size=" + fmt.Sprint(len(commentList)))
@@ -850,7 +931,7 @@ func queryComment(start_unix int64, end_unix int64) map[int64]int {
resultMap[commentRecord.PosterID] += 1
}
}
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -875,7 +956,7 @@ func queryWatch(start_unix int64, end_unix int64) map[int64]int {
indexTotal = 0
for {
watchList := make([]*Watch, 0)
sess.Select("id,user_id,repo_id").Table("watch").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,repo_id").Table("watch").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
sess.Find(&watchList)

log.Info("query Watch size=" + fmt.Sprint(len(watchList)))
@@ -887,7 +968,7 @@ func queryWatch(start_unix int64, end_unix int64) map[int64]int {
}
}

indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -913,7 +994,7 @@ func queryStar(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,uid,repo_id").Table("star").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,uid,repo_id").Table("star").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
starList := make([]*Star, 0)
sess.Find(&starList)

@@ -926,7 +1007,7 @@ func queryStar(start_unix int64, end_unix int64) map[int64]int {
}
}

indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -949,7 +1030,7 @@ func queryFollow(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,user_id,follow_id").Table("follow").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,follow_id").Table("follow").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
followList := make([]*Follow, 0)
sess.Find(&followList)

@@ -962,7 +1043,7 @@ func queryFollow(start_unix int64, end_unix int64) map[int64]int {
}
}

indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -985,7 +1066,7 @@ func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,uploader_id,size").Table("attachment").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,uploader_id,size").Table("attachment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
attachmentList := make([]*Attachment, 0)
sess.Find(&attachmentList)

@@ -998,7 +1079,7 @@ func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {
}
}

indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -1021,7 +1102,7 @@ func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,owner_id,name").Table("repository").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Select("id,owner_id,name").Table("repository").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
repoList := make([]*Repository, 0)
sess.Find(&repoList)
log.Info("query Repository size=" + fmt.Sprint(len(repoList)))
@@ -1032,7 +1113,7 @@ func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int {
resultMap[repoRecord.OwnerID] += 1
}
}
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
@@ -1111,7 +1192,7 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
statictisSess.Select("id,u_id").Table("user_login_log").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
statictisSess.Select("id,u_id").Table("user_login_log").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userLoginLogList := make([]*UserLoginLog, 0)
statictisSess.Find(&userLoginLogList)
log.Info("query user login size=" + fmt.Sprint(len(userLoginLogList)))
@@ -1122,7 +1203,7 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int {
resultMap[loginRecord.UId] += 1
}
}
indexTotal += Page_SIZE
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}


+ 267
- 0
models/user_business_struct.go View File

@@ -0,0 +1,267 @@
package models

import "code.gitea.io/gitea/modules/timeutil"

type UserBusinessAnalysisCurrentYear struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisLast30Day struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisLastMonth struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisCurrentMonth struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisCurrentWeek struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

type UserBusinessAnalysisYesterday struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
//action :ActionCommitRepo
CommitCount int `xorm:"NOT NULL DEFAULT 0"`
//issue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`
//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`
//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`
// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`
//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`
//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`
//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`
//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`
//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`
//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`
//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`
//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`
//user
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"`
}

+ 4
- 0
modules/auth/org.go View File

@@ -70,3 +70,7 @@ type CreateTeamForm struct {
func (f *CreateTeamForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

type SubmitReposOfTagForm struct {
RepoList []int64
}

+ 148
- 12
modules/cloudbrain/cloudbrain.go View File

@@ -1,6 +1,8 @@
package cloudbrain

import (
"code.gitea.io/gitea/modules/storage"
"encoding/json"
"errors"
"strconv"

@@ -80,7 +82,7 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) {
var jobID = ctx.Params(":jobid")

job, err := models.GetCloudbrainByJobID(jobID)
ctx.Cloudbrain = job
if !isAdminOrOwnerOrJobCreater(ctx, job, err) {

ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -92,6 +94,7 @@ func AdminOrJobCreaterRight(ctx *context.Context) {

var jobID = ctx.Params(":jobid")
job, err := models.GetCloudbrainByJobID(jobID)
ctx.Cloudbrain = job
if !isAdminOrJobCreater(ctx, job, err) {

ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -107,6 +110,9 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
uuid

var resourceSpec *models.ResourceSpec
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec {
if resourceSpecId == spec.Id {
resourceSpec = spec
@@ -185,25 +191,29 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
},
})
if err != nil {
log.Error("CreateJob failed:", err.Error())
log.Error("CreateJob failed:", err.Error(), ctx.Data["MsgID"])
return err
}
if jobResult.Code != Success {
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg)
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg, ctx.Data["MsgID"])
return errors.New(jobResult.Msg)
}

var jobID = jobResult.Payload["jobId"].(string)
err = models.CreateCloudbrain(&models.Cloudbrain{
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobID,
JobName: jobName,
SubTaskName: SubTaskName,
JobType: jobType,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobID,
JobName: jobName,
SubTaskName: SubTaskName,
JobType: jobType,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
Image: image,
GpuQueue: gpuQueue,
ResourceSpecId: resourceSpecId,
ComputeResource: models.GPUResource,
})

if err != nil {
@@ -212,3 +222,129 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,

return nil
}

func RestartTask(ctx *context.Context, task *models.Cloudbrain, newJobID *string) error {
dataActualPath := setting.Attachment.Minio.RealPath +
setting.Attachment.Minio.Bucket + "/" +
setting.Attachment.Minio.BasePath +
models.AttachmentRelativePath(task.Uuid) +
task.Uuid
jobName := task.JobName

var resourceSpec *models.ResourceSpec
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec {
if task.ResourceSpecId == spec.Id {
resourceSpec = spec
}
}

if resourceSpec == nil {
log.Error("no such resourceSpecId(%d)", task.ResourceSpecId, ctx.Data["MsgID"])
return errors.New("no such resourceSpec")
}

jobResult, err := CreateJob(jobName, models.CreateJobParams{
JobName: jobName,
RetryCount: 1,
GpuType: task.GpuQueue,
Image: task.Image,
TaskRoles: []models.TaskRole{
{
Name: SubTaskName,
TaskNumber: 1,
MinSucceededTaskCount: 1,
MinFailedTaskCount: 1,
CPUNumber: resourceSpec.CpuNum,
GPUNumber: resourceSpec.GpuNum,
MemoryMB: resourceSpec.MemMiB,
ShmMB: resourceSpec.ShareMemMiB,
Command: Command,
NeedIBDevice: false,
IsMainRole: false,
UseNNI: false,
},
},
Volumes: []models.Volume{
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, CodeMountPath + "/"),
MountPath: CodeMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: dataActualPath,
MountPath: DataSetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, ModelMountPath + "/"),
MountPath: ModelMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BenchMarkMountPath + "/"),
MountPath: BenchMarkMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, Snn4imagenetMountPath + "/"),
MountPath: Snn4imagenetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BrainScoreMountPath + "/"),
MountPath: BrainScoreMountPath,
ReadOnly: true,
},
},
},
})
if err != nil {
log.Error("CreateJob failed:%v", err.Error(), ctx.Data["MsgID"])
return err
}
if jobResult.Code != Success {
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg, ctx.Data["MsgID"])
return errors.New(jobResult.Msg)
}

var jobID = jobResult.Payload["jobId"].(string)
newTask := &models.Cloudbrain{
Status: string(models.JobWaiting),
UserID: task.UserID,
RepoID: task.RepoID,
JobID: jobID,
JobName: task.JobName,
SubTaskName: task.SubTaskName,
JobType: task.JobType,
Type: task.Type,
Uuid: task.Uuid,
Image: task.Image,
GpuQueue: task.GpuQueue,
ResourceSpecId: task.ResourceSpecId,
ComputeResource: task.ComputeResource,
}

err = models.RestartCloudbrain(task, newTask)
if err != nil {
log.Error("RestartCloudbrain(%s) failed:%v", jobName, err.Error(), ctx.Data["MsgID"])
return err
}

*newJobID = jobID

return nil
}

+ 6
- 0
modules/context/context.go View File

@@ -6,6 +6,7 @@
package context

import (
"code.gitea.io/gitea/routers/notice"
"html"
"html/template"
"io"
@@ -46,6 +47,7 @@ type Context struct {

Repo *Repository
Org *Organization
Cloudbrain *models.Cloudbrain
}

// IsUserSiteAdmin returns true if current user is a site admin
@@ -345,6 +347,10 @@ func Contexter() macaron.Handler {
ctx.Data["EnableSwagger"] = setting.API.EnableSwagger
ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn

notice, _ := notice.GetNewestNotice()
if notice != nil {
ctx.Data["notice"] = *notice
}
c.Map(ctx)
}
}

+ 8
- 0
modules/context/repo.go View File

@@ -11,6 +11,7 @@ import (
"net/url"
"path"
"strings"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cache"
@@ -517,6 +518,7 @@ func RepoAssignment() macaron.Handler {
return
}

startTime := time.Now()
tags, err := ctx.Repo.GitRepo.GetTags()
if err != nil {
ctx.ServerError("GetTags", err)
@@ -524,11 +526,17 @@ func RepoAssignment() macaron.Handler {
}
ctx.Data["Tags"] = tags

duration := time.Since(startTime)
log.Info("GetTags cost: %v seconds", duration.Seconds())
brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0)
if err != nil {
ctx.ServerError("GetBranches", err)
return
}

duration = time.Since(startTime)
log.Info("GetBranches cost: %v seconds", duration.Seconds())

ctx.Data["Branches"] = brs
ctx.Data["BranchesCount"] = len(brs)



+ 13
- 16
modules/modelarts/modelarts.go View File

@@ -48,12 +48,8 @@ const (
PerPage = 10
IsLatestVersion = "1"
NotLatestVersion = "0"
// ComputeResource = "NPU"
NPUResource = "NPU"
GPUResource = "CPU/GPU"
AllResource = "all"
DebugType = -1
VersionCount = 1
DebugType = -1
VersionCount = 1

SortByCreateTime = "create_time"
ConfigTypeCustom = "custom"
@@ -215,14 +211,15 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin
}
err = models.CreateCloudbrain(&models.Cloudbrain{

Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCloudBrainTwo,
Uuid: uuid,
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCloudBrainTwo,
Uuid: uuid,
ComputeResource: models.NPUResource,
})

if err != nil {
@@ -277,7 +274,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
DatasetName: attach.Name,
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
ComputeResource: NPUResource,
ComputeResource: models.NPUResource,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,
@@ -360,7 +357,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
PreVersionName: req.PreVersionName,
ComputeResource: NPUResource,
ComputeResource: models.NPUResource,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,


+ 3
- 3
modules/modelarts/resty.go View File

@@ -174,7 +174,7 @@ sendjob:
return &result, nil
}

func StopJob(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
func ManageNotebook(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
checkSetting()
client := getRestyClient()
var result models.NotebookActionResult
@@ -207,8 +207,8 @@ sendjob:
}

if len(response.ErrorCode) != 0 {
log.Error("StopJob failed(%s): %s", response.ErrorCode, response.ErrorMsg)
return &result, fmt.Errorf("StopJob failed(%s): %s", response.ErrorCode, response.ErrorMsg)
log.Error("ManageNotebook failed(%s): %s", response.ErrorCode, response.ErrorMsg)
return &result, fmt.Errorf("ManageNotebook failed(%s): %s", response.ErrorCode, response.ErrorMsg)
}

return &result, nil


+ 10
- 2
modules/repository/elk_pagedata.go View File

@@ -21,7 +21,8 @@ type Fields struct {
Format string `json:"format"`
}
type MatchPhrase struct {
Message string `json:"message"`
Message string `json:"message,omitempty"`
TagName string `json:"tagName.keyword,omitempty"`
}
type Should struct {
MatchPhrase MatchPhrase `json:"match_phrase"`
@@ -144,7 +145,7 @@ func ProjectViewInit(User string, Project string, Gte string, Lte string) (proje
inputStruct.Batch[0].Request.Params.Body.Fields = make([]Fields, 1)
inputStruct.Batch[0].Request.Params.Body.Fields[0].Field = setting.TimeField
inputStruct.Batch[0].Request.Params.Body.Fields[0].Format = setting.ElkTimeFormat
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 3)
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 4)
//限定查询时间
var timeRange Range
timeRange.Timestamptest.Gte = Gte
@@ -159,6 +160,13 @@ func ProjectViewInit(User string, Project string, Gte string, Lte string) (proje
var projectName FilterMatchPhrase
projectName.ProjectName = Project
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[2].FilterMatchPhrase = &projectName
//限定页面
var bool Bool
bool.Should = make([]Should, len(setting.PROJECT_LIMIT_PAGES))
for i, pageName := range setting.PROJECT_LIMIT_PAGES {
bool.Should[i].MatchPhrase.TagName = pageName
}
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[3].Bool = &bool
return inputStruct
}



+ 24
- 8
modules/setting/setting.go View File

@@ -435,8 +435,14 @@ var (

//home page
RecommentRepoAddr string

ESSearchURL string
ESSearchURL string
//notice config
UserNameOfNoticeRepo string
RepoNameOfNoticeRepo string
RefNameOfNoticeRepo string
TreePathOfNoticeRepo string
CacheTimeOutSecond int
CacheOn bool

//labelsystem config
LabelTaskName string
@@ -510,12 +516,13 @@ var (
TrainJobFLAVORINFOS string

//elk config
ElkUrl string
ElkUser string
ElkPassword string
Index string
TimeField string
ElkTimeFormat string
ElkUrl string
ElkUser string
ElkPassword string
Index string
TimeField string
ElkTimeFormat string
PROJECT_LIMIT_PAGES []string

//nginx proxy
PROXYURL string
@@ -1238,6 +1245,14 @@ func NewContext() {
RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/")
ESSearchURL = sec.Key("ESSearchURL").MustString("http://192.168.207.94:9200")

sec = Cfg.Section("notice")
UserNameOfNoticeRepo = sec.Key("USER_NAME").MustString("OpenIOSSG")
RepoNameOfNoticeRepo = sec.Key("REPO_NAME").MustString("promote")
RefNameOfNoticeRepo = sec.Key("REF_NAME").MustString("master")
TreePathOfNoticeRepo = sec.Key("TREE_PATH").MustString("notice.json")
CacheTimeOutSecond = sec.Key("CACHE_TIME_OUT_SECOND").MustInt(60)
CacheOn = sec.Key("CACHE_ON").MustBool(true)

sec = Cfg.Section("cloudbrain")
CBAuthUser = sec.Key("USER").MustString("")
CBAuthPassword = sec.Key("PWD").MustString("")
@@ -1311,6 +1326,7 @@ func NewContext() {
Index = sec.Key("INDEX").MustString("")
TimeField = sec.Key("TIMEFIELD").MustString(" @timestamptest")
ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time")
PROJECT_LIMIT_PAGES = strings.Split(sec.Key("project_limit_pages").MustString(""), ",")

SetRadarMapConfig()



+ 4
- 0
modules/storage/local.go View File

@@ -80,3 +80,7 @@ func (l *LocalStorage) HasObject(path string) (bool, error) {
func (l *LocalStorage) UploadObject(fileName, filePath string) error {
return nil
}

func (l *LocalStorage) DeleteDir(dir string) error {
return nil
}

+ 28
- 0
modules/storage/minio.go View File

@@ -11,6 +11,9 @@ import (
"strings"
"time"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"

"github.com/minio/minio-go"
)

@@ -76,6 +79,27 @@ func (m *MinioStorage) Delete(path string) error {
return m.client.RemoveObject(m.bucket, m.buildMinioPath(path))
}

// Delete delete a file
func (m *MinioStorage) DeleteDir(dir string) error {
objectsCh := make(chan string)

// Send object names that are needed to be removed to objectsCh
go func() {
defer close(objectsCh)
// List all objects from a bucket-name with a matching prefix.
for object := range m.client.ListObjects(m.bucket, dir, true, nil) {
if object.Err != nil {
log.Error("ListObjects failed:%v", object.Err)
}
objectsCh <- object.Key
}
}()

m.client.RemoveObjects(m.bucket, objectsCh)

return nil
}

//Get Presigned URL for get object
func (m *MinioStorage) PresignedGetURL(path string, fileName string) (string, error) {
// Set request parameters for content-disposition.
@@ -128,3 +152,7 @@ func (m *MinioStorage) UploadObject(fileName, filePath string) error {
_, err := m.client.FPutObject(m.bucket, fileName, filePath, minio.PutObjectOptions{})
return err
}

func GetMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

+ 1
- 0
modules/storage/storage.go View File

@@ -23,6 +23,7 @@ type ObjectStorage interface {
Save(path string, r io.Reader) (int64, error)
Open(path string) (io.ReadCloser, error)
Delete(path string) error
DeleteDir(dir string) error
PresignedGetURL(path string, fileName string) (string, error)
PresignedPutURL(path string) (string, error)
HasObject(path string) (bool, error)


+ 10
- 0
modules/util/util.go View File

@@ -6,6 +6,7 @@ package util

import (
"bytes"
"strconv"
"strings"
)

@@ -100,3 +101,12 @@ func NormalizeEOL(input []byte) []byte {
}
return tmp[:pos]
}

func AddZero(t int64) (m string) {
if t < 10 {
m = "0" + strconv.FormatInt(t, 10)
return m
} else {
return strconv.FormatInt(t, 10)
}
}

+ 46
- 1
options/locale/locale_en-US.ini View File

@@ -220,8 +220,40 @@ show_only_public = Showing only public
issues.in_your_repos = In your repositories
contributors = Contributors

page_title=Explore Better AI
page_small_title=OpenI AI development cooperation platform
page_description=The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation
page_use=Use Now
page_only_dynamic=Show only open source project dynamics
page_recommend_org=Recommended organization
page_recommend_org_desc=These excellent organizations are using Qizhi AI to develop collaboration platforms; Your organization also wants to show here,
page_recommend_org_commit=Click here to submit
page_recommend_org_more=More organizations
page_recommend_repo=Recommended projects
page_recommend_repo_desc=Excellent AI project recommendation; Your project also wants to show here,
page_recommend_repo_commit=Click here to submit
page_recommend_repo_go=. Click here
page_recommend_repo_more=Project Square
page_dev_env=Collaborative development environment
page_dev_env_desc=The biggest difference between Qizhi AI collaborative development platform and traditional git platform is that it provides a collaborative development environment for AI development
page_dev_env_desc_title=Unified management of development elements
page_dev_env_desc_desc=The platform provides four elements of AI development: unified management of model code, data set, model and execution environment
page_dev_env_desc1_title=Data collaboration and sharing
page_dev_env_desc1_desc=By uploading data sets in the project, many project members cooperate to complete data preprocessing; You can also establish a better model with community developers by setting the data as a public dataset
page_dev_env_desc2_title=Model management and sharing
page_dev_env_desc2_desc=Associate the model with the code version, adjust the model in different ways based on the code history version, and save the results; The trained model can be open and shared, so that more people can use the model to test and give feedback
page_dev_env_desc3_title=One configuration, multiple use
page_dev_env_desc3_desc=Provide execution environment sharing, one-time configuration and multiple use, reduce the threshold of model development, and avoid spending repeated time configuring complex environments
page_dev_yunlao=PengCheng Cloudbrain open source collaboration
page_dev_yunlao_desc1=The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks
page_dev_yunlao_desc2=Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and shengteng processors
page_dev_yunlao_desc3=Developers can freely choose the corresponding computing resources according to the use requirements, and can test the adaptability, performance and stability of the model in different hardware environments
page_dev_yunlao_desc4=If your model needs more computing resources, you can also apply separately
page_dev_yunlao_apply=Separate apply

[explore]
repos = Repositories
select_repos = Select the project
users = Users
organizations = Organizations
images = CloudImages
@@ -234,6 +266,8 @@ org_no_results = No matching organizations found.
code_no_results = No source code matching your search term found.
code_search_results = Search results for '%s'
code_last_indexed_at = Last indexed %s
save=save
cancel=cancel

[auth]
create_new_account = Register Account
@@ -421,7 +455,13 @@ static.openiindex=OpenI Index
static.registdate=Regist Date
static.countdate=Count Date
static.all=All

static.public.user_business_analysis_current_month=Current_Month
static.public.user_business_analysis_current_week=Current_Week
static.public.user_business_analysis_current_year=Current_Year
static.public.user_business_analysis_last30_day=Last_30_day
static.public.user_business_analysis_last_month=Last_Month
static.public.user_business_analysis_yesterday=Yesterday
static.public.user_business_analysis_all=All
[settings]
profile = Profile
account = Account
@@ -841,6 +881,7 @@ modelarts.current_version=Current version
modelarts.parent_version=Parent Version
modelarts.run_version=Run Version
modelarts.train_job.compute_node=Compute Node
modelarts.create_model = Create Model


modelarts.train_job.basic_info=Basic Info
@@ -900,6 +941,8 @@ model.manage.F1 = F1
model.manage.Precision = Precision
model.manage.Recall = Recall
model.manage.sava_model = Sava Model
model.manage.model_manage = ModelManage
model.manage.model_accuracy = Model Accuracy

template.items = Template Items
template.git_content = Git Content (Default Branch)
@@ -2654,3 +2697,5 @@ foot.member_news = Member news
foot.industry_advisory = Industry Advisory
foot.help = help
foot.copyright= Copyright: New Generation Artificial Intelligence Open Source Open Platform (OpenI)
Platform_Tutorial=Platform Tutorial
foot.advice_feedback=advice feedback

+ 48
- 1
options/locale/locale_zh-CN.ini View File

@@ -222,8 +222,40 @@ issues.in_your_repos=属于该用户项目的

contributors=贡献者

page_title=探索更好的AI
page_small_title=启智AI开发协作平台
page_description=面向AI领域的一站式协同开发环境,提供集代码开发、数据管理、模型调试、推理和评测为一体的AI开发流水线
page_use=立即使用
page_only_dynamic=仅展示开源项目动态
page_recommend_org=推荐组织
page_recommend_org_desc=这些优秀的组织正在使用启智AI开发协作平台;你的组织也想展示到这里,
page_recommend_org_commit=点此提交
page_recommend_org_more=更多组织
page_recommend_repo=推荐项目
page_recommend_repo_desc=优秀的AI项目推荐;你的项目也想展示到这里,
page_recommend_repo_commit=点此提交
page_recommend_repo_go=。进入
page_recommend_repo_more=项目广场
page_dev_env=协同开发环境
page_dev_env_desc=启智AI协作开发平台与传统git平台最大的不同就在于提供了面向AI开发的协同开发环境
page_dev_env_desc_title=开发要素统一管理
page_dev_env_desc_desc=平台提供了AI开发四大要素:模型代码、数据集、模型和执行环境的统一管理
page_dev_env_desc1_title=数据协同与共享
page_dev_env_desc1_desc=通过在项目中上传数据集,项目成员多人协作完成数据预处理;也可以通过将数据设置为公有数据集,与社区开发者共同建立更好的模型
page_dev_env_desc2_title=模型管理与共享
page_dev_env_desc2_desc=将模型与代码版本建立关联,可以基于代码历史版本,使用不同的方式调整模型,并将结果保存下来;训练好的模型可以开放共享,让更多人的使用模型测试并提出反馈
page_dev_env_desc3_title=一次配置,多次使用
page_dev_env_desc3_desc=提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境
page_dev_yunlao=鹏城云脑开源协同
page_dev_yunlao_desc1=平台已经与鹏城云脑打通,可以利用鹏城云脑的丰富算力资源,完成AI开发任务
page_dev_yunlao_desc2=鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 的GPU服务器和搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成
page_dev_yunlao_desc3=开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等
page_dev_yunlao_desc4=如果您的模型需要更多的计算资源,也可以单独申请
page_dev_yunlao_apply=单独申请

[explore]
repos=项目
select_repos=精选项目
users=用户
organizations=组织
images = 云脑镜像
@@ -238,6 +270,8 @@ org_no_results=未找到匹配的组织。
code_no_results=未找到与搜索字词匹配的源代码。
code_search_results=“%s” 的搜索结果是
code_last_indexed_at=最后索引于 %s
save=保存
cancel=取消

[auth]
create_new_account=注册帐号
@@ -425,6 +459,13 @@ static.openiindex=OpenI指数
static.registdate=用户注册时间
static.countdate=系统统计时间
static.all=所有
static.public.user_business_analysis_current_month=本月
static.public.user_business_analysis_current_week=本周
static.public.user_business_analysis_current_year=今年
static.public.user_business_analysis_last30_day=近30天
static.public.user_business_analysis_last_month=上月
static.public.user_business_analysis_yesterday=昨天
static.public.user_business_analysis_all=所有
[settings]
profile=个人信息
account=账号
@@ -787,6 +828,7 @@ model_noright=无权限操作
model_rename=模型名称重复,请修改模型名称

debug=调试
debug_again=再次调试
stop=停止
delete=删除
model_download=模型下载
@@ -845,6 +887,7 @@ modelarts.modify=修改
modelarts.current_version=当前版本
modelarts.parent_version=父版本
modelarts.run_version=运行版本
modelarts.create_model=创建模型



@@ -909,6 +952,8 @@ model.manage.F1 = F1值
model.manage.Precision = 精确率
model.manage.Recall = 召回率
model.manage.sava_model = 保存模型
model.manage.model_manage = 模型管理
model.manage.model_accuracy = 模型精度

template.items=模板选项
template.git_content=Git数据(默认分支)
@@ -1424,7 +1469,7 @@ milestones.open_tab=%d 开启中
milestones.close_tab=%d 已关闭
milestones.closed=于 %s关闭
milestones.no_due_date=暂无截止日期
milestones.open=开启
milestones.open=开启
milestones.close=关闭
milestones.new_subheader=里程碑组织任务,合并请求和跟踪进度。
milestones.completeness=%d%% 完成
@@ -2661,3 +2706,5 @@ foot.member_news=成员动态
foot.industry_advisory=行业资讯
foot.help=帮助
foot.copyright= 版权所有:新一代人工智能开源开放平台(OpenI)
Platform_Tutorial=新手指引
foot.advice_feedback = 意见反馈

+ 5
- 0
package-lock.json View File

@@ -11655,6 +11655,11 @@
"autolinker": "~0.28.0"
}
},
"remixicon": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/remixicon/-/remixicon-2.5.0.tgz",
"integrity": "sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww=="
},
"remove-bom-buffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",


+ 1
- 0
package.json View File

@@ -42,6 +42,7 @@
"postcss-preset-env": "6.7.0",
"postcss-safe-parser": "4.0.2",
"qs": "6.9.4",
"remixicon": "2.5.0",
"spark-md5": "3.0.1",
"svg-sprite-loader": "5.0.0",
"svgo": "1.3.2",


+ 442
- 0
public/home/home.js View File

@@ -0,0 +1,442 @@

var token;
if(isEmpty(token)){
var meta = $("meta[name=_uid]");
if(!isEmpty(meta)){
token = meta.attr("content");
console.log("token is uid:" + token);
}
}

var swiperNewMessage = new Swiper(".newslist", {
direction: "vertical",
slidesPerView: 10,
loop: true,
autoplay: {
delay: 2500,
disableOnInteraction: false,
},
});
var swiperRepo = new Swiper(".homepro-list", {
slidesPerView: 3,
slidesPerColumn: 2,
slidesPerColumnFill:'row',
spaceBetween: 30,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
autoplay: {
delay: 2500,
disableOnInteraction: false,
},
});

var output = document.getElementById("newmessage");
var socket = new WebSocket("ws://" + document.location.host + "/action/notification");

socket.onopen = function () {
console.log("message has connected.");
};

var messageQueue = [];
var maxSize = 20;
var html =document.documentElement;
var lang = html.attributes["lang"]
var isZh = true;
if(lang != null && lang.nodeValue =="en-US" ){
console.log("the language is " + lang.nodeValue);
isZh=false;
}else{
console.log("default lang=zh");
}

socket.onmessage = function (e) {
var data =JSON.parse(e.data)
console.log("recevie data=" + e.data)
var html = "";
if (data != null){
console.log("queue length=" + messageQueue.length);
if(messageQueue.length > maxSize){
delete messageQueue[0];
}else{
messageQueue.push(data);
}
var currentTime = new Date().getTime();
for(var i = 0; i < messageQueue.length; i++){
var record = messageQueue[i];
var recordPrefix = getMsg(record);
var actionName = getAction(record.OpType,isZh);
if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){
html += recordPrefix + actionName;
html += " <a href=\"" + getIssueLink(record) + "\" rel=\"nofollow\">" + getIssueText(record) + "</a>"
}
else if(record.OpType == "7" || record.OpType == "11" || record.OpType == "14" || record.OpType == "15" || record.OpType == "22"
|| record.OpType == "23"){
html += recordPrefix + actionName;
html += " <a href=\"" + getPRLink(record) + "\" rel=\"nofollow\">" + getPRText(record) + "</a>"
}
else if(record.OpType == "1"){
html += recordPrefix + actionName;
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
}
else if(record.OpType == "9" || record.OpType == "5"){
branch = "<a href=\"" + getRepoLink(record) + "/src/branch/" + record.RefName + "\" rel=\"nofollow\">" + record.RefName + "</a>"
actionName = actionName.replace("{branch}",branch);
html += recordPrefix + actionName;
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
}else if(record.OpType == "17"){
actionName = actionName.replace("{deleteBranchName}",record.RefName);
var repoLink = "<a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
actionName = actionName.replace("{repoName}",repoLink);
html += recordPrefix + actionName;
}
else if(record.OpType == "2"){
actionName = actionName.replace("{oldRepoName}",record.Content);
html += recordPrefix + actionName;
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepoLink(record) + "</a>"
}
else{
continue;
}

if(record.Repo != null){
var time = getTime(record.CreatedUnix,currentTime);
html += " " + time;
}
html += "</div>";
html += "</div>";
}
/*
<div class="swiper-slide item">
<img class="ui avatar image" src="/user/avatar/zhoupzh/-1" alt="">
<div class="middle aligned content">
<a href="/zhoupzh" title="">zhoupzh</a> 合并了合并请求 <a href="/OpenI/aiforge/pulls/1168" rel="nofollow">OpenI/aiforge#1168</a><span class="time-since">22 分钟前</span>
</div>
</div>
*/

}
console.log("html=" + html)
output.innerHTML = html;
swiperNewMessage.updateSlides();
swiperNewMessage.updateProgress();
};

function getMsg(record){
var html ="";
html += "<div class=\"swiper-slide item\">";
html += " <img class=\"ui avatar image\" src=\"/user/avatar/" + record.ActUser.Name + "/-1\" alt=\"\">"
html += " <div class=\"middle aligned content nowrap\">"
html += " <a href=\"/" + record.ActUser.Name + "\" title=\"\">" + record.ActUser.Name + "</a>"
return html;
}

function getRepoLink(record){
return "/" + record.Repo.OwnerName + "/" + record.Repo.Name;
}
function getRepoLink(record){
return record.Repo.OwnerName + "/" + record.Repo.Name;
}

function getTime(UpdatedUnix,currentTime){
UpdatedUnix = UpdatedUnix;
currentTime = currentTime / 1000;
var timeEscSecond = currentTime - UpdatedUnix;
if( timeEscSecond < 0){
timeEscSecond = 1;
}
console.log("currentTime=" + currentTime + " updateUnix=" + UpdatedUnix);
var hours= Math.floor(timeEscSecond / 3600);
//计算相差分钟数
var leave2 = Math.floor(timeEscSecond % (3600)); //计算小时数后剩余的秒数
var minutes= Math.floor(leave2 / 60);//计算相差分钟数

var leave3=Math.floor(leave2 % 60); //计算分钟数后剩余的秒数
var seconds= leave3;

if(hours == 0 && minutes == 0){
return seconds + getRepoOrOrg(6,isZh);
}else{
if(hours > 0){
return hours + getRepoOrOrg(4,isZh);
}else{
return minutes + getRepoOrOrg(5,isZh);
}
}
}

function getPRLink(record){
return "/" + record.Repo.OwnerName + "/" + record.Repo.Name + "/pulls/" + getIssueId(record);
}
function getPRText(record){
return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record);
}

function getIssueLink(record){
return "/" + record.Repo.OwnerName + "/" + record.Repo.Name + "/issues/" + getIssueId(record);
}

function getIssueId(record){
var Id = "1";
if(!isEmpty(record.Comment) && !isEmpty(record.Comment.Issue)){
Id = record.Comment.Issue.Index;
}else{
if(!isEmpty(record.Content)){
var content = record.Content;
var index = content.indexOf("|");
if(index != -1){
Id = content.substring(0,index);
}
}
}
return Id;
}

function getIssueText(record){
return record.Repo.OwnerName + "/" + record.Repo.Name + "#" + getIssueId(record);
}

/*
ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2
ActionStarRepo // 3
ActionWatchRepo // 4
ActionCommitRepo // 5
ActionCreateIssue // 6
ActionCreatePullRequest // 7
ActionTransferRepo // 8
ActionPushTag // 9
ActionCommentIssue // 10
ActionMergePullRequest // 11
ActionCloseIssue // 12
ActionReopenIssue // 13
ActionClosePullRequest // 14
ActionReopenPullRequest // 15
ActionDeleteTag // 16
ActionDeleteBranch // 17
ActionMirrorSyncPush // 18
ActionMirrorSyncCreate // 19
ActionMirrorSyncDelete // 20
ActionApprovePullRequest // 21
ActionRejectPullRequest // 22
ActionCommentPull // 23
*/

var actionNameZH={
"1":"创建了项目",
"2":"重命名项目 {oldRepoName} 为",
"5":"推送了 {branch} 分支的代码到",
"6":"创建了任务",
"7":"创建了合并请求",
"9":"推送了 {branch} 分支的代码到",
"10":"评论了任务",
"11":"合并了合并请求",
"12":"关闭了任务",
"13":"重新开启了任务",
"14":"关闭了合并请求",
"15":"重新开启了合并请求",
"17":"从 {repoName} 删除分支 {deleteBranchName}",
"22":"拒绝了合并请求",
"23":"评论了合并请求"
};

var actionNameEN={
"1":" created repository",
"2":" renamed repository from {oldRepoName} to ",
"5":" pushed to {branch} at",
"6":" opened issue",
"7":" created pull request",
"9":" pushed to {branch} at",
"10":" commented on issue",
"11":" merged pull request",
"12":" closed issue",
"13":" reopened issue",
"14":" closed pull request",
"15":" reopened pull request",
"17":" deleted branch {deleteBranchName} from {repoName}",
"22":" rejected pull request",
"23":" commented on pull request"
};

var repoAndOrgZH={
"1":"项目",
"2":"成员",
"3":"团队",
"4":"小时前",
"5":"分钟前",
"6":"秒前"
};

var repoAndOrgEN={
"1":"repository",
"2":"Members ",
"3":"Teams",
"4":" hours ago",
"5":" minutes ago",
"6":" seconds ago"
};


function getAction(opType,isZh){
if(isZh){
return actionNameZH[opType]
}else{
return actionNameEN[opType]
}
}

queryRecommendData();

function queryRecommendData(){
$.ajax({
type:"GET",
url:"/recommend/org",
headers: {
authorization:token,
},
dataType:"json",
async:false,
success:function(json){
console.log(json);
displayOrg(json);
},
error:function(response) {
console.log(response);
}
});

$.ajax({
type:"GET",
url:"/recommend/repo",
headers: {
authorization:token,
},
dataType:"json",
async:false,
success:function(json){
console.log(json);
displayRepo(json);
},
error:function(response) {
console.log(response);
}
});

}

/*
<div class="swiper-slide">
<div class="ui fluid card">
<div class="content">
<span class="right floated meta">
<i class="star icon"></i>276 <i class="star icon"></i>32
</span>
<img class="left floated mini ui image" src="/repo-avatars/278-a9f45e21b92b86dbf969c9f70dff1efc">
<a class="header nowrap" href="/OpenI/aiforge">aiforge </a>
<div class="description nowrap-2">
本项目是群体化方法与技术的开源实现案例,在基于Gitea的基础上,进一步支持社交化的协同开发、协同学习、协同研究等群体创新实践服务,特别是针对新一代人工智能技术特点,重点支持项目管理、git代码管理、大数据集存储管理与智能计算平台接入。
</div>
<div class="ui tags nowrap am-mt-10">
<a class="ui small label topic" href="/explore/repos?q=ai%e5%bc%80%e5%8f%91%e5%b7%a5%e5%85%b7&amp;topic=">ai开发工具</a>
<a class="ui small label topic" href="/explore/repos?q=openi&amp;topic=">openi</a>
<a class="ui small label topic" href="/explore/repos?q=golang&amp;topic=">golang</a>
<a class="ui small label topic" href="/explore/repos?q=git&amp;topic=">git</a>
<a class="ui small label topic" href="/explore/repos?q=pcl&amp;topic=">pcl</a>
</div>
</div>
</div>
</div>
*/
function displayRepo(json){
var orgRepo = document.getElementById("recommendrepo");
var html = "";
if (json != null && json.length > 0){
for(var i = 0; i < json.length;i++){
var record = json[i]
html += "<div class=\"swiper-slide\">";
html += " <div class=\"ui fluid card\">";
html += " <div class=\"content\">";
html += " <span class=\"right floated meta\">";
html += " <i class=\"ri-star-line\"></i>" + record["NumStars"] + "<i class=\"ri-git-branch-line am-ml-10\"></i>" + record["NumForks"];
html += " </span>";
html += " <img class=\"left floated mini ui image\" src=\"" + record["Avatar"] + "\">";
html += " <a class=\"header nowrap\" href=\"/" + record["OwnerName"] + "/" + record["Name"] + "\">" + record["Name"] +"</a>";
html += " <div class=\"description nowrap-2\">" + record["Description"] + " </div>";
html += " <div class=\"ui tags nowrap am-mt-10\">"
if(record["Topics"] != null){
for(var j = 0; j < record["Topics"].length; j++){
topic = record["Topics"][j];
url = "/explore/repos?q=" + (topic) + "&amp;topic="
html += "<a class=\"ui small label topic\" href=\"" + url + "\">" + topic + "</a>";
}
}
html += " </div>";
html += " </div>";
html += " </div>";
html += "</div>";
}
}
orgRepo.innerHTML = html;
swiperRepo.updateSlides();
swiperRepo.updateProgress();
}

/**
*
* <div class="column">
<div class="ui fluid card">
<div class="content">
<div class="ui small header">
<img class="ui image" src="/user/avatar/OpenI/-1">
<div class="content nowrap">
<a href="/OpenI">OpenI</a> 启智社区
<div class="sub header">39 项目 ・ 60 成员 ・ 23 团队</div>
</div>
</div>
</div>
</div>
</div>
*/

//var repoAndOrgZH = new Map([['1', "项目"], ['2', "成员"], ['3', "团队"]]);
//var repoAndOrgEN = new Map([['1', "Repository"], ['2', "Members"], ['3', "Teams"]]);


function getRepoOrOrg(key,isZhLang){
if(isZhLang){
return repoAndOrgZH[key];
}else{
return repoAndOrgEN[key];
}
}

function displayOrg(json){
var orgDiv = document.getElementById("recommendorg");
var html = "";
if (json != null && json.length > 0){
for(var i = 0; i < json.length;i++){
var record = json[i]
html += "<div class=\"column\">";
html += " <a href=\"/" + record["Name"] + "\" class=\"ui fluid card\">";
html += " <div class=\"content\">";
html += " <div class=\"ui small header\">";
html += " <img class=\"ui image\" src=\"" + record["Avatar"] + "\">";
html += " <div class=\"content nowrap\">";
html += " <span class=\"ui blue\">" + record["Name"] + "</span> " + record["FullName"];
html += " <div class=\"sub header\">" + record["NumRepos"] +" " + getRepoOrOrg(1,isZh) + " ・ " + record["NumMembers"] +" " + getRepoOrOrg(2,isZh) + " ・ " + record["NumTeams"] + " " + getRepoOrOrg(3,isZh) + "</div>";
html += " </div>";
html += " </div>";
html += " </div>";
html += " </a>";
html += "</div>";
}
}
orgDiv.innerHTML = html;
}

+ 13
- 10
routers/actionnotification.go View File

@@ -1,6 +1,8 @@
package routers

import (
"net/http"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
@@ -11,6 +13,9 @@ import (
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}

var SocketManager = socketwrap.NewClientsManager()
@@ -24,7 +29,7 @@ func ActionNotification(ctx *context.Context) {
}
client := &socketwrap.Client{Manager: SocketManager, Conn: conn, Send: make(chan *models.Action, 256)}

WriteLastTenActionsIfHave(conn)
WriteLastActionsIfHave(conn)

client.Manager.Register <- client

@@ -32,22 +37,20 @@ func ActionNotification(ctx *context.Context) {

}

func WriteLastTenActionsIfHave(conn *websocket.Conn) {
socketwrap.LastTenActionsQueue.Mutex.RLock()
func WriteLastActionsIfHave(conn *websocket.Conn) {
socketwrap.LastActionsQueue.Mutex.RLock()
{
size := socketwrap.LastTenActionsQueue.Queue.Len()
size := socketwrap.LastActionsQueue.Queue.Len()
if size > 0 {
tempE := socketwrap.LastTenActionsQueue.Queue.Front()
conn.WriteJSON(tempE)
tempE := socketwrap.LastActionsQueue.Queue.Front()
conn.WriteJSON(tempE.Value)
for i := 1; i < size; i++ {
tempE = tempE.Next()
conn.WriteJSON(tempE)
conn.WriteJSON(tempE.Value)

}
}

}
socketwrap.LastTenActionsQueue.Mutex.RUnlock()
socketwrap.LastActionsQueue.Mutex.RUnlock()
}



+ 8
- 2
routers/api/v1/api.go View File

@@ -524,7 +524,7 @@ func RegisterRoutes(m *macaron.Macaron) {
Get(notify.GetThread).
Patch(notify.ReadThread)
}, reqToken())
operationReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, OperationRequired: true})
//Project board
m.Group("/projectboard", func() {
@@ -544,7 +544,13 @@ func RegisterRoutes(m *macaron.Macaron) {
}, operationReq)

m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage)

m.Get("/query_user_current_month", operationReq, repo_ext.QueryUserStaticCurrentMonth)
m.Get("/query_user_current_week", operationReq, repo_ext.QueryUserStaticCurrentWeek)
m.Get("/query_user_current_year", operationReq, repo_ext.QueryUserStaticCurrentYear)
m.Get("/query_user_last30_day", operationReq, repo_ext.QueryUserStaticLast30Day)
m.Get("/query_user_last_month", operationReq, repo_ext.QueryUserStaticLastMonth)
m.Get("/query_user_yesterday", operationReq, repo_ext.QueryUserStaticYesterday)
m.Get("/query_user_all", operationReq, repo_ext.QueryUserStaticAll)
// Users
m.Group("/users", func() {
m.Get("/search", user.Search)


+ 6
- 11
routers/api/v1/repo/modelarts.go View File

@@ -6,6 +6,7 @@
package repo

import (
"code.gitea.io/gitea/modules/util"
"net/http"
"strconv"
"strings"
@@ -15,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/storage"
routerRepo "code.gitea.io/gitea/routers/repo"
)

func GetModelArtsNotebook(ctx *context.APIContext) {
@@ -105,7 +107,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
job.TrainJobDuration = result.TrainJobDuration

if result.Duration != 0 {
job.TrainJobDuration = addZero(result.Duration/3600000) + ":" + addZero(result.Duration%3600000/60000) + ":" + addZero(result.Duration%60000/1000)
job.TrainJobDuration = util.AddZero(result.Duration/3600000) + ":" + util.AddZero(result.Duration%3600000/60000) + ":" + util.AddZero(result.Duration%60000/1000)

} else {
job.TrainJobDuration = "00:00:00"
@@ -124,15 +126,6 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {

}

func addZero(t int64) (m string) {
if t < 10 {
m = "0" + strconv.FormatInt(t, 10)
return m
} else {
return strconv.FormatInt(t, 10)
}
}

func TrainJobGetLog(ctx *context.APIContext) {
var (
err error
@@ -237,7 +230,7 @@ func DelTrainJobVersion(ctx *context.APIContext) {
JobID: jobID,
})
if err != nil {
ctx.ServerError("get VersionListCount faild", err)
ctx.ServerError("get VersionListCount failed", err)
return
}
if VersionListCount > 0 {
@@ -255,6 +248,8 @@ func DelTrainJobVersion(ctx *context.APIContext) {
return
}
}
} else { //已删除该任务下的所有版本
routerRepo.DeleteJobStorage(task.JobName)
}

ctx.JSON(http.StatusOK, map[string]interface{}{


+ 48
- 9
routers/home.go View File

@@ -44,9 +44,52 @@ const (
func Home(ctx *context.Context) {
ctx.Data["PageIsHome"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
setRecommendURL(ctx)
ctx.HTML(200, tplHome)
}

func setRecommendURL(ctx *context.Context) {
addr := setting.RecommentRepoAddr[10:]
start := strings.Index(addr, "/")
end := strings.Index(addr, "raw")
if start != -1 && end != -1 {
ctx.Data["RecommendURL"] = addr[start:end]
} else {
ctx.Data["RecommendURL"] = setting.RecommentRepoAddr
}

ctx.Data["page_title"] = ctx.Tr("home.page_title")
ctx.Data["page_small_title"] = ctx.Tr("home.page_small_title")
ctx.Data["page_description"] = ctx.Tr("home.page_description")
ctx.Data["page_use"] = ctx.Tr("home.page_use")
ctx.Data["page_only_dynamic"] = ctx.Tr("home.page_only_dynamic")
ctx.Data["page_recommend_org"] = ctx.Tr("home.page_recommend_org")
ctx.Data["page_recommend_org_desc"] = ctx.Tr("home.page_recommend_org_desc")
ctx.Data["page_recommend_org_commit"] = ctx.Tr("home.page_recommend_org_commit")
ctx.Data["page_recommend_org_more"] = ctx.Tr("home.page_recommend_org_more")
ctx.Data["page_recommend_repo"] = ctx.Tr("home.page_recommend_repo")
ctx.Data["page_recommend_repo_desc"] = ctx.Tr("home.page_recommend_repo_desc")
ctx.Data["page_recommend_repo_commit"] = ctx.Tr("home.page_recommend_repo_commit")
ctx.Data["page_recommend_repo_go"] = ctx.Tr("home.page_recommend_repo_go")
ctx.Data["page_recommend_repo_more"] = ctx.Tr("home.page_recommend_repo_more")
ctx.Data["page_dev_env"] = ctx.Tr("home.page_dev_env")
ctx.Data["page_dev_env_desc"] = ctx.Tr("home.page_dev_env_desc")
ctx.Data["page_dev_env_desc_title"] = ctx.Tr("home.page_dev_env_desc_title")
ctx.Data["page_dev_env_desc_desc"] = ctx.Tr("home.page_dev_env_desc_desc")
ctx.Data["page_dev_env_desc1_title"] = ctx.Tr("home.page_dev_env_desc1_title")
ctx.Data["page_dev_env_desc1_desc"] = ctx.Tr("home.page_dev_env_desc1_desc")
ctx.Data["page_dev_env_desc2_title"] = ctx.Tr("home.page_dev_env_desc2_title")
ctx.Data["page_dev_env_desc2_desc"] = ctx.Tr("home.page_dev_env_desc2_desc")
ctx.Data["page_dev_env_desc3_title"] = ctx.Tr("home.page_dev_env_desc3_title")
ctx.Data["page_dev_env_desc3_desc"] = ctx.Tr("home.page_dev_env_desc3_desc")
ctx.Data["page_dev_yunlao"] = ctx.Tr("home.page_dev_yunlao")
ctx.Data["page_dev_yunlao_desc1"] = ctx.Tr("home.page_dev_yunlao_desc1")
ctx.Data["page_dev_yunlao_desc2"] = ctx.Tr("home.page_dev_yunlao_desc2")
ctx.Data["page_dev_yunlao_desc3"] = ctx.Tr("home.page_dev_yunlao_desc3")
ctx.Data["page_dev_yunlao_desc4"] = ctx.Tr("home.page_dev_yunlao_desc4")
ctx.Data["page_dev_yunlao_apply"] = ctx.Tr("home.page_dev_yunlao_apply")
}

func Dashboard(ctx *context.Context) {
if ctx.IsSigned {
if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
@@ -77,7 +120,7 @@ func Dashboard(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/login")
return
}
setRecommendURL(ctx)
ctx.Data["PageIsHome"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.HTML(200, tplHome)
@@ -527,6 +570,8 @@ func RecommendOrgFromPromote(ctx *context.Context) {
if err == nil {
userMap := make(map[string]interface{})
userMap["Name"] = user.Name
userMap["Description"] = user.Description
userMap["FullName"] = user.FullName
userMap["ID"] = user.ID
userMap["Avatar"] = user.RelAvatarLink()
userMap["NumRepos"] = user.NumRepos
@@ -558,14 +603,8 @@ func recommendFromPromote(url string) ([]string, error) {
lines := strings.Split(allLineStr, "\n")
result := make([]string, len(lines))
for i, line := range lines {

tmpIndex := strings.Index(line, ".")
log.Info("i=" + fmt.Sprint(i) + " line=" + line + " tmpIndex=" + fmt.Sprint(tmpIndex))
if tmpIndex == -1 {
result[i] = strings.Trim(line, " ")
} else {
result[i] = strings.Trim(line[tmpIndex+1:], " ")
}
log.Info("i=" + fmt.Sprint(i) + " line=" + line)
result[i] = strings.Trim(line, " ")
}
return result, nil
}


+ 87
- 0
routers/notice/notice.go View File

@@ -0,0 +1,87 @@
package notice

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"encoding/json"
"github.com/patrickmn/go-cache"
"time"
)

var noticeCache = cache.New(2*time.Minute, 1*time.Minute)

const (
NOTICE_CACHE_KEY = "notice"
)

type Notice struct {
Title string
Link string
Visible int //0 invisible, 1 visible
CommitId string
}

var lock int32 = 0

func GetNewestNotice() (*Notice, error) {
defer func() {
if err := recover(); err != nil {
log.Error("recover error", err)
}
}()

var notice *Notice
var err error
if setting.CacheOn {
notice, err = getNewestNoticeFromCacheAndDisk()
} else {
notice, err = getNewestNoticeFromDisk()
}

if err != nil {
return nil, err
}
return notice, nil
}

func getNoticeTimeout() time.Duration {
return time.Duration(setting.CacheTimeOutSecond) * time.Second
}

func getNewestNoticeFromDisk() (*Notice, error) {
log.Debug("Get notice from disk")
repoFile, err := models.ReadLatestFileInRepo(setting.UserNameOfNoticeRepo, setting.RepoNameOfNoticeRepo, setting.RefNameOfNoticeRepo, setting.TreePathOfNoticeRepo)
if err != nil {
log.Error("GetNewestNotice failed, error=%v", err)
return nil, err
}
notice := &Notice{}
json.Unmarshal(repoFile.Content, notice)
if notice.Title == "" {
return nil, err
}
notice.CommitId = repoFile.CommitId
return notice, nil
}

func getNewestNoticeFromCacheAndDisk() (*Notice, error) {
v, success := noticeCache.Get(NOTICE_CACHE_KEY)
if success {
log.Debug("Get notice from cache,value = %v", v)
if v == nil {
return nil, nil
}
n := v.(*Notice)
return n, nil
}

notice, err := getNewestNoticeFromDisk()
if err != nil {
log.Error("GetNewestNotice failed, error=%v", err)
noticeCache.Set(NOTICE_CACHE_KEY, nil, 30*time.Second)
return nil, err
}
noticeCache.Set(NOTICE_CACHE_KEY, notice, getNoticeTimeout())
return notice, nil
}

+ 8
- 0
routers/org/home.go View File

@@ -130,5 +130,13 @@ func Home(ctx *context.Context) {
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager

//find org tag info
tags, err := models.GetAllOfficialTagRepos(org.ID, ctx.Org.IsOwner)
if err != nil {
ctx.ServerError("GetAllOfficialTagRepos", err)
return
}

ctx.Data["tags"] = tags
ctx.HTML(200, tplOrgHome)
}

+ 90
- 0
routers/org/tag.go View File

@@ -0,0 +1,90 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package org

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context"
"errors"
"strconv"
)

const DefaultOrgTagLimit = -1

// SubmitTags submit repos of org tag
func SubmitTags(ctx *context.Context, form auth.SubmitReposOfTagForm) {
if !ctx.Org.IsOwner {
ctx.ServerError("UpdateTagReposByID", errors.New("no access to submit tags"))
return
}
tag := getTagFromContext(ctx)
if ctx.Written() {
return
}
if tag.Limit != DefaultOrgTagLimit && len(form.RepoList) > tag.Limit {
ctx.ServerError("UpdateTagReposByID", errors.New("tags size over limit"))
return
}
err := models.UpdateTagReposByID(tag.ID, ctx.Org.Organization.ID, form.RepoList)
if err != nil {
ctx.ServerError("UpdateTagReposByID", err)
return
}

ctx.JSON(200, map[string]interface{}{
"code": "00",
"msg": "success",
})
}

// GetTagRepos get repos under org tag
func GetTagRepos(ctx *context.Context) {
if !ctx.Org.IsOwner {
ctx.ServerError("GetTagRepos", errors.New("no access to get tags"))
return
}
tag := getTagFromContext(ctx)
if ctx.Written() {
return
}

r, err := models.GetTagRepos(tag.ID, ctx.Org.Organization.ID)
if err != nil {
ctx.ServerError("GetTagRepos", err)
return
}

ctx.JSON(200, map[string]interface{}{
"code": "00",
"msg": "success",
"data": r,
})
}

// getTagFromContext finds out tag info From context.
func getTagFromContext(ctx *context.Context) *models.OfficialTag {
var tag *models.OfficialTag
var err error

tagIdStr := ctx.Query("tagId")
if len(tagIdStr) == 0 {
ctx.ServerError("GetTagInfo", errors.New("tag is not exist"))
return nil
}
tagId, _ := strconv.ParseInt(tagIdStr, 10, 32)
tag, err = models.GetTagByID(tagId)
if err != nil {
if models.IsErrTagNotExist(err) {
ctx.NotFound("GetTagInfo", err)
} else {
ctx.ServerError("GetTagInfo", err)
}
return nil
}

return tag
}

+ 49
- 7
routers/repo/ai_model_manage.go View File

@@ -99,6 +99,18 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
//udpate status and version count
models.ModifyModelNewProperty(lastNewModelId, MODEL_NOT_LATEST, 0)
}
var units []models.RepoUnit
var deleteUnitTypes []models.UnitType
units = append(units, models.RepoUnit{
RepoID: ctx.Repo.Repository.ID,
Type: models.UnitTypeModelManage,
Config: &models.ModelManageConfig{
EnableModelManage: true,
},
})
deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeModelManage)

models.UpdateRepositoryUnits(ctx.Repo.Repository, units, deleteUnitTypes)

log.Info("save model end.")

@@ -130,10 +142,13 @@ func SaveModel(ctx *context.Context) {
version := ctx.Query("Version")
label := ctx.Query("Label")
description := ctx.Query("Description")
trainTaskCreate := ctx.QueryBool("trainTaskCreate")

if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.ServerError("No right.", errors.New(ctx.Tr("repo.model_noright")))
return
if !trainTaskCreate {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.ServerError("No right.", errors.New(ctx.Tr("repo.model_noright")))
return
}
}

if JobId == "" || VersionName == "" {
@@ -474,6 +489,23 @@ func ShowOneVersionOtherModel(ctx *context.Context) {

func ShowModelTemplate(ctx *context.Context) {
ctx.Data["isModelManage"] = true
repoId := ctx.Repo.Repository.ID
Type := -1
_, count, _ := models.QueryModel(&models.AiModelQueryOptions{
ListOptions: models.ListOptions{
Page: 1,
PageSize: 2,
},
RepoID: repoId,
Type: Type,
New: MODEL_LATEST,
})
ctx.Data["MODEL_COUNT"] = count

_, trainCount, _ := models.QueryModelTrainJobList(repoId)
log.Info("query train count=" + fmt.Sprint(trainCount))

ctx.Data["TRAIN_COUNT"] = trainCount
ctx.HTML(200, tplModelManageIndex)
}

@@ -626,7 +658,6 @@ func QueryModelListForPredict(ctx *context.Context) {

func QueryModelFileForPredict(ctx *context.Context) {
id := ctx.Query("ID")
parentDir := ctx.Query("parentDir")
model, err := models.QueryModelById(id)
if err != nil {
log.Error("no such model!", err.Error())
@@ -634,9 +665,20 @@ func QueryModelFileForPredict(ctx *context.Context) {
return
}
prefix := model.Path[len(setting.Bucket)+1:]
if parentDir != "" {
prefix = prefix + parentDir
}
fileinfos, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, prefix)
ctx.JSON(http.StatusOK, fileinfos)
}

func QueryOneLevelModelFile(ctx *context.Context) {
id := ctx.Query("ID")
parentDir := ctx.Query("parentDir")
model, err := models.QueryModelById(id)
if err != nil {
log.Error("no such model!", err.Error())
ctx.ServerError("no such model:", err)
return
}
prefix := model.Path[len(setting.Bucket)+1:]
fileinfos, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir)
ctx.JSON(http.StatusOK, fileinfos)
}

+ 52
- 8
routers/repo/blame.go View File

@@ -6,13 +6,6 @@ package repo

import (
"bytes"
"container/list"
"fmt"
"html"
gotemplate "html/template"
"net/url"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -22,6 +15,12 @@ import (
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"container/list"
"fmt"
"html"
gotemplate "html/template"
"net/url"
"strings"
)

const (
@@ -35,7 +34,52 @@ func RefBlame(ctx *context.Context) {
ctx.NotFound("Blame FileName", nil)
return
}

//get repo contributors info
contributors, err := git.GetContributors(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName)
if err == nil && contributors != nil {
var contributorInfos []*ContributorInfo
contributorInfoHash := make(map[string]*ContributorInfo)
count := 0
for _, c := range contributors {
if count >= 25 {
continue
}
if strings.Compare(c.Email, "") == 0 {
continue
}
// get user info from committer email
user, err := models.GetUserByActivateEmail(c.Email)
if err == nil {
// committer is system user, get info through user's primary email
if existedContributorInfo, ok := contributorInfoHash[user.Email]; ok {
// existed: same primary email, different committer name
existedContributorInfo.CommitCnt += c.CommitCnt
} else {
// new committer info
var newContributor = &ContributorInfo{
user, user.RelAvatarLink(), user.Name, user.Email, c.CommitCnt,
}
count++
contributorInfos = append(contributorInfos, newContributor)
contributorInfoHash[user.Email] = newContributor
}
} else {
// committer is not system user
if existedContributorInfo, ok := contributorInfoHash[c.Email]; ok {
// existed: same primary email, different committer name
existedContributorInfo.CommitCnt += c.CommitCnt
} else {
var newContributor = &ContributorInfo{
user, "", "", c.Email, c.CommitCnt,
}
count++
contributorInfos = append(contributorInfos, newContributor)
contributorInfoHash[c.Email] = newContributor
}
}
}
ctx.Data["ContributorInfo"] = contributorInfos
}
userName := ctx.Repo.Owner.Name
repoName := ctx.Repo.Repository.Name
commitID := ctx.Repo.CommitID


+ 158
- 79
routers/repo/cloudbrain.go View File

@@ -14,18 +14,17 @@ import (
"strings"
"time"

"code.gitea.io/gitea/modules/modelarts"

"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/storage"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
)

const (
@@ -206,7 +205,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
}
repo := ctx.Repo.Repository
downloadCode(repo, codePath)
uploadCodeToMinio(codePath+"/", jobName, "/code/")
uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/")

modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/"
mkModelPath(modelPath)
@@ -220,7 +219,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
gpuType = gpuInfo.Value
}
}
downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BrainScoreName, benchmarkPath, form.BenchmarkCategory, gpuType)
downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BenchmarkName, benchmarkPath, form.BenchmarkCategory, gpuType)
uploadCodeToMinio(benchmarkPath+"/", jobName, cloudbrain.BenchMarkMountPath+"/")
}

@@ -236,15 +235,79 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
uploadCodeToMinio(brainScorePath+"/", jobName, cloudbrain.BrainScoreMountPath+"/")
}

err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, getMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
getMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), getMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
getMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId)
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func CloudBrainRestart(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
var resultCode = "0"
var errorMsg = ""
var status = string(models.JobWaiting)

task := ctx.Cloudbrain
for {
if task.Status != string(models.JobStopped) && task.Status != string(models.JobSucceeded) && task.Status != string(models.JobFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not stopped"
break
}

if task.Image == "" || task.GpuQueue == "" || task.Type != models.TypeCloudBrainOne {
log.Error("the job(%s) version is too old", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job's version is too old and can not be restarted"
break
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin()) {
log.Error("the user has no right ro restart the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to restart the job"
break
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have already a running or waiting task, can not create more"
break
}
}

err = cloudbrain.RestartTask(ctx, task, &jobID)
if err != nil {
log.Error("RestartTask failed:%v", err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

break
}

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
}

func CloudBrainShow(ctx *context.Context) {
@@ -296,46 +359,19 @@ func CloudBrainShow(ctx *context.Context) {
}

func CloudBrainDebug(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
if !ctx.IsSigned {
log.Error("the user has not signed in")
ctx.Error(http.StatusForbidden, "", "the user has not signed in")
return
}
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}

debugUrl := setting.DebugServerHost + "jpylab_" + task.JobID + "_" + task.SubTaskName
debugUrl := setting.DebugServerHost + "jpylab_" + ctx.Cloudbrain.JobID + "_" + ctx.Cloudbrain.SubTaskName
ctx.Redirect(debugUrl)
}

func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrainForm) {
var jobID = ctx.Params(":jobid")
if !ctx.IsSigned {
log.Error("the user has not signed in")
ctx.Error(http.StatusForbidden, "", "the user has not signed in")
return
}
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.JSON(200, map[string]string{
"result_code": "-1",
"error_msg": "GetCloudbrainByJobID failed",
})
return
}

err = cloudbrain.CommitImage(jobID, models.CommitImageParams{
Ip: task.ContainerIp,
TaskContainerId: task.ContainerID,
err := cloudbrain.CommitImage(ctx.Cloudbrain.JobID, models.CommitImageParams{
Ip: ctx.Cloudbrain.ContainerIp,
TaskContainerId: ctx.Cloudbrain.ContainerID,
ImageDescription: form.Description,
ImageTag: form.Tag,
})
if err != nil {
log.Error("CommitImage(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"])
log.Error("CommitImage(%s) failed:%v", ctx.Cloudbrain.JobName, err.Error(), ctx.Data["msgID"])
ctx.JSON(200, map[string]string{
"result_code": "-1",
"error_msg": "CommitImage failed",
@@ -351,32 +387,46 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain

func CloudBrainStop(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
var resultCode = "0"
var errorMsg = ""
var status = ""

if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) {
log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"])
ctx.ServerError("the job has been stopped", errors.New("the job has been stopped"))
return
}
task := ctx.Cloudbrain
for {
if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) {
log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

err = cloudbrain.StopJob(jobID)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"])
ctx.ServerError("StopJob failed", err)
return
}
err := cloudbrain.StopJob(jobID)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

task.Status = string(models.JobStopped)
err = models.UpdateJob(task)
if err != nil {
ctx.ServerError("UpdateJob failed", err)
return
task.Status = string(models.JobStopped)
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

status = task.Status
break
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
}

func StopJobsByUserID(userID int64) {
@@ -423,7 +473,7 @@ func StopJobs(cloudBrains []*models.Cloudbrain) {
Action: models.ActionStop,
}
err := retry(3, time.Second*30, func() error {
_, err := modelarts.StopJob(taskInfo.JobID, param)
_, err := modelarts.ManageNotebook(taskInfo.JobID, param)
return err
})
logErrorAndUpdateJobStatus(err, taskInfo)
@@ -460,12 +510,7 @@ func logErrorAndUpdateJobStatus(err error, taskInfo *models.Cloudbrain) {
}

func CloudBrainDel(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
task := ctx.Cloudbrain

if task.Status != string(models.JobStopped) && task.Status != string(models.JobFailed) {
log.Error("the job(%s) has not been stopped", task.JobName, ctx.Data["msgID"])
@@ -473,12 +518,14 @@ func CloudBrainDel(ctx *context.Context) {
return
}

err = models.DeleteJob(task)
err := models.DeleteJob(task)
if err != nil {
ctx.ServerError("DeleteJob failed", err)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

deleteJobStorage(task.JobName, models.TypeCloudBrainOne)
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func CloudBrainShowModels(ctx *context.Context) {
@@ -560,7 +607,7 @@ func getImages(ctx *context.Context, imageType string) {

func GetModelDirs(jobName string, parentDir string) (string, error) {
var req string
modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath+"/")
modelActualPath := storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/")
if parentDir == "" {
req = "baseDir=" + modelActualPath
} else {
@@ -570,10 +617,6 @@ func GetModelDirs(jobName string, parentDir string) (string, error) {
return getDirs(req)
}

func getMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

func CloudBrainDownloadModel(ctx *context.Context) {
parentDir := ctx.Query("parentDir")
fileName := ctx.Query("fileName")
@@ -756,6 +799,35 @@ func mkModelPath(modelPath string) error {
return nil
}

func deleteJobStorage(jobName string, cloudbrainType int) error {
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
if err != nil {
log.Error("RemoveAll(%s) failed:%v", localJobPath, err)
}

//delete oss
if cloudbrainType == models.TypeCloudBrainOne {
dirPath := setting.CBCodePathPrefix + jobName + "/"
err = storage.Attachments.DeleteDir(dirPath)
if err != nil {
log.Error("DeleteDir(%s) failed:%v", localJobPath, err)
}
} else if cloudbrainType == models.TypeCloudBrainTwo {
//dirPath := setting.CodePathPrefix + jobName + "/"
//err = storage.ObsRemoveObject(setting.Bucket, dirPath)
//if err != nil {
// log.Error("ObsRemoveObject(%s) failed:%v", localJobPath, err)
//}
log.Info("no need to delete")
} else {
log.Error("cloudbrainType(%d) error", cloudbrainType)
}

return nil
}

func SyncCloudbrainStatus() {
cloudBrains, err := models.GetCloudBrainUnStoppedJob()
if err != nil {
@@ -827,6 +899,13 @@ func SyncCloudbrainStatus() {
task.Duration = result.Duration
task.TrainJobDuration = result.TrainJobDuration

if result.Duration != 0 {
task.TrainJobDuration = util.AddZero(result.Duration/3600000) + ":" + util.AddZero(result.Duration%3600000/60000) + ":" + util.AddZero(result.Duration%60000/1000)

} else {
task.TrainJobDuration = "00:00:00"
}

err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)


+ 5
- 0
routers/repo/issue.go View File

@@ -13,6 +13,7 @@ import (
"net/http"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
@@ -336,6 +337,7 @@ func issues(ctx *context.Context, milestoneID int64, isPullOption util.OptionalB

// Issues render issues page
func Issues(ctx *context.Context) {
startTime := time.Now()
isPullList := ctx.Params(":type") == "pulls"
if isPullList {
MustAllowPulls(ctx)
@@ -366,6 +368,9 @@ func Issues(ctx *context.Context) {

ctx.Data["CanWriteIssuesOrPulls"] = ctx.Repo.CanWriteIssuesOrPulls(isPullList)

duration := time.Since(startTime)
log.Info("Issues cost: %v seconds", duration.Seconds())

ctx.HTML(200, tplIssues)
}



+ 160
- 74
routers/repo/modelarts.go View File

@@ -11,11 +11,10 @@ import (
"strings"
"time"

"code.gitea.io/gitea/modules/cloudbrain"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
@@ -42,6 +41,7 @@ const (

func DebugJobIndex(ctx *context.Context) {
debugListType := ctx.Query("debugListType")
ctx.Data["ListType"] = debugListType
MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository
page := ctx.QueryInt("page")
@@ -49,12 +49,9 @@ func DebugJobIndex(ctx *context.Context) {
page = 1
}
debugType := modelarts.DebugType
jobType := string(models.JobTypeDebug)
if debugListType == modelarts.GPUResource {
if debugListType == models.GPUResource {
debugType = models.TypeCloudBrainOne
jobType = ""
}
if debugListType == modelarts.NPUResource {
} else if debugListType == models.NPUResource {
debugType = models.TypeCloudBrainTwo
}

@@ -63,9 +60,10 @@ func DebugJobIndex(ctx *context.Context) {
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
Type: debugType,
JobType: jobType,
RepoID: repo.ID,
Type: debugType,
JobTypeNot: true,
JobType: string(models.JobTypeTrain),
})
if err != nil {
ctx.ServerError("Get debugjob faild:", err)
@@ -73,21 +71,13 @@ func DebugJobIndex(ctx *context.Context) {
}

for i, task := range ciTasks {
if task.Cloudbrain.Type == models.TypeCloudBrainOne {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.GPUResource
}
if task.Cloudbrain.Type == models.TypeCloudBrainTwo {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.NPUResource
}

ciTasks[i].CanDebug = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "debugListType", "ListType")
ctx.Data["Page"] = pager
ctx.Data["PageIsCloudBrain"] = true
ctx.Data["Tasks"] = ciTasks
@@ -150,13 +140,27 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm)
return
}
}
_, err = models.GetCloudbrainByName(jobName)
if err == nil {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("the job name did already exist", tplModelArtsNotebookNew, &form)
return
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form)
return
}
}

err = modelarts.GenerateTask(ctx, jobName, uuid, description, flavor)
if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func NotebookShow(ctx *context.Context) {
@@ -202,11 +206,6 @@ func NotebookShow(ctx *context.Context) {

func NotebookDebug(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
_, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}

result, err := modelarts.GetJob(jobID)
if err != nil {
@@ -232,55 +231,118 @@ func NotebookDebug(ctx *context.Context) {
ctx.Redirect(debugUrl)
}

func NotebookStop(ctx *context.Context) {
func NotebookManage(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
log.Info(jobID)
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
var action = ctx.Params(":action")
var resultCode = "0"
var errorMsg = ""
var status = ""

if task.Status != string(models.JobRunning) {
log.Error("the job(%s) is not running", task.JobName)
ctx.ServerError("the job is not running", errors.New("the job is not running"))
return
}
for {
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

param := models.NotebookAction{
Action: models.ActionStop,
}
res, err := modelarts.StopJob(jobID, param)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err.Error())
ctx.ServerError("StopJob failed", err)
return
}
if action == models.ActionStop {
if task.Status != string(models.ModelArtsRunning) {
log.Error("the job(%s) is not running", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not running"
break
}

task.Status = res.CurrentStatus
err = models.UpdateJob(task)
if err != nil {
ctx.ServerError("UpdateJob failed", err)
return
if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin() && !ctx.IsUserRepoOwner()) {
log.Error("the user has no right ro stop the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to stop the job"
break
}
} else if action == models.ActionRestart {
if task.Status != string(models.ModelArtsStopped) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsCreateFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not stopped"
break
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin()) {
log.Error("the user has no right ro restart the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to restart the job"
break
}

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have already a running or waiting task, can not create more"
break
}
}

action = models.ActionStart
} else {
log.Error("the action(%s) is illegal", action, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "非法操作"
break
}

param := models.NotebookAction{
Action: action,
}
res, err := modelarts.ManageNotebook(jobID, param)
if err != nil {
log.Error("ManageNotebook(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "启动失败"
break
}

task.Status = res.CurrentStatus
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

status = task.Status

break
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
}

func NotebookDel(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
task := ctx.Cloudbrain

if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped){
if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped) {
log.Error("the job(%s) has not been stopped", task.JobName)
ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped"))
return
}

_, err = modelarts.DelNotebook(jobID)
_, err := modelarts.DelNotebook(jobID)
if err != nil {
log.Error("DelJob(%s) failed:%v", task.JobName, err.Error())
ctx.ServerError("DelJob failed", err)
@@ -293,7 +355,7 @@ func NotebookDel(ctx *context.Context) {
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func TrainJobIndex(ctx *context.Context) {
@@ -312,6 +374,7 @@ func TrainJobIndex(ctx *context.Context) {
},
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobTypeNot: false,
JobType: string(models.JobTypeTrain),
IsLatestVersion: modelarts.IsLatestVersion,
})
@@ -323,6 +386,7 @@ func TrainJobIndex(ctx *context.Context) {
for i, task := range tasks {
tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
tasks[i].ComputeResource = models.NPUResource
}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
@@ -364,7 +428,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = jobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
@@ -433,7 +497,7 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = jobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
@@ -521,7 +585,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = task.JobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
@@ -610,7 +674,7 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = task.JobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
@@ -1192,6 +1256,10 @@ func paramCheckCreateTrainJob(form auth.CreateModelArtsTrainJobForm) error {
log.Error("the WorkServerNumber(%d) must be in (1,25)", form.WorkServerNumber)
return errors.New("计算节点数必须在1-25之间")
}
if form.BranchName == "" {
log.Error("the branch must not be null!", form.BranchName)
return errors.New("代码分支不能为空!")
}

return nil
}
@@ -1352,19 +1420,19 @@ func TrainJobDel(ctx *context.Context) {
}
}

//删除存储
if len(VersionListTasks) > 0 {
DeleteJobStorage(VersionListTasks[0].JobName)
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job")
}

func TrainJobStop(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil)
return
}
task := ctx.Cloudbrain

_, err = modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10))
_, err := modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10))
if err != nil {
log.Error("StopTrainJob(%s) failed:%v", task.JobName, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil)
@@ -1477,3 +1545,21 @@ func ModelDownload(ctx *context.Context) {
}
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently)
}

func DeleteJobStorage(jobName string) error {
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
if err != nil {
log.Error("RemoveAll(%s) failed:%v", localJobPath, err)
}

//delete oss
dirPath := setting.CodePathPrefix + jobName + "/"
err = storage.ObsRemoveObject(setting.Bucket, dirPath)
if err != nil {
log.Error("ObsRemoveObject(%s) failed:%v", localJobPath, err)
}

return nil
}

+ 126
- 0
routers/repo/user_data_analysis.go View File

@@ -15,6 +15,132 @@ import (
"github.com/360EntSecGroup-Skylar/excelize/v2"
)

const (
PAGE_SIZE = 2000
)

func queryUserDataPage(ctx *context.Context, tableName string, queryObj interface{}) {
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
userName := ctx.Query("userName")
IsReturnFile := ctx.QueryBool("IsReturnFile")

if IsReturnFile {
//writer exec file.
xlsx := excelize.NewFile()
sheetName := ctx.Tr("user.static.sheetname")
index := xlsx.NewSheet(sheetName)
xlsx.DeleteSheet("Sheet1")
dataHeader := map[string]string{
"A1": ctx.Tr("user.static.id"),
"B1": ctx.Tr("user.static.name"),
"C1": ctx.Tr("user.static.codemergecount"),
"D1": ctx.Tr("user.static.commitcount"),
"E1": ctx.Tr("user.static.issuecount"),
"F1": ctx.Tr("user.static.commentcount"),
"G1": ctx.Tr("user.static.focusrepocount"),
"H1": ctx.Tr("user.static.starrepocount"),
"I1": ctx.Tr("user.static.logincount"),
"J1": ctx.Tr("user.static.watchedcount"),
"K1": ctx.Tr("user.static.commitcodesize"),
"L1": ctx.Tr("user.static.solveissuecount"),
"M1": ctx.Tr("user.static.encyclopediascount"),
"N1": ctx.Tr("user.static.createrepocount"),
"O1": ctx.Tr("user.static.openiindex"),
"P1": ctx.Tr("user.static.registdate"),
"Q1": ctx.Tr("user.static.countdate"),
}
for k, v := range dataHeader {
//设置单元格的值
xlsx.SetCellValue(sheetName, k, v)
}
_, count := models.QueryUserStaticDataByTableName(1, 1, tableName, queryObj, userName)
var indexTotal int64
indexTotal = 0
for {
re, _ := models.QueryUserStaticDataByTableName(int(indexTotal), PAGE_SIZE, tableName, queryObj, "")
log.Info("return count=" + fmt.Sprint(count))
for i, userRecord := range re {
rows := fmt.Sprint(i + 2)
xlsx.SetCellValue(sheetName, "A"+rows, userRecord.ID)
xlsx.SetCellValue(sheetName, "B"+rows, userRecord.Name)
xlsx.SetCellValue(sheetName, "C"+rows, userRecord.CodeMergeCount)
xlsx.SetCellValue(sheetName, "D"+rows, userRecord.CommitCount)
xlsx.SetCellValue(sheetName, "E"+rows, userRecord.IssueCount)
xlsx.SetCellValue(sheetName, "F"+rows, userRecord.CommentCount)
xlsx.SetCellValue(sheetName, "G"+rows, userRecord.FocusRepoCount)
xlsx.SetCellValue(sheetName, "H"+rows, userRecord.StarRepoCount)
xlsx.SetCellValue(sheetName, "I"+rows, userRecord.LoginCount)
xlsx.SetCellValue(sheetName, "J"+rows, userRecord.WatchedCount)
xlsx.SetCellValue(sheetName, "K"+rows, userRecord.CommitCodeSize)
xlsx.SetCellValue(sheetName, "L"+rows, userRecord.SolveIssueCount)
xlsx.SetCellValue(sheetName, "M"+rows, userRecord.EncyclopediasCount)
xlsx.SetCellValue(sheetName, "N"+rows, userRecord.CreateRepoCount)
xlsx.SetCellValue(sheetName, "O"+rows, fmt.Sprintf("%.2f", userRecord.OpenIIndex))

formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3])

formatTime = userRecord.DataDate
xlsx.SetCellValue(sheetName, "Q"+rows, formatTime+" 00:01")
}

//设置默认打开的表单
xlsx.SetActiveSheet(index)
filename := sheetName + "_" + ctx.Tr("user.static."+tableName) + ".xlsx"
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
if _, err := xlsx.WriteTo(ctx.Resp); err != nil {
log.Info("writer exel error." + err.Error())
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
} else {
re, count := models.QueryUserStaticDataByTableName((page-1)*pageSize, pageSize, tableName, queryObj, userName)
mapInterface := make(map[string]interface{})
mapInterface["data"] = re
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
}
}

func QueryUserStaticCurrentMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth))
}

func QueryUserStaticCurrentWeek(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_week", new(models.UserBusinessAnalysisCurrentWeek))
}

func QueryUserStaticCurrentYear(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_year", new(models.UserBusinessAnalysisCurrentYear))
}

func QueryUserStaticLast30Day(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_last30_day", new(models.UserBusinessAnalysisLast30Day))
}

func QueryUserStaticLastMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_last_month", new(models.UserBusinessAnalysisLastMonth))
}

func QueryUserStaticYesterday(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_yesterday", new(models.UserBusinessAnalysisYesterday))
}

func QueryUserStaticAll(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_all", new(models.UserBusinessAnalysisAll))
}

func QueryUserStaticDataPage(ctx *context.Context) {
startDate := ctx.Query("startDate")
endDate := ctx.Query("endDate")


+ 13
- 7
routers/routes/routes.go View File

@@ -628,6 +628,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/org", func() {
m.Group("/:org", func() {
m.Get("/members", org.Members)
m.Group("/org_tag", func() {
m.Get("/repo_list", org.GetTagRepos)
m.Post("/repo_submit", bindIgnErr(auth.SubmitReposOfTagForm{}), org.SubmitTags)
})
}, context.OrgAssignment())
})
m.Group("/org", func() {
@@ -965,20 +969,21 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/cloudbrain", func() {
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.CloudBrainDebug)
m.Post("/commit_image", cloudbrain.AdminOrOwnerOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage)
m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainDebug)
m.Post("/commit_image", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDel)
m.Post("/restart", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainRestart)
m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate)
m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels)
m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDownloadModel)
m.Get("/download_model", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainDownloadModel)
})
m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainNew)
m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate)
}, context.RepoRef())
m.Group("/modelmanage", func() {
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel)
m.Post("/create_new_model", reqRepoModelManageWriter, repo.SaveNewNameModel)
m.Post("/create_new_model", repo.SaveNewNameModel)
m.Delete("/delete_model", repo.DeleteModel)
m.Put("/modify_model", repo.ModifyModelInfo)
m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate)
@@ -990,6 +995,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList)
m.Get("/query_model_for_predict", reqRepoCloudBrainReader, repo.QueryModelListForPredict)
m.Get("/query_modelfile_for_predict", reqRepoCloudBrainReader, repo.QueryModelFileForPredict)
m.Get("/query_onelevel_modelfile", reqRepoCloudBrainReader, repo.QueryOneLevelModelFile)
m.Group("/:ID", func() {
m.Get("", repo.ShowSingleModel)
m.Get("/downloadsingle", repo.DownloadSingleModelFile)
@@ -1005,8 +1011,8 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/notebook", func() {
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.NotebookShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.NotebookDebug)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookStop)
m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.NotebookDebug)
m.Post("/:action", reqRepoCloudBrainWriter, repo.NotebookManage)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel)
})
m.Get("/create", reqRepoCloudBrainWriter, repo.NotebookNew)
@@ -1019,7 +1025,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobDel)
m.Get("/model_download", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.ModelDownload)
m.Get("/model_download", cloudbrain.AdminOrJobCreaterRight, repo.ModelDownload)
m.Get("/create_version", cloudbrain.AdminOrJobCreaterRight, repo.TrainJobNewVersion)
m.Post("/create_version", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion)
})


+ 1
- 2
services/repository/repository.go View File

@@ -5,13 +5,12 @@
package repository

import (
"fmt"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
repo_module "code.gitea.io/gitea/modules/repository"
pull_service "code.gitea.io/gitea/services/pull"
"fmt"
)

// CreateRepository creates a repository for the user/organization.


+ 5
- 0
services/socketwrap/client.go View File

@@ -14,6 +14,11 @@ type Client struct {
Send chan *models.Action
}

func (c *Client) Close() {
close(c.Send)
c.Conn.Close()
}

func (c *Client) WritePump() {

defer func() {


+ 46
- 11
services/socketwrap/clientManager.go View File

@@ -1,11 +1,17 @@
package socketwrap

import (
"os"
"os/signal"
"syscall"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"github.com/elliotchance/orderedmap"
)

type ClientsManager struct {
Clients map[*Client]bool
Clients *orderedmap.OrderedMap
Register chan *Client
Unregister chan *Client
}
@@ -14,33 +20,62 @@ func NewClientsManager() *ClientsManager {
return &ClientsManager{
Register: make(chan *Client),
Unregister: make(chan *Client),
Clients: make(map[*Client]bool),
Clients: orderedmap.NewOrderedMap(),
}
}

var LastTenActionsQueue = NewSyncQueue(10)
const MaxClients = 100

var LastActionsQueue = NewSyncQueue(20)

func (h *ClientsManager) Run() {
initActionQueue()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
var signalsReceived uint
for {
select {
case client := <-h.Register:
h.Clients[client] = true
h.Clients.Set(client, true)
if h.Clients.Len() > MaxClients {
h.Clients.Delete(h.Clients.Front().Key)
}

case client := <-h.Unregister:
if _, ok := h.Clients[client]; ok {
delete(h.Clients, client)
if _, ok := h.Clients.Get(client); ok {
h.Clients.Delete(client)
close(client.Send)
}
case message := <-models.ActionChan:
LastTenActionsQueue.Push(message)
for client := range h.Clients {
LastActionsQueue.Push(message)
for _, client := range h.Clients.Keys() {
select {
case client.Send <- message:
case client.(*Client).Send <- message:
default:
close(client.Send)
delete(h.Clients, client)
close(client.(*Client).Send)
h.Clients.Delete(client)
}
}
case s := <-sig:
log.Info("received signal", s)
signalsReceived++
if signalsReceived < 2 {
for _, client := range h.Clients.Keys() {
h.Clients.Delete(client)
client.(*Client).Close()
}
break

}
}
}
}

func initActionQueue() {
actions, err := models.GetLast20PublicFeeds()
if err == nil {
for i := len(actions) - 1; i >= 0; i-- {
LastActionsQueue.Push(actions[i])
}
}
}

+ 7
- 0
templates/base/footer_content.tmpl View File

@@ -26,7 +26,14 @@
{{end}}
</div>
</div>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="ui item" target="_blank">{{.i18n.Tr "custom.Platform_Tutorial"}}</a>
{{if .EnableSwagger}}<a href="/api/swagger" class="ui item">API</a>{{end}}
{{if .IsSigned}}
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="ui item" target="_blank">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{else}}
<a href="{{AppSubUrl}}/user/login" class="ui item">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{end}}

{{template "custom/extra_links_footer" .}}
</div>
</div>


+ 6
- 0
templates/base/footer_content_fluid.tmpl View File

@@ -26,7 +26,13 @@
{{end}}
</div>
</div>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="ui item" target="_blank">{{.i18n.Tr "custom.Platform_Tutorial"}}</a>
{{if .EnableSwagger}}<a href="/api/swagger" class="ui item">API</a>{{end}}
{{if .IsSigned}}
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="ui item" target="_blank">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{else}}
<a href="{{AppSubUrl}}/user/login" class="ui item">{{.i18n.Tr "custom.foot.advice_feedback"}}</a>
{{end}}
{{template "custom/extra_links_footer" .}}
</div>
</div>


+ 44
- 2
templates/base/head.tmpl View File

@@ -186,7 +186,6 @@ var _hmt = _hmt || [];
})();
</script>
<script src="/self/func.js" type="text/javascript"></script>

</head>
<body>
{{template "custom/body_outer_pre" .}}
@@ -195,14 +194,57 @@ var _hmt = _hmt || [];
<noscript>{{.i18n.Tr "enable_javascript"}}</noscript>

{{template "custom/body_inner_pre" .}}
{{if not .PageIsInstall}}
<div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar" .}}
</div><!-- end bar -->
<div class="notic_content" id ="notic_content" >
<a href={{.notice.Link}} class="a_width">
<marquee behavior="scroll" direction="left">
{{.notice.Title}}
</marquee>
</a>
<i class="icon icon-octicon x_icon" onclick="closeNoice()">{{svg "octicon-x" 16}}</i>
</div>
{{end}}
{{/*
</div>
</body>
</html>
*/}}

<script>
function closeNoice(){
document.getElementById("notic_content").style.display='none'
localStorage.setItem("isCloseNotice",true)
}
function isShowNotice(){
var current_notice = localStorage.getItem("notice")

if (current_notice != "{{.notice.CommitId}}"){
localStorage.setItem('notice',"{{.notice.CommitId}}");
isNewNotice=true;
localStorage.setItem("isCloseNotice",false)
}else{
isNewNotice=false;
}
if ("{{.notice.Visible}}"){
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{
isCloseNotice = localStorage.getItem("isCloseNotice")
if (JSON.parse(isCloseNotice)){
document.getElementById("notic_content").style.display='none'
}else{
document.getElementById("notic_content").style.display='block'
}

}
}else{
document.getElementById("notic_content").style.display='none'
}
}
isShowNotice();
</script>

+ 43
- 0
templates/base/head_fluid.tmpl View File

@@ -200,9 +200,52 @@ var _hmt = _hmt || [];
<div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar_fluid" .}}
</div><!-- end bar -->
<div class="notic_content" id ="notic_content" >
<a href={{.notice.Link}} class="a_width">
<marquee behavior="scroll" direction="left">
{{.notice.Title}}
</marquee>
</a>
<i class="icon icon-octicon x_icon" onclick="closeNoice()">{{svg "octicon-x" 16}}</i>
</div>
{{end}}
{{/*
</div>
</body>
</html>
*/}}

<script>
function closeNoice(){
document.getElementById("notic_content").style.display='none'
localStorage.setItem("isCloseNotice",true)
}
function isShowNotice(){
var current_notice = localStorage.getItem("notice")

if (current_notice != "{{.notice.CommitId}}"){
localStorage.setItem('notice',"{{.notice.CommitId}}");
isNewNotice=true;
localStorage.setItem("isCloseNotice",false)
}else{
isNewNotice=false;
}
if ("{{.notice.Visible}}"){
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{
isCloseNotice = localStorage.getItem("isCloseNotice")
if (JSON.parse(isCloseNotice)){
document.getElementById("notic_content").style.display='none'
}else{
document.getElementById("notic_content").style.display='block'
}

}
}else{
document.getElementById("notic_content").style.display='none'
}
}
isShowNotice();
</script>

+ 13
- 10
templates/base/head_home.tmpl View File

@@ -186,24 +186,27 @@ var _hmt = _hmt || [];
s.parentNode.insertBefore(hm, s);
})();
</script>
<script src="/self/func.js" type="text/javascript"></script>
<!--RemixIcon Fonts v2.5.0-->
<link rel="stylesheet" href="/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css">
<!-- Swiper -->
<link rel="stylesheet" href="/swiper/swiper-bundle.min.css">
<script src="/swiper/swiper-bundle.min.js"></script>
</head>
<body>
{{template "custom/body_outer_pre" .}}

<div class="full height">
<noscript>{{.i18n.Tr "enable_javascript"}}</noscript>
<div class="ui vertical masthead secondary hometop segment">
{{template "custom/body_inner_pre" .}}

{{if not .PageIsInstall}}
<div class="ui container">
<div class="ui top secondary stackable main menu following bar">
{{template "base/head_navbar_home" .}}
</div><!-- end bar -->
</div>
{{end}}
{{template "custom/body_inner_pre" .}}
{{if not .PageIsInstall}}
<div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar" .}}
</div><!-- end bar -->
{{end}}
{{/*
</div>
</div>
</body>
</html>


+ 10
- 0
templates/base/head_navbar.tmpl View File

@@ -168,6 +168,14 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>

@@ -213,4 +221,6 @@
</div><!-- end anonymous right menu -->

{{end}}

</div>


+ 8
- 0
templates/base/head_navbar_fluid.tmpl View File

@@ -166,6 +166,14 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>



+ 8
- 0
templates/base/head_navbar_home.tmpl View File

@@ -148,6 +148,14 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>



+ 8
- 0
templates/base/head_navbar_pro.tmpl View File

@@ -169,6 +169,14 @@
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
<a class="item" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">
<i class="tutorial_icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/><path d="M2 3.993A1 1 0 0 1 2.992 3h18.016c.548 0 .992.445.992.993v16.014a1 1 0 0 1-.992.993H2.992A.993.993 0 0 1 2 20.007V3.993zM12 5v14h8V5h-8zm1 2h6v2h-6V7zm0 3h6v2h-6v-2z"/>
</svg>
</i>
{{.i18n.Tr "custom.Platform_Tutorial"}}
</a>
{{if .IsAdmin}}
<div class="divider"></div>



+ 44
- 0
templates/base/head_pro.tmpl View File

@@ -200,9 +200,53 @@ var _hmt = _hmt || [];
<div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar_pro" .}}
</div><!-- end bar -->
<div class="notic_content" id ="notic_content" >
<a href={{.notice.Link}} class="a_width">
<marquee behavior="scroll" direction="left">
{{.notice.Title}}
</marquee>
</a>
<i class="icon icon-octicon x_icon" onclick="closeNoice()">{{svg "octicon-x" 16}}</i>
</div>
{{end}}
{{/*
</div>
</body>
</html>
*/}}


<script>
function closeNoice(){
document.getElementById("notic_content").style.display='none'
localStorage.setItem("isCloseNotice",true)
}
function isShowNotice(){
var current_notice = localStorage.getItem("notice")

if (current_notice != "{{.notice.CommitId}}"){
localStorage.setItem('notice',"{{.notice.CommitId}}");
isNewNotice=true;
localStorage.setItem("isCloseNotice",false)
}else{
isNewNotice=false;
}
if ("{{.notice.Visible}}"){
if(isNewNotice){
document.getElementById("notic_content").style.display='block'
}else{
isCloseNotice = localStorage.getItem("isCloseNotice")
if (JSON.parse(isCloseNotice)){
document.getElementById("notic_content").style.display='none'
}else{
document.getElementById("notic_content").style.display='block'
}

}
}else{
document.getElementById("notic_content").style.display='none'
}
}
isShowNotice();
</script>

+ 1
- 1
templates/base/paginate.tmpl View File

@@ -1,7 +1,7 @@
{{$paginationLink := .Page.GetParams}}
{{with .Page.Paginater}}
{{if gt .TotalPages 1}}
<div class="center page buttons">
<div class="center page buttons" style="margin: 0px auto 15px">
<div class="ui borderless pagination menu">
<a class="{{if .IsFirst}}disabled{{end}} item navigation" {{if not .IsFirst}}href="{{$.Link}}{{if $paginationLink}}?{{$paginationLink}}{{end}}"{{end}}><i class="angle double left icon"></i><span class="navigation_label">&nbsp;{{$.i18n.Tr "admin.first_page"}}</span></a>
<a class="{{if not .HasPrevious}}disabled{{end}} item navigation" {{if .HasPrevious}}href="{{$.Link}}?page={{.Previous}}{{if $paginationLink}}&{{$paginationLink}}{{end}}"{{end}}>


+ 13
- 13
templates/explore/repo_list.tmpl View File

@@ -40,20 +40,20 @@

<div class="ui secondary pointing tabular top attached borderless menu navbar">
{{if .PageIsExplore}}
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=hot">
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=hot&tab={{$.TabName}}">
<svg class="svg octicon-repo" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-repo" />
</svg>
热门{{.i18n.Tr "explore.repos"}}
</a>
<a class="{{if eq .SortType "active"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=active">
<a class="{{if eq .SortType "active"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=active&tab={{$.TabName}}">
<svg class="svg octicon-inbox" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-inbox" />
</svg>
活跃{{.i18n.Tr "explore.repos"}}
</a>
{{end}}
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=recentupdate">
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=recentupdate&tab={{$.TabName}}">
<svg class="svg octicon-organization" width="16" height="16" aria-hidden="true">
<use xlink:href="#octicon-organization" />
</svg> {{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}
@@ -67,16 +67,16 @@
<i class="dropdown icon"></i>
</span>
<div class="menu">
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&topic={{$.Topic}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
</div>
</div>
</div>


+ 1
- 1
templates/explore/repo_orgtop.tmpl View File

@@ -59,7 +59,7 @@
</div>
<div class="swiper-slide">
<div class="ui card">
<a class="image" href="https://git.openi.org.cn/TensorLayer">
<a class="image" href="https://git.openi.org.cn/OpenI/TensorLayerX">
<img src="/img/org-tensorlayer@2x-80.jpg" alt="TensorLayer" title="TensorLayer">
</a>
</div>


+ 1
- 0
templates/explore/repo_search.tmpl View File

@@ -10,6 +10,7 @@
<div class="ui fluid action input">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
<input type="hidden" name="topic" value="{{$.Topic}}">
<input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}">
<button class="ui green button">{{.i18n.Tr "explore.search"}}</button>
</div>


+ 132
- 192
templates/home.tmpl View File

@@ -1,221 +1,161 @@
{{template "base/head_home" .}}
<div class="ui container homebanner">
<h1 class="ui header">
启智AI开发协作平台
<div class="sub header">
面向AI领域的一站式协同开发环境
</div>
</h1>
<p class="am-lh-18">免费私有代码仓库,免费计算资源,大容量数据存储,<br>多类型硬件环境(GPU、NPU),AI开发流水线(开发-调试-训练-迭代)</p>
{{if .IsSigned}}
<a class="circular ui secondary button" href="{{AppSubUrl}}/dashboard">立即使用 <i class="right arrow icon"></i></a>
{{else}}
<a class="circular ui secondary button" href="{{AppSubUrl}}/user/login">立即使用 <i class="right arrow icon"></i></a>
{{end}}
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div>
</div>
</div><!-- end segment -->

<div class="explore repositories">
<div class="ui sticky container">
<div class="ui secondary pointing fluid five item menu" style="background-color: #FFF;">
<a class="item" href="#first">代码</a>
<a class="item" href="#second">数据</a>
<a class="item" href="#third">AI流水线</a>
<a class="item" href="#fourth">协同开发</a>
<a class="item" href="#fifth">云脑协同</a>
</div>
</div>

<div id="railContent">
<a name="first"></a>
<div class="ui container am-mt-30 basic tab i-code active" style="position: relative;">
<div class="ui inverted very padded segment radius15 am-pl-30">
<div class="ui mobile reversed stackable grid am-pl-30">
<div class="six wide column">
<h2 class="ui huge blue header">代码管理</h2>
<p class="am-lh-18">在这里为你和你的团队创建项目,基于Git工具,提交记录或者回滚代码修改。<br>
不论是公开或者私有仓库,都可免费使用所有功能。<br>
尽情将你喜欢的代码都放在这里,仓库数量、存储容量不受限</p>
{{if .IsSigned}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/dashboard">立即使用 </a>
{{else}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/user/login">立即使用 </a>
{{end}}
</div>
<div class="ten wide column computer only i-code-pic am-pt-30">
<img class="ui fluid rounded image am-shadow-2 am-mt-10" src="/img/i-code-pic.jpg" style="position: absolute;">
<div class="ui vertical masthead secondary hometop segment">
<div class="ui container" style="position: relative;">
<div class="ui center homebanner">
<h1 class="ui huge header">
{{.page_title}}
<div class="sub header">
{{.page_small_title}}
</div>
</div>
</h1>
<p class="ui am-lh-18">{{.page_description}}</p>
{{if .IsSigned}}
<a class="circular huge ui secondary button" href="{{AppSubUrl}}/dashboard">{{.page_use}} <i class="right arrow icon"></i></a>
{{else}}
<a class="circular huge ui secondary button" href="{{AppSubUrl}}/user/login">{{.page_use}} <i class="right arrow icon"></i></a>
{{end}}
</div>
<div class="am-mt-30 am-pt-30 am-pl-30">
<div class="am-pl-30 am-pb-30">
<h2 class="ui huge header am-bw">协作开发</h2>
<p class="am-lh-18">鼓励通过创建合并请求(PR)的方式,更好的进行团队协作<br>
代码评审让每一次的代码修改得以二次确认,提高代码质量<br>
创建并指派任务(Issue),让每一个任务的进展有迹可循,规范管理<br>
被合并的PR,可获得奖励积分;积分总额可以显示出你在项目中的贡献度,也许有一天会有人愿意为此付费<br>
</p>
</div>
</div>
<div class="leftline01"></div>
</div>

<a name="second"></a>
<div class="ui basic tab active am-mt-30 bg-gray am-pt-30">
<div class="ui container i-data" style="position: relative;">
<div class="leftline02"></div>
<div class="ui stackable grid">
<div class="nine wide column">
<img class="ui centered medium rounded large image" src="/img/gitopeni-index-02.svg">
<div class="i-code-pic" style="margin-top: -4.0rem;">
<img class="ui fluid rounded image am-shadow-2" src="/img/i-data-pic.jpg">
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div>
<div id="homenews" class="ui container">
<p>* {{.page_only_dynamic}}</p>
<div class="ui grid">
<div class="twelve wide tablet ten wide computer column homenews">
<div class="newslist">
<div class="ui mini aligned list swiper-wrapper" id="newmessage">
</div>
</div>
</div>
<div class="seven wide column am-pt-30">
<h2 class="ui huge blue header">数据集管理</h2>
<p class="am-lh-18">
数据是重要的生产要素,AI开发更是离不开数据;<br>
- 数据与模型代码的协同,可在项目中上传关联的数据集;<br>
- 数据存储免费,不限制文件大小;<br>
- 数据可共享,标注清洗过的公开数据集,用户可设置为公有数据,供社区用户下载;
</p>
<div class="am-mt-30 am-pt-20"></div>
<h2 class="ui huge header">使用数据集</h2>
<p class="am-lh-18">
数据集可以直接用于训练或者推理任务中<br>
创建任务时选择对应的数据集,启动任务执行环境(Docker)后,即可在Docker内访问到你的代码和数据,就像在你本地执行一样
</p>
</div>
</div>
</div><!-- end homenews -->
</div>
</div><!-- end segment -->

<!--组织-->
<div class="ui container homeorg">
<div class="ui stackable grid">
<div class="sixteen wide tablet four wide computer column homeorg-tit">
<h2>{{.page_recommend_org}}</h2>
<p><span class="ui text grey">{{.page_recommend_org_desc}}</span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p>
<a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a>
</div>
<div class="sixteen wide tablet twelve wide computer column">
<div class="ui stackable three column grid homeorg-list" id="recommendorg">
</div>
</div>
</div>
</div>
<div class="leftline01"></div>
</div>
<!--项目-->
<div class="ui container homepro">
<div class="leftline02"></div>
<div class="leftline02-2"></div>
<div class="ui center homepro-tit am-mb-20">
<h2>{{.page_recommend_repo}}</h2>
<p><span class="ui text grey">{{.page_recommend_repo_desc}}</span><a href="{{.RecommendURL}}">{{.page_recommend_repo_commit}}</a>{{.page_recommend_repo_go}}<a href="{{AppSubUrl}}/explore/">{{.page_recommend_repo_more}}</a></p>
</div>

<a name="third"></a>
<div class="ui basic tab active container am-mt-30 am-pt-30">
<h2 class="ui center aligned huge blue header am-pt-30">
AI流水线
<div class="sub header am-mt-10">提供集代码开发、数据管理、模型调试、推理和评测为一体的AI开发流水线</div>
</h2>
<div class="ui divider"></div>
<div class="ui centered grid">
<div class="fourteen wide column">
<div class="ui two column grid">
<div class="column">
<div class="ui small header">调试任务:</div>
<div class="ui bulleted list">
<div class="item">配置模型运行环境;</div>
<div class="item">可在线编辑和调试模型代码,并将改动更新至代码仓库;</div>
<div class="item">基于编辑好的脚本,开展模型评测任务;</div>
</div>
</div>
<div class="column">
<div class="ui small header">作业任务:</div>
<div class="ui bulleted list">
<div class="item">利用已配置好的模型运行环境;</div>
<div class="item">基于编辑好的脚本,一键运行,开展模型训练或模型推理任务;</div>
</div>
</div>
</div>
</div>
<div class="homepro-list">
<div class="swiper-wrapper" id="recommendrepo">
</div>
<div class="ui divider"></div>
<img class="ui centered image" src="/img/develop.svg">
<div class="swiper-pagination"></div>
</div>
</div>

<a name="fourth"></a>
<div class="ui basic tab active container am-mt-30 am-pt-30 i-env">
<h2 class="ui center aligned huge blue header am-pt-30">
协同开发环境
<div class="sub header am-mt-10">启智AI协作开发平台与传统git平台最大的不同就在于提供了面向AI开发的协同开发环境</div>
</h2>
<div class="ui four stackable cards am-mt-20">
<div class="card">
<div class="image">
<img src="/img/i-pic-01.svg">

<a name="fourth"></a>
<div class="ui container i-env">
<div class="ui center am-pb-30">
<div class="leftline03"></div>
<h2>{{.page_dev_env}}</h2>
<p><span class="ui text grey">{{.page_dev_env_desc}}</p>
</div>
<div class="ui four stackable cards">
<div class="card">
<div class="image">
<img src="/img/i-pic-01.svg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc_title}}</h3>
<div class="description">
{{.page_dev_env_desc_desc}}
</div>
<div class="content">
<h3 class="ui centered header">开发要素统一管理</h3>
<div class="description">
平台提供了AI开发四大要素:模型代码、数据集、模型和执行环境的统一管理
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-02.svg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc1_title}}</h3>
<div class="description">
{{.page_dev_env_desc1_desc}}
</div>
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-02.svg">
</div>
<div class="content">
<h3 class="ui centered header">数据协同与共享</h3>
<div class="description">
通过在项目中上传数据集,项目成员多人协作完成数据预处理;也可以通过将数据设置为公有数据集,与社区开发者共同建立更好的模型
</div>
</div>
<div class="image">
<img src="/img/i-pic-03.svg">
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-03.svg">
</div>
<div class="content">
<h3 class="ui centered header">模型管理与共享</h3>
<div class="description">
将模型与代码版本建立关联,可以基于代码历史版本,使用不同的方式调整模型,并将结果保存下来;训练好的模型可以开放共享,让更多人的使用模型测试并提出反馈
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc2_title}}</h3>
<div class="description">
{{.page_dev_env_desc2_desc}}
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-04.svg">
</div>
<div class="content">
<h3 class="ui centered header">一次配置,多次使用</h3>
<div class="description">
提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境
</div>
</div>
<div class="card">
<div class="image">
<img src="/img/i-pic-04.svg">
</div>
<div class="content">
<h3 class="ui centered small header">{{.page_dev_env_desc3_title}}</h3>
<div class="description">
{{.page_dev_env_desc3_desc}}
</div>
</div>
</div>
</div>
</div>

<a name="fifth"></a>
<div class="ui basic tab active container am-mt-30 am-pt-30">
<div class="ui very padded black inverted segment radius15">
<div class="ui stackable grid">
<div class="six wide column">
<img class="ui centered large image" src="/img/i-yunnao.svg">
</div>
<div class="ten wide column am-pt-30">
<h2 class="ui huge blue header">鹏城云脑开源协同</h2>
<p class="am-lh-18">
平台已经与鹏城云脑打通,可以利用鹏城云脑的丰富算力资源,完成AI开发任务<br>
鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 的GPU服务器和搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成<br>
开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等<br>
如果您的模型需要更多的计算资源,也可以单独申请<br>
</p>
{{if .IsSigned}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/dashboard">立即使用 </a><a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">单独申请</a>
{{else}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/user/login">立即使用 </a><a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">单独申请</a>
{{end}}
</div>
<a name="fifth"></a>
<div class="ui container">
<div class="ui very padded inverted segment radius15">
<div class="ui stackable grid">
<div class="six wide column">
<img class="ui centered large image" src="/img/i-yunnao.svg">
</div>
<div class="ten wide column am-pt-30">
<h2 class="ui grey inverted header">{{.page_dev_yunlao}}</h2>
<p class="am-lh-18 ui text grey">
{{.page_dev_yunlao_desc1}}<br>
{{.page_dev_yunlao_desc2}}<br>
{{.page_dev_yunlao_desc3}}<br>
{{.page_dev_yunlao_desc4}}<br>
</p>
{{if .IsSigned}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/dashboard">{{.page_use}}</a>
{{else}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/user/login">{{.page_use}}</a>
{{end}}
<a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">{{.page_dev_yunlao_apply}}</a>
</div>
</div>
</div>
<div class="am-mt-30"></div>

</div><!-- end railContent -->
</div>
<div class="am-mt-30"></div>
<script src="/self/js/jquery.min.js" type="text/javascript"></script>
<script src="/home/home.js?v={{MD5 AppVer}}" type="text/javascript"></script>

</div><!-- end explore -->
<script>
$('.menu .item')
.tab();
$('.ui.sticky')
.sticky({
context: '#railContent',
observeChanges: true,
})
.sticky('refresh');
</script>

{{template "base/footer" .}}

+ 5
- 4
templates/org/home.tmpl View File

@@ -20,10 +20,11 @@
</div>

<div class="ui container">
<div class="ui stackable grid">
{{template "org/navber" .}}
<div class="ui fourteen wide computer column">
{{template "org/navber" .}}
{{template "org/select_pro" .}}
<div class="ui stackable grid">
<div class="ui sixteen wide computer column">
<div class="ui mobile reversed stackable grid">
<div class="ui ten wide tablet eleven wide computer column">
{{if .CanCreateOrgRepo}}


+ 3
- 2
templates/org/member/members.tmpl View File

@@ -3,10 +3,11 @@
{{template "org/header" .}}
<div class="ui container">
{{template "base/alert" .}}
{{template "org/navber" .}}
<div class="ui stackable grid">
{{template "org/navber" .}}
<div class="ui fourteen wide computer column list">
<div class="ui sixteen wide computer column list">
{{ range .Members}}
<div class="item ui grid">
<div class="ui two wide column">


+ 37
- 5
templates/org/navber.tmpl View File

@@ -1,4 +1,4 @@
<div class="tablet only mobile only sixteen wide mobile sixteen wide tablet column row">
<!-- <div class="tablet only mobile only sixteen wide mobile sixteen wide tablet column row">
<div class="ui secondary pointing tabular top attached borderless menu navbar">
<a class="{{if $.PageIsOrgHome}}active{{end}} item" href="{{.HomeLink}}">
{{svg "octicon-home" 16}}&nbsp;{{$.i18n.Tr "org.home"}}
@@ -12,10 +12,10 @@
</a>
{{end}}
</div>
</div>
</div> -->
<!--平板、移动端-->
<div class="computer only two wide computer column">
<!-- <div class="computer only two wide computer column">
<div class="ui grid">
<div class="sixteen wide column ui secondary sticky pointing tabular vertical menu">
{{with .Org}}
@@ -33,5 +33,37 @@
{{end}}
</div>
</div>
</div>
<!--电脑、宽屏-->
</div> -->
<!--电脑、宽屏-->
<style>
.dis{
margin-bottom: 10px;
}
.active{
color:#0366D6 !important;
}
.mleft{
margin-left: 30% !important;
}
.mbom{
margin-bottom: 10px !important;
}
</style>

<div class="row">
<div class="ui secondary pointing tabular top attached borderless menu navbar mbom">
{{with .Org}}
<a class="{{if $.PageIsOrgHome}}active{{end}} item mleft" href="{{.HomeLink}}">
{{svg "octicon-home" 16}}&nbsp;{{$.i18n.Tr "org.home"}}
</a>
{{end}}
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members">
{{svg "octicon-organization" 16}}&nbsp;{{$.i18n.Tr "org.people"}}
</a>
{{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}}
<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams">
{{svg "octicon-jersey" 16}}&nbsp;{{$.i18n.Tr "org.teams"}}
</a>
{{end}}
</div>
</div>

+ 319
- 0
templates/org/select_pro.tmpl View File

@@ -0,0 +1,319 @@
<style>
.text-right{
float:right !important;
}
.header{
font-weight:bold;
font-size: 18px;
font-family: SourceHanSansSC-medium;
}
.cor{
color:#0366D6 !important;
}
.header_card{
/* color:#003A8C !important; */
color:#0366D6 !important;
margin: 10px 0 0px 0;
height: 25px;
}
.marg{
margin: 0 5px !important;
}

.content_list{
max-height: 130px;
overflow: auto;
}
.Relist{
color:#0366D6 !important;
}
.descript_height{
color: #101010 !important;
margin: 10px 0;
height: 40px !important;
word-break:break-all;
line-height: 20px;
overflow: hidden;
/* overflow: hidden!important;
word-wrap:break-word!important; */


}

.tags_height{
height: 30px !important;
}
.full_height{
height: 100%;
}
.omit{
overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
/deep/ ui.checkbox input[type=checkbox]::after{
border: 1px solid #0366D6 !important;
}
.nowrap-2 {
/* height: 2.837em; */
/* line-height: 1.4285em; */
overflow: hidden;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}


</style>
<div class="ui stackable grid">
<div style="width: 100%;margin:15px 0;">
{{if .tags}}
<span class="header">
精选项目
</span>
<!-- {{.IsOrganizationOwner}} -->
{{if .IsOrganizationOwner}}
<a class="text-right" id="model" onclick="showcreate()" >{{svg "octicon-gear" 16}}自定义</a>
{{end}}
{{end}}
</div>
<div style="width: 100%;">
{{ range .tags}}
{{if eq .TagName "精选项目"}}
<div class="ui three cards" style="margin-bottom: 10px;">
{{ range .RepoList}}
<div class="card" >
<div class="extra full_height cor" >
<div class=" header header_card omit" >
<a class="header_card image poping up " href="{{.Link}}" data-content="{{.Name}}" data-position="top left" data-variation="tiny inverted"> {{.Name}}</a>
</div>
<div class='content descript_height nowrap-2'>
{{.Description}}
</div>
<div class="content " >
{{if .Topics }}
<div class=" tags " style="position: relative;">
{{range .Topics}}
{{if ne . "" }}<a style="max-width:100%;margin: 5px 0;display:inline-flex;" href="{{AppSubUrl}}/explore/repos?q={{.}}&topic={{$.Topic}}" ><span class="ui small label topic omit" >{{.}}</span></a>{{end}}
{{end}}
</div>
{{end}}
</div>
</div>
<div class=" extra " style="color:#888888;border-top: none !important">
<div class="ui mini right compact marg" >
<a class="item marg ">
{{svg "octicon-eye" 16}} {{.NumWatches}}
</a>
<a class="item marg">
{{svg "octicon-star" 16}} {{.NumStars}}
</a>
<a class="item marg">
{{svg "octicon-git-branch" 16}} {{.NumForks}}
</a>
</div>
</div>
</div>
{{end}}
</div>
{{end}}
{{end}}

</div>

</div>

<div class="ui modal">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">自定义精选项目</h4>
</div>
<div class="content content-padding" style="color: black;">
<p>最多可选9个公开项目</p>
<div class="ui search" >
<div class="ui input" style="width: 100%;">
<input type="text" id = 'search_selectPro' placeholder="Search ..." value = '' oninput="search()">
</div>
</div>
<div style="margin: 10px ;">
<div id ='org_list' style="margin-bottom: 20px;"class="content_list" >

</div>
</div>
<p id='recommend'></p>
<div class="inline field" style="margin-left: 37%;">
<div class="actions">
<button id="submitId" type="button" class="ui create_train_job green deny button" onclick="saveSeletedPro(1)">
{{.i18n.Tr "explore.save"}}
</button>
<button class="ui button cancel" >{{.i18n.Tr "explore.cancel"}}</button>
</div>
</div>
</div>

</div>

<script>
var data;
var filterData=[];
var num=0;

function showcreate(obj){
document.getElementById("search_selectPro").value=''
$('.ui.modal')
.modal({
centered: false,
onShow:function(){
$("#org_list").empty()
getPro(1)
},
onHide:function(){
}
})
.modal('show')
}
function getPro(typeTag){

$.ajax({
type:"GET",
url:"/org/{{.Org.Name}}/org_tag/repo_list?tagId="+typeTag,
dataType:"json",
async:false,
success:function(json){
data = json.data;
var n_length = data.length
pro_html = getHTML(data)
$("#org_list").append(pro_html)
// console.log('原始',data)
checkedNum(0)
}
});
}
function getHTML(data){
let pro_html=''
for (let i=0;i<data.length;i++){
if (data[i].Selected==true){
console.log("data[i]:",data[i])
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = " ${i}" checked="" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected=${data[i].Selected} > <label class='omit image poping up' data-content=${data[i].RepoName}  data-position="top left " data-variation="mini"> ${data[i].RepoName}</label></div>`
pro_html += '</div>'
}
else{
pro_html += `<div class="ui checkbox" style="width: 33%;margin-bottom:10px" > <input type="checkbox" id = "${i}" onclick="checkedNum(${i})" class="Relist" name ='select_pro_name' data-repoid="${data[i].RepoID}" data-reponame="${data[i].RepoName}" data-selected= ${data[i].Selected}> <label class='omit image poping up' data-content=${data[i].RepoName}  data-position="top left " data-variation="mini"> ${data[i].RepoName} </label></div>`
pro_html += '</div>'
}
}
return pro_html
}
function saveSeletedPro(typeTag){
var saveData=[];
$('input[name="select_pro_name"]:checked').each(function(){
console.log('值',this.dataset.repoid)

saveData.push(parseInt(this.dataset.repoid));
})
if(saveData.length>9){
alert("最多可选9个,保存失败")
return
}
// saveData = getSelecteDataID();
// console.log("数据:",saveData)
$.ajax({
type:"POST",
url:"/org/{{.Org.Name}}/org_tag/repo_submit?tagId="+typeTag,
contentType:'application/json',
dataType:"json",
async:false,
data:JSON.stringify({'repoList':saveData
}),
success:function(res){
console.log('保存成功');
location.reload()

}
});
}

function getSelecteData(){
var selectedData=[];
$('input[name="select_pro_name"]:checked').each(function(){
// console.log(this)
// console.log('值',this.dataset.selected)

selectedData.push({"RepoID":parseInt(this.dataset.repoid),"RepoName":this.dataset.reponame,"Selected":JSON.parse(this.dataset.selected)});
})
return selectedData
}
function search(){
var selectedData = getSelecteData();
var searchValue = document.getElementById("search_selectPro").value;
filterData=[];
console.log("searchValue:",searchValue)
for (let i=0;i<data.length;i++){
var isInclude=false;
if(data[i].RepoName.toLowerCase().includes(searchValue.toLowerCase())){
filterData.push(data[i])
}
}
console.log("选中的值:",selectedData)
console.log("筛选包括选中的值:",filterData)
var showData=[];
for(i=0;i<selectedData.length;i++){
filterData =filterData.filter((item)=>{
return item.RepoID!=selectedData[i].RepoID
});
}
console.log("筛选后不包括选中的值:",filterData)
$("#org_list").empty()
if(searchValue!=""){
if (filterData.length!=0){
var pro_html = getHTML(selectedData);
console.log("selectedData_pro_html:",pro_html)
$("#org_list").append(pro_html)
pro_html= getHTML(filterData);
$("#org_list").append(pro_html)
}else{
var pro_html = getHTML(selectedData);
$("#org_list").append(pro_html)
}
}else{
var pro_html = getHTML(data);
$("#org_list").append(pro_html)
}
}

function checkedNum(id){

num=0;
var inputs = document.getElementsByName("select_pro_name")
for (var i=0;i<inputs.length;i++){
if(inputs[i].checked){
num++
if(num>9){
document.getElementById(id).checked=false
alert("选择超过9个,请重新选择!")
return
}
}
}

var show_num = 9-num;
document.getElementById("recommend").innerHTML="还能推荐"+show_num+"个"

}

</script>

+ 3
- 3
templates/org/team/teams.tmpl View File

@@ -3,12 +3,12 @@
{{template "org/header" .}}
<div class="ui container">
{{template "base/alert" .}}
{{template "org/navber" .}}
<div class="ui stackable grid">
{{template "org/navber" .}}
<div class="ui fourteen wide computer column list">
<div class="ui sixteen wide computer column list">
<div class="ui two column grid">
{{range .Teams}}
<div class="column">


+ 20
- 3
templates/repo/cloudbrain/new.tmpl View File

@@ -93,6 +93,14 @@
display: none;
}

.icons{
/* position: absolute !important;
right: 150px;
top: 14px;
z-index: 2; */
}


</style>

<div id="mask">
@@ -182,9 +190,10 @@
</select>
</div>

<div class="inline required field">
<div class="inline required field" style="position: relative;">
<label>镜像</label>
<input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" required autofocus maxlength="254">
<i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i>
<datalist class="ui search" id="cloudbrain_image" style='width:385px;' name="image">
{{range .images}}
<option name="image" value="{{.Place}}">{{.PlaceView}}</option>
@@ -261,9 +270,17 @@
<script>
let form = document.getElementById('form_id');

$('#messageInfo').css('display','none')
let inputs = document.querySelectorAll('input[list]');
inputs[0].addEventListener('change', function() {
$(".icon.icons").css("visibility","visible")
});

$('#messageInfo').css('display','none')
function clearValue(){
context=inputs[0]
context.value=''
$(".icon.icons").css("visibility","hidden")
}
form.onsubmit = function(e){
let value_task = $("input[name='job_name']").val()
let value_image = $("input[name='image']").val()


+ 147
- 46
templates/repo/debugjob/index.tmpl View File

@@ -202,14 +202,17 @@
<div class="rect5"></div>
</div>
</div>
<!-- 提示框 -->
<div class="alert"></div>

<div class="alert"></div>
<div class="repository release dataset-list view">
{{template "repo/header" .}}
{{template "base/alert" .}}
<!-- 提示框 -->
<!-- 列表容器 -->
<div class="ui container">
<div class="ui two column stackable grid ">
<div class="ui two column stackable grid">
<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
@@ -282,7 +285,7 @@
<div class="row">
<!-- 任务名 -->
<div class="four wide column">
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;">
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;">
<span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span>
</a>
</div>
@@ -315,34 +318,49 @@
</a>
{{end}} -->
<!-- 调试 -->
{{if .CanDebug}}
{{if eq .ComputeResource "CPU/GPU"}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
<form id="debugAgainForm-{{.JobID}}">
{{$.CsrfTokenHtml}}
{{if .CanDebug}}
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}}
<a style="margin: 0 1rem;" id="model-debug-{{.JobID}}" class='ui basic {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick='debugAgain("{{.JobID}}","{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/")'>
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}} disabled {{else}}blue {{end}}button' onclick='debugAgain("{{.JobID}}","{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/")'>
{{$.i18n.Tr "repo.debug_again"}}
</a>
{{end}}
{{else}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug_again"}}
</a>
{{end}}
{{end}}
{{else}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug"}}
</a>
{{end}}
</form>
<!-- 停止 -->
<form id="stopForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;">
<form id="stopForm-{{.JobID}}" style="margin-left:-1px;">
{{$.CsrfTokenHtml}}
{{if .CanDel}}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{if eq .ComputeResource "CPU/GPU" }}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' onclick='stopDebug("{{.JobID}}","{{$.RepoLink}}/cloudbrain/{{.JobID}}/stop")'>
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' onclick='stopDebug("{{.JobID}}","{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/stop")'>
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
{{else}}
<a class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
<input type="hidden" name="debugListType" value="all">
</form>
<!-- 删除 -->
<form id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post">
@@ -384,6 +402,13 @@
<a class="ui basic disabled button">{{$.i18n.Tr "repo.download"}}</a>
{{end}}
</div>
{{if and (ne .JobType "DEBUG") (eq .Cloudbrain.Type 0)}}
<div class="item" style="padding: 0 !important;">
<a class="ui basic blue button" href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/rate" target="_blank">
评分
</a>
</div>
{{end}}
</div>
</div>
@@ -463,10 +488,21 @@

<script>
// 调试和评分新开窗口
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
let url={{.RepoLink}}
let getParam=location.search.split('?debugListType=').pop()
let getParam=getQueryVariable('debugListType')
let dropdownValue = getParam==='all'||getParam==='' ? '全部' : getParam
localStorage.setItem('all',location.href)
function getQueryVariable(variable)
{
let query = window.location.search.substring(1);
let vars = query.split("&");
for (let i=0;i<vars.length;i++) {
let pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
function stop(obj) {
if (obj.style.color != "rgb(204, 204, 204)") {
obj.target = '_blank'
@@ -489,6 +525,7 @@
onApprove: function() {
document.getElementById(delId).submit()
flag = true
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
},
onHidden: function() {
if (flag == false) {
@@ -499,7 +536,68 @@
.modal('show')
}
}
function debugAgain(JobID,debugUrl){
if($('#' + JobID+ '-text').text()==="RUNNING"){
window.open(debugUrl+'debug')
}else{
$.ajax({
type:"POST",
url:debugUrl+'restart',
data:$('#debugAgainForm-'+JobID).serialize(),
success:function(res){
if(res.result_code==="0"){
if(res.job_id!==JobID){
location.reload()
}else{
$('#' + JobID+'-icon').removeClass().addClass(res.status)
$('#' + JobID+ '-text').text(res.status)
$('#model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#model-delete-'+JobID).removeClass('blue').addClass('disabled')
$('#model-debug-'+JobID).text("调试").css("margin","0 1rem")
}
}else{
$('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut();
}
},
error :function(res){
console.log(res)

}
})
}
}
function stopDebug(JobID,stopUrl){
$.ajax({
type:"POST",
url:stopUrl,
data:$('#stopForm-'+JobID).serialize(),
success:function(res){
if(res.result_code==="0"){
$('#' + JobID+'-icon').removeClass().addClass(res.status)
$('#' + JobID+ '-text').text(res.status)
if(res.status==="STOPPED"){
$('#model-debug-'+JobID).removeClass('disabled').addClass('blue').text("再次调试").css("margin","0")
$('#model-image-'+JobID).removeClass('blue').addClass('disabled')
$('#stop-model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#model-delete-'+JobID).removeClass('disabled').addClass('blue')
}
else{
$('#model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#stop-model-debug-'+JobID).removeClass('blue').addClass('disabled')
}
}else{
$('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut();
}
},
error :function(res){
console.log(res)

}
})

}
// 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus);
@@ -508,8 +606,9 @@
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const computeResource = job.dataset.resource
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED']
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED']
if (initArray.includes(job.textContent.trim())) {
return
}
const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain'
@@ -521,32 +620,30 @@
$('#' + jobID+ '-text').text(status)
}
if(status==="RUNNING"){
$('#model-debug-'+jobID).removeClass('disabled')
$('#model-debug-'+jobID).addClass('blue')
$('#model-image-'+jobID).removeClass('disabled')
$('#model-image-'+jobID).addClass('blue')
$('#model-debug-'+jobID).removeClass('disabled').addClass('blue').text('调试').css("margin","0 1rem")
$('#model-image-'+jobID).removeClass('disabled').addClass('blue')
}
if(status!=="RUNNING"){
$('#model-debug-'+jobID).removeClass('blue')
$('#model-debug-'+jobID).addClass('disabled')
$('#model-image-'+jobID).removeClass('blue')
$('#model-image-'+jobID).addClass('disabled')

// $('#model-debug-'+jobID).removeClass('blue')
// $('#model-debug-'+jobID).addClass('disabled')
$('#model-image-'+jobID).removeClass('blue').addClass('disabled')
}
if(["CREATING","STOPPING","WAITING","STARTING"].includes(status)){
$('#model-debug-'+jobID).removeClass('blue').addClass('disabled')
}
if(['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED'].includes(status)){
$('#model-debug-'+jobID).removeClass('disabled').addClass('blue').text('再次调试').css("margin","0")
}
if(["RUNNING","WAITING"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('disabled')
$('#stop-model-debug-'+jobID).addClass('blue')
$('#stop-model-debug-'+jobID).removeClass('disabled').addClass('blue')
}
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('blue')
$('#stop-model-debug-'+jobID).addClass('disabled')
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED","SUCCEEDED"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('blue').addClass('disabled')
}
if(status==="STOPPED" || status==="FAILED"|| status==="START_FAILED"){
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('blue')
$('#model-delete-'+jobID).removeClass('disabled').addClass('blue')
}else{
$('#model-delete-'+jobID).removeClass('blue')
$('#model-delete-'+jobID).addClass('disabled')
$('#model-delete-'+jobID).removeClass('blue').addClass('disabled')
}
}).fail(function(err) {
console.log(err);
@@ -554,6 +651,7 @@
});
};
$(document).ready(function(){
dropdownValue = dropdownValue==="CPU%2FGPU"? 'CPU/GPU' : dropdownValue
$('.default.text').text(dropdownValue)
$('.ui.dropdown')
.dropdown({
@@ -564,6 +662,12 @@
location.href = `${url}/debugjob?debugListType=${value}`
}
})
$('.message .close')
.on('click', function() {
$(this)
.closest('.message')
.transition('fade')
})
})
@@ -601,7 +705,6 @@
// 显示弹窗,弹出相应的信息
function showmask() {
var image_tag = !$('#image_tag').val()
console.log("image_tag",image_tag)
if(image_tag){
return
}
@@ -612,8 +715,6 @@
var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; 
var json1 = JSON.parse(responseText)
$('#mask').css('display', 'none')
parent.location.href

if (json1.result_code === "0") {
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
} else {


+ 3
- 3
templates/repo/header.tmpl View File

@@ -51,7 +51,7 @@
</div>
{{if not .IsBeingCreated}}
<div class="repo-buttons">
<form method="post" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}">
<form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}">
{{$.CsrfTokenHtml}}
<div class="ui labeled button" tabindex="0">
<button type="submit" class="ui compact basic button">
@@ -62,7 +62,7 @@
</a>
</div>
</form>
<form method="post" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}">
<form method="post" style="margin: 0;" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}">
{{$.CsrfTokenHtml}}
<div class="ui labeled button" tabindex="0">
<button type="submit" class="ui compact basic button">
@@ -181,4 +181,4 @@
</div>


<script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
<script src="{{StaticUrlPrefix}}/js/jquery.js?v={{MD5 AppVer}}"></script>

+ 1
- 0
templates/repo/issue/list.tmpl View File

@@ -4,6 +4,7 @@
}
.ovfl{
overflow-y:hidden !important;
min-width: 140px!important;
}
</style>
{{template "base/head" .}}


+ 6
- 24
templates/repo/modelarts/trainjob/index.tmpl View File

@@ -121,7 +121,7 @@
</div>
<!-- 任务运行时间 -->
<div class="two wide column text center padding0">
<span style="font-size: 12px;" id="duration-{{.JobID}}"></span>
<span style="font-size: 12px;" id="duration-{{.JobID}}">{{.TrainJobDuration}}</span>
</div>
<!-- 计算资源 -->
<div class="two wide column text center padding0">
@@ -253,35 +253,18 @@
}
}

function loadJobDuration() {
$(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const versionname = job.dataset.version
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
console.log(data)
const duration = data.JobDuration
const jobID = data.JobID
$('#duration-'+jobID).text(duration)
})
})
}
$(document).ready(loadJobDuration);
// 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus);
function loadJobStatus() {
$(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const jobID = job.dataset.jobid
const repoPath = job.dataset.repopath
const versionname = job.dataset.version
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
return
const status_text = $(`#${jobID}-text`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'].includes(status_text)){
return
}

$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
const jobID = data.JobID
const status = data.JobStatus
@@ -329,7 +312,6 @@
}
}
function stopVersion(version_name,jobID){
const url = '/api/v1/repos/{{$.RepoRelPath}}/modelarts/train-job/'+jobID+'/stop_version'
$.post(url,{version_name:version_name},(data)=>{
if(data.StatusOK===0){


+ 142
- 8
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -161,6 +161,15 @@ td, th {
padding-top: 0.5rem ;
}
</style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="ui container">
@@ -186,6 +195,12 @@ td, th {
<span class="accordion-panel-title-content">
<span>
<div style="float: right;">
{{$.CsrfTokenHtml}}
{{if .CanModify}}
<a class="ti-action-menu-item" onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{else}}
<a class="ti-action-menu-item disabled">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{end}}
{{$.CsrfTokenHtml}}
{{if .CanModify}}
<a class="ti-action-menu-item" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a>
@@ -446,11 +461,66 @@ td, th {
</div>
</div>
</div>
<!-- 创建模型 -->
<div id="newmodel">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">导入新模型</h4>
</div>
<div class="content content-padding">
<form id="formId" method="POST" class="ui form">
<div class="ui error message">
</div>
{{$.CsrfTokenHtml}}
<input type="hidden" name="trainTaskCreate" value="true">

<div class="two inline fields ">
<div class="required ten wide field">
<label style="margin-left: -23px;">选择训练任务</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input class="width83" id="JobName" readonly required>
</div>
<div class="required six widde field">
<label>版本</label>
<input class="width70" id="VersionName" name="VersionName" readonly required>
</div>
</div>
<div class="required inline field" id="modelname">
<label>模型名称</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>
<div class="inline field">
<label>模型标签</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea>
</div>
<div class="inline field" style="margin-left: 75px;">
<button onclick="createModel()" id="submitId" type="button" class="ui create_train_job green button" style="position: absolute;">
{{.i18n.Tr "repo.model.manage.sava_model"}}
</button>
</div>
</form>
<div class="actions" style="display: inline-block;margin-left: 180px;">
<button class="ui button cancel" >{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div>
</div>
</div>
</div>
{{template "base/footer" .}}

<script>
console.log({{.version_list_task}})
$('.menu .item').tab()

$(document).ready(function(){
@@ -480,7 +550,61 @@ td, th {
}
let timeid = window.setInterval(loadJobStatus, 30000);
$(document).ready(loadJobStatus);
function showcreate(obj){
$('.ui.modal.second')
.modal({
centered: false,
onShow:function(){
$('input[name="Version"]').addClass('model_disabled')
// $('input[name="JobId"]').text(obj.JobName)
$('#JobName').val(obj.JobName).addClass('model_disabled')
$('input[name="JobId"]').val(obj.JobID)
$('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled')
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
createModelName()
},
onHide:function(){
document.getElementById("formId").reset();
$('.ui.dimmer').css({"background-color":""})
$('.ui.error.message').text()
$('.ui.error.message').css('display','none')
}
})
.modal('show')
}
function createModel(){
let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model`
let data = $("#formId").serialize()
$("#mask").css({"display":"block","z-index":"9999"})
$.ajax({
url:url_href,
type:'POST',
data:data,
success:function(res){
location.href=`/${userName}/${repoPath}/modelmanage/show_model`
$('.ui.modal.second').modal('hide')
},
error: function(xhr){
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
$('.ui.error.message').text(xhr.responseText)
$('.ui.error.message').css('display','block')
},
complete:function(xhr){
$("#mask").css({"display":"none","z-index":"1"})
}
})
}
function createModelName(){
let repoName = location.pathname.split('/')[2]
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4)
$('#name').val(modelName)
$('#version').val("0.0.1")
}
function renderSize(value){
if(null==value||value==''){
return "0 Bytes";
@@ -495,14 +619,19 @@ td, th {
}
function loadJobStatus() {
$(".ui.accordion.border-according").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const versionname = job.dataset.version
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
return
// ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED']
// if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
// || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
// || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
// return
// }
let status = $(`#${versionname}-status-span`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'].includes(status)){
return
}
let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED"]
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
@@ -663,7 +792,12 @@ td, th {
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
if(data.Dirs[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>"

html += "<td class='text right age three wide'>"


+ 18
- 6
templates/repo/modelmanage/index.tmpl View File

@@ -17,16 +17,30 @@
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<!-- 列表容器 -->
<div class="ui container active loader" id="loadContainer">
<div class="ui container {{if ne $.MODEL_COUNT 0}}active loader {{end}}" id="loadContainer">
{{template "base/alert" .}}
<div class="ui two column stackable grid" style="display: none;">
<div class="ui two column stackable grid">
<div class="column"></div>
<div class="column right aligned">
<!-- -->
<a class="ui button {{if .Permission.CanWrite $.UnitTypeCloudBrain}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a>
</div>
</div>

{{if eq $.MODEL_COUNT 0}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过模型</div>
<div class="bgtask-content">
{{if $.RepoIsEmpty}}
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div>
{{end}}
{{if eq $.TRAIN_COUNT 0}}
<div class="bgtask-content-txt">训练任务:您还没创建过训练任务,请先创建<a href="{{.RepoLink}}/modelarts/train-job">训练任务</a>。</div>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>
</div>
</div>
{{else}}
<!-- 中下列表展示区 -->
<div class="ui grid" style="display: none;">
<div class="row" style="padding-top: 0;">
@@ -38,6 +52,7 @@
</div>
</div>
</div>
{{end}}

</div>

@@ -89,7 +104,6 @@
<div class="menu" id="job-name">
</div>
</div>
</div>
<div class="required six widde field">
<label>版本</label>
@@ -103,7 +117,6 @@
</div>
</div>
</div>

<div class="required inline field" id="modelname">
<label>模型名称</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
@@ -141,7 +154,6 @@
<script>
let repolink = {{.RepoLink}}
let repoId = {{$repository}}
let url_href = window.location.pathname.split('show_model')[0] + 'create_model'
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config;
$('input[name="_csrf"]').val(csrf)



+ 265
- 66
templates/repo/modelmanage/showinfo.tmpl View File

@@ -69,7 +69,7 @@
<!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> -->
<div class="ui breadcrumb">
<a class="section" href="{{$.RepoLink}}/modelmanage/show_model">
模型管理
{{$.i18n.Tr "repo.model.manage.model_manage"}}
</a>
<div class="divider"> / </div>
<div class="active section">{{.name}}</div>
@@ -78,67 +78,121 @@
</select>
</h4>
<div id="showInfo" style="border:1px solid #e2e2e2;padding: 20px 60px;margin-top:24px">
<div class="half-table">
<span class="model_header_text">基本信息</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">模型名称</td>
<td class="ti-text-form-content word-elipsis"><span id="ModelName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">版本</td>
<td class="ti-text-form-content word-elipsis"><span id="Version" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">标签</td>
<td class="ti-text-form-content">
<div id="Label" style="overflow: hidden;width: 95%;">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second">{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first">
<div class="half-table">
<span class="model_header_text">基本信息</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.model_name"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="ModelName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Version" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.migrate_items_labels"}}</td>
<td class="ti-text-form-content">
<div id="Label" style="overflow: hidden;width: 95%;">
</div>
</div>

</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">大小</td>
<td class="ti-text-form-content word-elipsis"><span id="Size" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">创建时间</td>
<td class="ti-text-form-content word-elipsis"><span id="CreateTime" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">模型描述</td>
<td class="ti-text-form-content" ><div id="edit-td" style="display:flex"><span id="Description" title="" class="iword-elipsis"></span><i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div></td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.model_size"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Size" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.createtime"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="CreateTime" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.description"}}</td>
<td class="ti-text-form-content" >
<div id="edit-td" style="display:flex">
<span id="Description" title="" class="iword-elipsis"></span>
<i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></i>
</div>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.code_version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="CodeBranch" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.start_file"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="BootFile" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="DatasetName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Parameters" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="EngineName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.standard"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="FlavorName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.compute_node"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="WorkServerNumber" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div class="half-table">
<span class="model_header_text">{{$.i18n.Tr "repo.model.manage.model_accuracy"}}</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Accuracy"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">F1</td>
<td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Precision"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Recall"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div style="clear: both;"></div>
</div>
<div class="half-table">
<span class="model_header_text">模型精度</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">准确率</td>
<td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">F1</td>
<td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">精确率</td>
<td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">召回率</td>
<td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td>
</tr>
</tbody>
</table>
<div class="ui tab" data-tab="second">
<input type="hidden" name="model" value="-1">
<input type="hidden" name="modelback" value="-1">
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb'>
<div class="active section"></div>
<div class="divider"> / </div>

</div>
<div id="dir_list">
</div>
</div>
<div style="clear: both;"></div>
</div>
</div>
</div>
@@ -146,6 +200,9 @@
<script>
let url = location.href.split('show_model')[0]
let ID = location.search.split('?name=').pop()
$(document).ready(function(){
$('.secondary.menu .item').tab();
});
$(document).ready(loadInfo);
function changeInfo(version){
$.get(`${url}show_model_info_api?name=${ID}`,(data)=>{
@@ -155,7 +212,9 @@ function changeInfo(version){
let returnArray = []
returnArray = transObj(versionData)
let [initObj,initModelAcc,id] = returnArray
editorCancel('','')
renderInfo(initObj,initModelAcc,id)
loadModelFile(versionData[0].ID,versionData[0].Version,'','','init')
})
}
function loadInfo(){
@@ -172,11 +231,17 @@ function loadInfo(){
returnArray = transObj(data)
let [initObj,initModelAcc,id] = returnArray
renderInfo(initObj,initModelAcc,id)
loadModelFile(data[0].ID,data[0].Version,'','','init')
})
}
function transObj(data){
let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy} = data[0]
let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy,CodeBranch,CodeCommitID,TrainTaskInfo} = data[0]
let modelAcc = JSON.parse(Accuracy)
TrainTaskInfo = JSON.parse(TrainTaskInfo)
// Parameters = JSON.parse(Parameters)
let {Parameters,EngineName} = TrainTaskInfo
Parameters = JSON.parse(Parameters)
Parameters = Parameters.parameter.length === 0 ? '--':Parameters.parameter
let size = tranSize(Size)
let time = transTime(CreatedUnix)
let initObj = {
@@ -186,6 +251,15 @@ function transObj(data){
Size:size,
CreateTime:time,
Description:Description || '--',
CodeBranch:CodeBranch || '--',
CodeCommitID:CodeCommitID || '--',
BootFile:TrainTaskInfo.BootFile || '--',
DatasetName:TrainTaskInfo.DatasetName || '--',
Parameters:TrainTaskInfo.Parameters || '--',
FlavorName:TrainTaskInfo.FlavorName || '--',
WorkServerNumber:TrainTaskInfo.WorkServerNumber || '--',
Parameters:Parameters,
EngineName:EngineName,
}
let initModelAcc = {
Accuracy: modelAcc.Accuracy || '--',
@@ -221,15 +295,16 @@ function tranSize(value){
function editorFn(context){
let id= context.dataset.id
let text = context.dataset.desc
console.log(id,text)
$('#edit-td').replaceWith("<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;' id='edit-text'>"+text+"</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure(\"" + text + "\",\"" + id + "\")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel(\"" + text + "\",\"" + id + "\")'></i></div>");
let textValue = text.replace(/enter;/g,'\r\n')
$('#edit-td').replaceWith(`<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;white-space: nowrap;' id='edit-text'>${textValue}</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure("${text}","${id}")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel("${text}","${id}")'></i></div>`);
}
function editorCancel(text,id){
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${text}" class="iword-elipsis">${text}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
let objkey = text.replace(/enter;/g,'\r\n')
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${objkey}" class="iword-elipsis">${objkey}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
}
function editorSure(text,id){
let description=$('#textarea-value').val()
let sourcetext = $('#textarea-value').val().replace(/\n/g,'enter;')
let data = {
ID:id,
Description:description
@@ -239,16 +314,17 @@ function editorSure(text,id){
type:'PUT',
data:data
}).done((res)=>{
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${description}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${sourcetext}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
})
}
function renderInfo(obj,accObj,id){
for(let key in obj){
if(key==="Description"){
let descriptionText=obj[key].replace(/\r\n|\n/g,'enter;')
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
$('#edit-pencil').attr("data-id",id)
$('#edit-pencil').attr("data-desc",obj[key])
$('#edit-pencil').attr("data-desc",descriptionText)
}
else if(key==="Label"){
$('#Label').empty()
@@ -264,6 +340,25 @@ function renderInfo(obj,accObj,id){
$('#Label').append(html)
}
}
else if(key==="CodeCommitID"){
let codeCommit = obj[key].slice(0,10)
let html = `<a style="margin-left:1rem" class="ui label" title="${codeCommit}">${codeCommit}</a>`
$('#CodeBranch').append(html)

}
else if(key==="Parameters"){
if(obj[key]==='--'){
$(`#${key}`).text(obj[key])
}else{
const parameterArray = obj[key].map(element => {
let labelValue = `${element.label}=${element.value}`
return labelValue
});
const parameter = parameterArray.join('; ')
$(`#${key}`).text(parameter)
$(`#${key}`).attr("title",parameter)
}
}
else{
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
@@ -276,4 +371,108 @@ function renderInfo(obj,accObj,id){
}
}

function loadModelFile(ID,version_name,parents,filename,init){
$.get(`${url}query_onelevel_modelfile?ID=${ID}&parentDir=${parents}`, (data) => {
$('#dir_list').empty()
renderDir(data,ID,version_name)
if(init==="init"){
$('input[name=model]').val("")
$('input[name=modelback]').val(version_name)
$('#file_breadcrumb').empty()
let htmlBread = ""
htmlBread += `<div class='active section'>${version_name}</div>`
htmlBread += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBread)
}else{
renderBrend(ID,version_name,parents,filename,init)
}
})
}
function renderSize(value){
if(null==value||value==''){
return "0 Bytes";
}
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
var index=0;
var srcsize = parseFloat(value);
index=Math.floor(Math.log(srcsize)/Math.log(1024));
var size =srcsize/Math.pow(1024,index);
size=size.toFixed(2);//保留的小数位数
return size+unitArr[index];
}

function renderBrend(ID,version_name,parents,filename,init){
if(init=="folder"){
let htmlBrend = ""
let sectionName=$('#file_breadcrumb .active.section').text()
let parents1 = $('input[name=model]').val()
let filename1 = $('input[name=modelback]').val()
if(parents1===""){
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','','init')">${sectionName}</a>`)
}else{
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','${filename1}')">${sectionName}</a>`)
}
htmlBrend += `<div class='active section'>${filename}</div>`
htmlBrend += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBrend)
$('input[name=model]').val(parents)
$('input[name=modelback]').val(filename)
}else{
$('input[name=model]').val(parents)
$('input[name=modelbac]').val(filename)
$('#file_breadcrumb a.section:contains(${filename})').nextAll().remove()
$('#file_breadcrumb a.section:contains(${filename})').replaceWith(`<div class='active section'>${filename}</div>`)
$('#file_breadcrumb div.section:contains(${filename})').append("<div class='divider'> / </div>")
}
}
function renderDir(data,ID,version_name){
let html=""
html += "<div class='ui grid' style='margin:0;'>"
html += "<div class='row' style='padding: 0;'>"
html += "<div class='ui sixteen wide column' style='padding:1rem;'>"
html += "<div class='dir list'>"
html += "<table id='repo-files-table' class='ui single line table pad20'>"
html += '<tbody>'
for(let i=0;i<data.length;i++){
let dirs_size = renderSize(data[i].Size)
html += "<tr>"
html += "<td class='name six wid'>"
html += "<span class='truncate'>"
html += "<span class='octicon octicon-file-directory'>"
html += "</span>"
if(data[i].IsDir){
html += `<a onclick="loadModelFile('${ID}','${version_name}','${data[i].ParenDir}','${data[i].FileName}','folder')">`
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}else{
html += `<a href="${url}${ID}/downloadsingle?parentDir=${data[i].ParenDir}&fileName=${data[i].FileName}">`
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}
html += '</a>'
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
if(data[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>"

html += "<td class='text right age three wide'>"
html += "<span class='truncate has-emoji'>" + data[i].ModTime + "</span>"
html += "</td>"
html += "</tr>"
}
html += "</tbody>"
html += "</table>"
html += "</div>"
html += "</div>"
html += "</div>"
html += "</div>"
$('#dir_list').append(html)
}
</script>

+ 12
- 0
vendor/github.com/elliotchance/orderedmap/.editorconfig View File

@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.go]
indent_style = tab
indent_size = 4
max_line_length = 80

+ 1
- 0
vendor/github.com/elliotchance/orderedmap/.gitignore View File

@@ -0,0 +1 @@
/.idea

+ 9
- 0
vendor/github.com/elliotchance/orderedmap/.travis.yml View File

@@ -0,0 +1,9 @@
language: go

go:
- 1.11.x
- 1.12.x
- master

script:
- env GO111MODULE=on go test

+ 21
- 0
vendor/github.com/elliotchance/orderedmap/LICENSE View File

@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 Elliot Chance

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 102
- 0
vendor/github.com/elliotchance/orderedmap/README.md View File

@@ -0,0 +1,102 @@
# 🔃 github.com/elliotchance/orderedmap [![GoDoc](https://godoc.org/github.com/elliotchance/orderedmap?status.svg)](https://godoc.org/github.com/elliotchance/orderedmap) [![Build Status](https://travis-ci.org/elliotchance/orderedmap.svg?branch=master)](https://travis-ci.org/elliotchance/orderedmap)

## Installation

```bash
go get -u github.com/elliotchance/orderedmap
```

## Basic Usage

An `*OrderedMap` is a high performance ordered map that maintains amortized O(1)
for `Set`, `Get`, `Delete` and `Len`:

```go
m := orderedmap.NewOrderedMap()

m.Set("foo", "bar")
m.Set("qux", 1.23)
m.Set(123, true)

m.Delete("qux")
```

Internally an `*OrderedMap` uses a combination of a map and linked list.

## Iterating

Be careful using `Keys()` as it will create a copy of all of the keys so it's
only suitable for a small number of items:

```go
for _, key := range m.Keys() {
value, _:= m.Get(key)
fmt.Println(key, value)
}
```

For larger maps you should use `Front()` or `Back()` to iterate per element:

```go
// Iterate through all elements from oldest to newest:
for el := m.Front(); el != nil; el = el.Next() {
fmt.Println(el.Key, el.Value)
}

// You can also use Back and Prev to iterate in reverse:
for el := m.Back(); el != nil; el = el.Prev() {
fmt.Println(el.Key, el.Value)
}
```

The iterator is safe to use bidirectionally, and will return `nil` once it goes
beyond the first or last item.

If the map is changing while the iteration is in-flight it may produce
unexpected behavior.

## Performance

CPU: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz

RAM: 8GB

System: Windows 10

```shell
$go test -benchmem -run=^$ github.com/elliotchance/orderedmap -bench BenchmarkAll
```

map[int]bool

| | map | orderedmap |
| ------- | ------------------- | ------------------- |
| set | 198 ns/op, 44 B/op | 722 ns/op, 211 B/op |
| get | 18 ns/op, 0 B/op | 37.3 ns/op, 0 B/op |
| delete | 888 ns/op, 211 B/op | 280 ns/op, 44 B/op |
| Iterate | 206 ns/op, 44 B/op | 693 ns/op, 259 B/op |

map[string]bool(PS : Use strconv.Itoa())

| | map | orderedmap |
| ----------- | ------------------- | ----------------------- |
| set | 421 ns/op, 86 B/op | 1048 ns/op, 243 B/op |
| get | 81.1 ns/op, 2 B/op | 97.8 ns/op, 2 B/op |
| delete | 737 ns/op, 122 B/op | 1188 ns/op, 251 B/op |
| Iterate all | 14706 ns/op, 1 B/op | 52671 ns/op, 16391 B/op |

Big map[int]bool (10000000 keys)

| | map | orderedmap |
| ----------- | -------------------------------- | ------------------------------- |
| set all | 1.834559 s/op, 423.9470291 MB/op | 7.5564667 s/op, 1784.1483 MB/op |
| get all | 2.6367878 s/op, 423.9698 MB/op | 9.0232475 s/op, 1784.1086 MB/op |
| Iterate all | 1.9526784 s/op, 423.9042 MB/op | 8.2495265 s/op, 1936.7619 MB/op |

Big map[string]bool (10000000 keys)

| | map | orderedmap |
| ----------- | --------------------------------- | ----------------------------------- |
| set all | 4.8893923 s/op, 921.33435 MB/op | 10.4405527 s/op, 2089.0144 MB/op |
| get all | 7.122791 s/op, 997.3802643 MB/op | 13.2613692 s/op, 2165.09521 MB/op |
| Iterate all | 5.1688922 s/op, 921.4619293 MB/op | 12.6623711 s/op, 2241.5272064 MB/op |

+ 33
- 0
vendor/github.com/elliotchance/orderedmap/element.go View File

@@ -0,0 +1,33 @@
package orderedmap

import "container/list"

type Element struct {
Key, Value interface{}

element *list.Element
}

func newElement(e *list.Element) *Element {
if e == nil {
return nil
}

element := e.Value.(*orderedMapElement)

return &Element{
element: e,
Key: element.key,
Value: element.value,
}
}

// Next returns the next element, or nil if it finished.
func (e *Element) Next() *Element {
return newElement(e.element.Next())
}

// Prev returns the previous element, or nil if it finished.
func (e *Element) Prev() *Element {
return newElement(e.element.Prev())
}

+ 5
- 0
vendor/github.com/elliotchance/orderedmap/go.mod View File

@@ -0,0 +1,5 @@
module github.com/elliotchance/orderedmap

go 1.12

require github.com/stretchr/testify v1.7.0

+ 15
- 0
vendor/github.com/elliotchance/orderedmap/go.sum View File

@@ -0,0 +1,15 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 150
- 0
vendor/github.com/elliotchance/orderedmap/orderedmap.go View File

@@ -0,0 +1,150 @@
package orderedmap

import "container/list"

type orderedMapElement struct {
key, value interface{}
}

type OrderedMap struct {
kv map[interface{}]*list.Element
ll *list.List
}

func NewOrderedMap() *OrderedMap {
return &OrderedMap{
kv: make(map[interface{}]*list.Element),
ll: list.New(),
}
}

// Get returns the value for a key. If the key does not exist, the second return
// parameter will be false and the value will be nil.
func (m *OrderedMap) Get(key interface{}) (interface{}, bool) {
value, ok := m.kv[key]
if ok {
return value.Value.(*orderedMapElement).value, true
}

return nil, false
}

// Set will set (or replace) a value for a key. If the key was new, then true
// will be returned. The returned value will be false if the value was replaced
// (even if the value was the same).
func (m *OrderedMap) Set(key, value interface{}) bool {
_, didExist := m.kv[key]

if !didExist {
element := m.ll.PushBack(&orderedMapElement{key, value})
m.kv[key] = element
} else {
m.kv[key].Value.(*orderedMapElement).value = value
}

return !didExist
}

// GetOrDefault returns the value for a key. If the key does not exist, returns
// the default value instead.
func (m *OrderedMap) GetOrDefault(key, defaultValue interface{}) interface{} {
if value, ok := m.kv[key]; ok {
return value.Value.(*orderedMapElement).value
}

return defaultValue
}

// GetElement returns the element for a key. If the key does not exist, the
// pointer will be nil.
func (m *OrderedMap) GetElement(key interface{}) *Element {
value, ok := m.kv[key]
if ok {
element := value.Value.(*orderedMapElement)
return &Element{
element: value,
Key: element.key,
Value: element.value,
}
}

return nil
}

// Len returns the number of elements in the map.
func (m *OrderedMap) Len() int {
return len(m.kv)
}

// Keys returns all of the keys in the order they were inserted. If a key was
// replaced it will retain the same position. To ensure most recently set keys
// are always at the end you must always Delete before Set.
func (m *OrderedMap) Keys() (keys []interface{}) {
keys = make([]interface{}, m.Len())

element := m.ll.Front()
for i := 0; element != nil; i++ {
keys[i] = element.Value.(*orderedMapElement).key
element = element.Next()
}

return keys
}

// Delete will remove a key from the map. It will return true if the key was
// removed (the key did exist).
func (m *OrderedMap) Delete(key interface{}) (didDelete bool) {
element, ok := m.kv[key]
if ok {
m.ll.Remove(element)
delete(m.kv, key)
}

return ok
}

// Front will return the element that is the first (oldest Set element). If
// there are no elements this will return nil.
func (m *OrderedMap) Front() *Element {
front := m.ll.Front()
if front == nil {
return nil
}

element := front.Value.(*orderedMapElement)

return &Element{
element: front,
Key: element.key,
Value: element.value,
}
}

// Back will return the element that is the last (most recent Set element). If
// there are no elements this will return nil.
func (m *OrderedMap) Back() *Element {
back := m.ll.Back()
if back == nil {
return nil
}

element := back.Value.(*orderedMapElement)

return &Element{
element: back,
Key: element.key,
Value: element.value,
}
}

// Copy returns a new OrderedMap with the same elements.
// Using Copy while there are concurrent writes may mangle the result.
func (m *OrderedMap) Copy() *OrderedMap {
m2 := NewOrderedMap()

for el := m.Front(); el != nil; el = el.Next() {
m2.Set(el.Key, el.Value)
}

return m2
}

+ 9
- 0
vendor/github.com/patrickmn/go-cache/CONTRIBUTORS View File

@@ -0,0 +1,9 @@
This is a list of people who have contributed code to go-cache. They, or their
employers, are the copyright holders of the contributed code. Contributed code
is subject to the license restrictions listed in LICENSE (as they were when the
code was contributed.)

Dustin Sallings <dustin@spy.net>
Jason Mooberry <jasonmoo@me.com>
Sergey Shepelev <temotor@gmail.com>
Alex Edwards <ajmedwards@gmail.com>

+ 19
- 0
vendor/github.com/patrickmn/go-cache/LICENSE View File

@@ -0,0 +1,19 @@
Copyright (c) 2012-2017 Patrick Mylund Nielsen and the go-cache contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save