You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

cloudbrain_image.go 10 kB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. package models
  2. import (
  3. "fmt"
  4. "strings"
  5. "xorm.io/builder"
  6. "code.gitea.io/gitea/modules/timeutil"
  7. )
  8. const RECOMMOND_TYPE = 5
  9. const NORMAL_TYPE = 0
  10. type Image struct {
  11. ID int64 `xorm:"pk autoincr"`
  12. Type int `xorm:"INDEX NOT NULL"` //0 normal 5官方推荐,中间值保留为后续扩展
  13. CloudbrainType int `xorm:"INDEX NOT NULL"` //0 云脑一 1云脑二
  14. UID int64 `xorm:"INDEX NOT NULL"`
  15. IsPrivate bool `xorm:"INDEX NOT NULL"`
  16. Tag string `xorm:"varchar(100) UNIQUE"`
  17. Description string `xorm:"varchar(765)"`
  18. Topics []string `xorm:"TEXT JSON"`
  19. Place string `xorm:"varchar(300)"`
  20. NumStars int `xorm:"NOT NULL DEFAULT 0"`
  21. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  22. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  23. }
  24. type ImageStar struct {
  25. ID int64 `xorm:"pk autoincr"`
  26. UID int64 `xorm:"UNIQUE(s)"`
  27. ImageID int64 `xorm:"UNIQUE(s)"`
  28. CreatedUnix timeutil.TimeStamp `xorm:"created"`
  29. }
  30. type ImageTopic struct {
  31. ID int64
  32. Name string `xorm:"UNIQUE VARCHAR(105)"`
  33. ImageCount int
  34. CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
  35. UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
  36. }
  37. type ImageTopicRelation struct {
  38. ImageID int64 `xorm:"UNIQUE(s)"`
  39. TopicID int64 `xorm:"UNIQUE(s)"`
  40. }
  41. type SearchImageOptions struct {
  42. Keyword string
  43. UID int64
  44. IncludePublic bool
  45. IncludeStarByMe bool
  46. IncludeCustom bool
  47. CodeLanguage string
  48. Framework string
  49. CudaVersion string
  50. ListOptions
  51. SearchOrderBy
  52. }
  53. type ErrorImageTagExist struct {
  54. Tag string
  55. }
  56. func (err ErrorImageTagExist) Error() string {
  57. return fmt.Sprintf("Image already exists [tag: %s]", err.Tag)
  58. }
  59. type ErrImageNotExist struct {
  60. ID int64
  61. }
  62. func (err ErrImageNotExist) Error() string {
  63. return fmt.Sprintf("Image does not exist [id: %d]", err.ID)
  64. }
  65. func IsErrImageTagExist(err error) bool {
  66. _, ok := err.(ErrorImageTagExist)
  67. return ok
  68. }
  69. func IsImageExist(tag string) (bool, error) {
  70. return x.Exist(&Image{
  71. Tag: tag,
  72. })
  73. }
  74. type FindImageTopicOptions struct {
  75. ListOptions
  76. ImageID int64
  77. Keyword string
  78. }
  79. func (opts *FindImageTopicOptions) toConds() builder.Cond {
  80. var cond = builder.NewCond()
  81. if opts.ImageID > 0 {
  82. cond = cond.And(builder.Eq{"image_topic.image_id": opts.ImageID})
  83. }
  84. if opts.Keyword != "" {
  85. cond = cond.And(builder.Like{"image_topic.name", strings.ToLower(opts.Keyword)})
  86. }
  87. return cond
  88. }
  89. func GetImageByID(id int64) (*Image, error) {
  90. rel := new(Image)
  91. has, err := x.
  92. ID(id).
  93. Get(rel)
  94. if err != nil {
  95. return nil, err
  96. } else if !has {
  97. return nil, ErrImageNotExist{id}
  98. }
  99. return rel, nil
  100. }
  101. func FindImageTopics(opts *FindImageTopicOptions) (topics []*ImageTopic, err error) {
  102. sess := x.Select("image_topic.*").Where(opts.toConds())
  103. if opts.ImageID > 0 {
  104. sess.Join("INNER", "image_topic_relation", "image_topic_relation.topic_id = image_topic.id")
  105. }
  106. if opts.PageSize != 0 && opts.Page != 0 {
  107. sess = opts.setSessionPagination(sess)
  108. }
  109. return topics, sess.Desc("image_topic.image_count").Find(&topics)
  110. }
  111. func SaveImageTopics(imageID int64, topicNames ...string) error {
  112. topics, err := FindImageTopics(&FindImageTopicOptions{
  113. ImageID: imageID,
  114. })
  115. if err != nil {
  116. return err
  117. }
  118. sess := x.NewSession()
  119. defer sess.Close()
  120. if err := sess.Begin(); err != nil {
  121. return err
  122. }
  123. var addedTopicNames []string
  124. for _, topicName := range topicNames {
  125. if strings.TrimSpace(topicName) == "" {
  126. continue
  127. }
  128. var found bool
  129. for _, t := range topics {
  130. if strings.EqualFold(topicName, t.Name) {
  131. found = true
  132. break
  133. }
  134. }
  135. if !found {
  136. addedTopicNames = append(addedTopicNames, topicName)
  137. }
  138. }
  139. var removeTopics []*ImageTopic
  140. for _, t := range topics {
  141. var found bool
  142. for _, topicName := range topicNames {
  143. if strings.EqualFold(topicName, t.Name) {
  144. found = true
  145. break
  146. }
  147. }
  148. if !found {
  149. removeTopics = append(removeTopics, t)
  150. }
  151. }
  152. for _, topicName := range addedTopicNames {
  153. _, err := addTopicByNameToImage(sess, imageID, topicName)
  154. if err != nil {
  155. return err
  156. }
  157. }
  158. for _, topic := range removeTopics {
  159. err := removeTopicFromImage(sess, imageID, topic)
  160. if err != nil {
  161. return err
  162. }
  163. }
  164. topicNames = make([]string, 0, 25)
  165. if err := sess.Table("image_topic").Cols("name").
  166. Join("INNER", "image_topic_relation", "image_topic_relation.topic_id = image_topic.id").
  167. Where("image_topic_relation.image_id = ?", imageID).Desc("image_topic.image_count").Find(&topicNames); err != nil {
  168. return err
  169. }
  170. if _, err := sess.ID(imageID).Cols("topics").Update(&Image{
  171. Topics: topicNames,
  172. }); err != nil {
  173. return err
  174. }
  175. return sess.Commit()
  176. }
  177. func addTopicByNameToImage(e Engine, imageID int64, topicName string) (*ImageTopic, error) {
  178. var topic ImageTopic
  179. has, err := e.Where("name = ?", topicName).Get(&topic)
  180. if err != nil {
  181. return nil, err
  182. }
  183. if !has {
  184. topic.Name = topicName
  185. topic.ImageCount = 1
  186. if _, err := e.Insert(&topic); err != nil {
  187. return nil, err
  188. }
  189. } else {
  190. topic.ImageCount++
  191. if _, err := e.ID(topic.ID).Cols("image_count").Update(&topic); err != nil {
  192. return nil, err
  193. }
  194. }
  195. if _, err := e.Insert(&ImageTopicRelation{
  196. ImageID: imageID,
  197. TopicID: topic.ID,
  198. }); err != nil {
  199. return nil, err
  200. }
  201. return &topic, nil
  202. }
  203. func removeTopicFromImage(e Engine, imageId int64, topic *ImageTopic) error {
  204. topic.ImageCount--
  205. if _, err := e.ID(topic.ID).Cols("image_count").Update(topic); err != nil {
  206. return err
  207. }
  208. if _, err := e.Delete(&ImageTopicRelation{
  209. ImageID: imageId,
  210. TopicID: topic.ID,
  211. }); err != nil {
  212. return err
  213. }
  214. return nil
  215. }
  216. /*func SearchImage(opts *SearchImageOptions) ([]*Image, int64, error) {
  217. cond := SearchImageCondition(opts)
  218. return SearchImageByCondition(opts, cond)
  219. }*/
  220. func SearchImageCondition(opts *SearchImageOptions) builder.Cond {
  221. var cond = builder.NewCond()
  222. if len(opts.Keyword) > 0 {
  223. cond = cond.And(builder.Or(builder.Like{"image.tag", opts.Keyword}, builder.Like{"image.description", opts.Keyword}))
  224. }
  225. if len(opts.CudaVersion) > 0 {
  226. cond = cond.And(builder.Eq{"image.cuda_version": opts.CudaVersion})
  227. }
  228. if len(opts.CodeLanguage) > 0 {
  229. cond = cond.And(builder.Eq{"image.code_language": opts.CodeLanguage})
  230. }
  231. if len(opts.Framework) > 0 {
  232. cond = cond.And(builder.Eq{"image.framework": opts.Framework})
  233. }
  234. if opts.IncludePublic {
  235. cond = cond.And(builder.Eq{"image.is_private": false})
  236. }
  237. /**
  238. if opts.IncludeStarByMe {
  239. cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic})
  240. cond = cond.And(builder.Eq{"attachment.is_private": false})
  241. if opts.OwnerID > 0 {
  242. if len(opts.Keyword) == 0 {
  243. cond = cond.Or(builder.Eq{"repository.owner_id": opts.OwnerID})
  244. } else {
  245. subCon := builder.NewCond()
  246. subCon = subCon.And(builder.Eq{"repository.owner_id": opts.OwnerID}, builder.Or(builder.Like{"dataset.title", opts.Keyword}, builder.Like{"dataset.description", opts.Keyword}))
  247. cond = cond.Or(subCon)
  248. }
  249. }
  250. } else if opts.OwnerID > 0 {
  251. cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID})
  252. if !opts.IsOwner {
  253. cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic})
  254. cond = cond.And(builder.Eq{"attachment.is_private": false})
  255. }
  256. }*/
  257. return cond
  258. }
  259. /*func SearchImageByCondition(opts *SearchImageOptions, cond builder.Cond) ([]*Image, int64, error) {
  260. if opts.Page <= 0 {
  261. opts.Page = 1
  262. }
  263. var err error
  264. sess := x.NewSession()
  265. defer sess.Close()
  266. datasets := make(DatasetList, 0, opts.PageSize)
  267. selectColumnsSql := "distinct dataset.id,dataset.title, dataset.status, dataset.category, dataset.description, dataset.download_times, dataset.license, dataset.task, dataset.release_id, dataset.user_id, dataset.repo_id, dataset.created_unix,dataset.updated_unix,dataset.num_stars"
  268. count, err := sess.Distinct("dataset.id").Join("INNER", "repository", "repository.id = dataset.repo_id").
  269. Join("INNER", "attachment", "attachment.dataset_id=dataset.id").
  270. Where(cond).Count(new(Dataset))
  271. if err != nil {
  272. return nil, 0, fmt.Errorf("Count: %v", err)
  273. }
  274. sess.Select(selectColumnsSql).Join("INNER", "repository", "repository.id = dataset.repo_id").
  275. Join("INNER", "attachment", "attachment.dataset_id=dataset.id").
  276. Where(cond).OrderBy(opts.SearchOrderBy.String())
  277. if opts.PageSize > 0 {
  278. sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
  279. }
  280. if err = sess.Find(&datasets); err != nil {
  281. return nil, 0, fmt.Errorf("Dataset: %v", err)
  282. }
  283. if err = datasets.loadAttributes(sess); err != nil {
  284. return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
  285. }
  286. return datasets, count, nil
  287. }*/
  288. func CreateLocalImage(image *Image) error {
  289. _, err := x.Insert(image)
  290. return err
  291. }
  292. //star or unstar Image
  293. func StarImage(userID, imageID int64, star bool) error {
  294. sess := x.NewSession()
  295. defer sess.Close()
  296. if err := sess.Begin(); err != nil {
  297. return err
  298. }
  299. if star {
  300. if isImageStaring(sess, userID, imageID) {
  301. return nil
  302. }
  303. if _, err := sess.Insert(&ImageStar{UID: userID, ImageID: imageID}); err != nil {
  304. return err
  305. }
  306. if _, err := sess.Exec("UPDATE `image` SET num_stars = num_stars + 1 WHERE id = ?", imageID); err != nil {
  307. return err
  308. }
  309. if _, err := sess.Exec("UPDATE `user` SET num_image_stars = num_image_stars + 1 WHERE id = ?", userID); err != nil {
  310. return err
  311. }
  312. } else {
  313. if !isImageStaring(sess, userID, imageID) {
  314. return nil
  315. }
  316. if _, err := sess.Delete(&ImageStar{0, userID, imageID, 0}); err != nil {
  317. return err
  318. }
  319. if _, err := sess.Exec("UPDATE `image` SET num_stars = num_stars - 1 WHERE id = ?", imageID); err != nil {
  320. return err
  321. }
  322. if _, err := sess.Exec("UPDATE `user` SET num_image_stars = num_image_stars - 1 WHERE id = ?", userID); err != nil {
  323. return err
  324. }
  325. }
  326. return sess.Commit()
  327. }
  328. func IsImageStaring(userID, datasetID int64) bool {
  329. return isImageStaring(x, userID, datasetID)
  330. }
  331. func isImageStaring(e Engine, userID, imageID int64) bool {
  332. has, _ := e.Get(&ImageStar{0, userID, imageID, 0})
  333. return has
  334. }
  335. func RecommendImage(imageId int64, recommond bool) error {
  336. image := Image{Type: getRecommondType(recommond)}
  337. _, err := x.ID(imageId).Cols("type").Update(image)
  338. return err
  339. }
  340. func getRecommondType(recommond bool) int {
  341. if recommond {
  342. return RECOMMOND_TYPE
  343. } else {
  344. return NORMAL_TYPE
  345. }
  346. }