token.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. package token
  2. import (
  3. "encoding/hex"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "net/http"
  8. "strings"
  9. "time"
  10. "github.com/gin-gonic/gin"
  11. "github.com/guregu/null"
  12. "github.com/metarare/metarare_api/common"
  13. "github.com/metarare/metarare_api/helpers"
  14. "github.com/metarare/metarare_api/helpers/gauth"
  15. "github.com/metarare/metarare_api/helpers/gerror"
  16. "github.com/metarare/metarare_api/models"
  17. "github.com/metarare/metarare_api/util"
  18. "github.com/metarare/metarare_api/view"
  19. "gorm.io/gorm"
  20. )
  21. type TokenV1Router struct {
  22. group *gin.RouterGroup
  23. mDB *gorm.DB
  24. rDB *gorm.DB
  25. awsConf util.AWSConfs
  26. assetsAwsConf util.AWSConfs
  27. }
  28. type TokenBaseInfo struct {
  29. Commission float64 `json:"commission"`
  30. Collection []CollectionData `json:"collection"`
  31. }
  32. type CollectionData struct {
  33. CollectionID uint64 `json:"collection_id"`
  34. ThumbnailImage string `json:"thumbnail_image"`
  35. Name string `json:"name"`
  36. IsOfficial bool `json:"is_official"`
  37. }
  38. type RegisterTokenData struct {
  39. CollectionID uint64 `json:"collection_id" binding:"required"`
  40. Name string `json:"name" binding:"required"`
  41. Description string `json:"description" binding:"required"`
  42. Type string `json:"type" binding:"required"`
  43. TotalCount int `json:"total_count" binding:"required"`
  44. Royalties uint32 `json:"royalties" binding:"required"`
  45. Sale RegisterSaleData `json:"sale" binding:"required"`
  46. Traits []Trait `json:"traits"`
  47. }
  48. type Trait struct {
  49. Key string `json:"key"`
  50. Value string `json:"value"`
  51. }
  52. type RegisterSaleData struct {
  53. SaleType string `json:"sale_type" binding:"required"`
  54. Price float64 `json:"price" binding:"required"`
  55. StartPrice float64 `json:"start_price" binding:"required"`
  56. StartAt time.Time `json:"start_at" binding:"required"`
  57. EndAt time.Time `json:"end_at" binding:"required"`
  58. Currency string `json:"currency" binding:"required"`
  59. }
  60. type TargetID struct {
  61. ID uint64 `json:"id"`
  62. }
  63. type Like struct {
  64. TokenID uint64 `json:"token_id" binding:"required"`
  65. IsLike bool `json:"is_like"`
  66. }
  67. func NewTokenV1Router(r common.Router, basePath string) TokenV1Router {
  68. t := TokenV1Router{
  69. group: r.Version.Group(basePath),
  70. mDB: r.Db.MasterDB,
  71. rDB: r.Db.ReadDB,
  72. awsConf: util.AWSConfs{
  73. Region: r.Env.GetString("storage.region"),
  74. BucketName: r.Env.GetString("storage.bucket_name"),
  75. Access_key_id: r.Env.GetString("storage.access_key_id"),
  76. Access_key: r.Env.GetString("storage.access_key"),
  77. },
  78. assetsAwsConf: util.AWSConfs{
  79. Region: r.Env.GetString("storage.region"),
  80. BucketName: r.Env.GetString("storage.assets_buket_name"),
  81. Access_key_id: r.Env.GetString("storage.access_key_id"),
  82. Access_key: r.Env.GetString("storage.access_key"),
  83. },
  84. }
  85. t.group.GET("baseinfo", t.getTokenBaseInfo)
  86. t.group.PATCH("like", t.updateLikeCount)
  87. t.group.POST("", t.registerToken)
  88. t.group.GET("owner", t.getOwnerList)
  89. t.group.GET("log/:token_id", t.getTokenLog)
  90. t.group.GET("resaleinfo/:token_id", t.getTokenResaleInfo)
  91. t.group.GET(":token_id", t.getTokenDetailInfo)
  92. return t
  93. }
  94. // getTokenBaseInfo godoc
  95. // @Summary get token base info
  96. // @Description 아이템 생성 시 내가 만든 컬렉션 리스트와, 사이트 커미션 수수료 정보 가져오기
  97. // @Schemes
  98. // @security ApiKeyAuth
  99. // @Tags token
  100. // @Accept json
  101. // @Produce json
  102. // @Param type query string true "erc721, erc1155"
  103. // @Success 200 {object} TokenBaseInfo
  104. // @Router /token/baseinfo [get]
  105. func (t TokenV1Router) getTokenBaseInfo(c *gin.Context) {
  106. //NOTE x 다이나믹으로 해당 컬렉션의 타입을 받아 분기시켜서 보내준다.
  107. userID, err := gauth.GetCurrentUserIDToInt64(c)
  108. if err != nil || userID == 0 {
  109. gerror.IntegratedResponseToRequest(c, http.StatusUnauthorized, gerror.Unauthorized, nil, err)
  110. return
  111. }
  112. condition := c.Query("type")
  113. if condition != "erc721" && condition != "erc1155" {
  114. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, err)
  115. return
  116. }
  117. wallet := models.UserWallet{}
  118. if err := t.rDB.Where("user_id = ?", userID).Find(&wallet).Error; err != nil {
  119. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidParameterValue, nil, err)
  120. return
  121. }
  122. response := TokenBaseInfo{}
  123. if err := t.rDB.Select("commission").Table("setting").Find(&response.Commission).Error; err != nil {
  124. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidParameterValue, nil, err)
  125. return
  126. }
  127. if err := t.rDB.Select("collection.id AS collection_id, collection.is_official, collection_profile.thumbnail_image, collection_profile.name").Table("collection").
  128. Joins("INNER JOIN collection_profile ON collection_profile.collection_id = collection.id").
  129. Where("(collection.is_official = 1 AND collection.type = ?) OR (collection.type = ? AND collection.owner_address = ?)", condition, condition, wallet.Address).Find(&response.Collection).Error; err != nil {
  130. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidParameterValue, nil, err)
  131. return
  132. }
  133. gerror.IntegratedResponseToRequest(c, http.StatusOK, gerror.OK, response, nil)
  134. return
  135. }
  136. // registerToken godoc
  137. // @Summary create NFT
  138. // @Description NFT 생성과 동시에 판매 등록
  139. // @Schemes
  140. // @security ApiKeyAuth
  141. // @Tags token
  142. // @Accept multipart/form-data
  143. // @Produce json
  144. // @Param contentImage formData file true "content image"
  145. // @Param json formData common.SwagStruct true "object"
  146. // @Success 200 {string} OK
  147. // @Router /token [post]
  148. func (t TokenV1Router) registerToken(c *gin.Context) {
  149. userID, err := gauth.GetCurrentUserIDToInt64(c)
  150. if err != nil || userID == 0 {
  151. gerror.IntegratedResponseToRequest(c, http.StatusUnauthorized, gerror.Unauthorized, nil, err)
  152. return
  153. }
  154. form, err := c.MultipartForm()
  155. if err != nil {
  156. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MultipartError, nil, err)
  157. return
  158. }
  159. _request := form.Value["json"]
  160. if _request == nil {
  161. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, errors.New("invalid parameter value"))
  162. return
  163. }
  164. request := RegisterTokenData{}
  165. if err := json.Unmarshal([]byte(_request[0]), &request); err != nil {
  166. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidParameterValue, nil, nil)
  167. return
  168. }
  169. //validate check
  170. if request.CollectionID == 0 || request.Name == "" || request.Type == "" || request.TotalCount > 20 ||
  171. request.Royalties > 50 || request.Sale.SaleType == "" || request.Sale.Currency == "" {
  172. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, err)
  173. return
  174. }
  175. contentImage := form.File["contentImage"]
  176. if contentImage == nil {
  177. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, errors.New("invalid parameter value"))
  178. return
  179. }
  180. wallet := models.UserWallet{}
  181. if err := t.rDB.Where("user_id = ?", userID).Find(&wallet).Error; err != nil {
  182. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidConnection, nil, err)
  183. return
  184. }
  185. collection := models.Collection{}
  186. _err := t.rDB.Where("id = ?", request.CollectionID).Find(&collection).Error
  187. if errors.Is(_err, gorm.ErrRecordNotFound) {
  188. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, _err)
  189. return
  190. }
  191. setting := models.Setting{}
  192. _err = t.rDB.Find(&setting).Error
  193. if errors.Is(_err, gorm.ErrRecordNotFound) {
  194. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, _err)
  195. return
  196. }
  197. tx := t.mDB.Begin()
  198. defer common.DBTransaction(tx)
  199. var contentImageURL string
  200. var assetsImageURL string
  201. ContentImagePath := fmt.Sprintf("token/content")
  202. for _, f := range contentImage {
  203. contentImageURL, err = util.UploadToS3(t.awsConf, ContentImagePath, f)
  204. if err != nil {
  205. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.Error3rdParty, nil, err)
  206. tx.Rollback()
  207. return
  208. }
  209. // NOTE x assets image data
  210. imageURL, err := util.UploadToS3(t.assetsAwsConf, "", f)
  211. if err != nil {
  212. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.Error3rdParty, nil, err)
  213. tx.Rollback()
  214. return
  215. }
  216. str := strings.Split(imageURL, "/")
  217. assetsImageURL = "https://assets.meta-rare.net/" + str[len(str)-1]
  218. }
  219. response := models.Sale{}
  220. tokenUID := common.GenerateTokenUID(tx, "token_")
  221. for idx := 1; idx <= int(request.TotalCount); idx++ {
  222. token := models.Token{
  223. CollectionID: request.CollectionID,
  224. Name: request.Name,
  225. Description: request.Description,
  226. Royalties: request.Royalties,
  227. CreatorAddress: wallet.Address,
  228. OwnerAddress: wallet.Address,
  229. ContentURL: contentImageURL,
  230. AssetsImageURL: assetsImageURL,
  231. Type: request.Type,
  232. UID: tokenUID,
  233. }
  234. if request.Type == "erc1155" {
  235. token.TotalCount = null.IntFrom(int64(request.TotalCount))
  236. token.Index = null.IntFrom(int64(idx))
  237. }
  238. if err := tx.Save(&token).Error; err != nil {
  239. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  240. tx.Rollback()
  241. return
  242. }
  243. sale := models.Sale{
  244. TokenID: token.ID,
  245. SaleType: request.Sale.SaleType,
  246. UID: common.GenerateSaleUID(tx, "sale_"),
  247. Currency: request.Sale.Currency,
  248. Status: "ongoing",
  249. TreasuryTax: setting.Commission,
  250. }
  251. if request.Sale.SaleType == "fixed" {
  252. sale.Price = null.FloatFrom(request.Sale.Price)
  253. } else if request.Sale.SaleType == "time" {
  254. sale.StartPrice = null.FloatFrom(request.Sale.StartPrice)
  255. sale.StartAt = null.TimeFrom(request.Sale.StartAt)
  256. sale.EndAt = null.TimeFrom(request.Sale.EndAt)
  257. }
  258. if request.Sale.SaleType == "fixed" {
  259. _v := common.MakeHashData{
  260. OwnerAddress: wallet.Address,
  261. CollectionAddress: collection.ContractAddress,
  262. TokenType: request.Type,
  263. TokenID: int64(token.ID),
  264. Currency: request.Sale.Currency,
  265. Price: request.Sale.Price,
  266. Index: int64(idx),
  267. TotalIndex: int64(request.TotalCount),
  268. CreationTax: int64(request.Royalties * 100),
  269. PrevTreasuryTax: int64(setting.Commission * 100),
  270. TreasuryAddress: setting.TreasuryAddress,
  271. }
  272. _vv, err := common.MakeSining(tx, _v)
  273. if err != nil {
  274. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  275. tx.Rollback()
  276. return
  277. }
  278. _signature, _hashData, err := helpers.Signing(_vv, wallet.PrivateKey)
  279. if err != nil {
  280. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  281. tx.Rollback()
  282. return
  283. }
  284. sale.HashData = hex.EncodeToString(_hashData)
  285. sale.Signature = hex.EncodeToString(_signature)
  286. }
  287. if err := tx.Save(&sale).Error; err != nil {
  288. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  289. tx.Rollback()
  290. return
  291. }
  292. for _, item := range request.Traits {
  293. tr := models.Traits{
  294. TokenID: token.ID,
  295. Key: item.Key,
  296. Value: item.Value,
  297. }
  298. if err := tx.Save(&tr).Error; err != nil {
  299. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  300. tx.Rollback()
  301. return
  302. }
  303. }
  304. if idx == 1 {
  305. response = sale
  306. }
  307. if request.Type == "erc721" {
  308. break
  309. }
  310. }
  311. if err := tx.Commit().Error; err != nil {
  312. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  313. tx.Rollback()
  314. return
  315. }
  316. gerror.IntegratedResponseToRequest(c, http.StatusOK, gerror.OK, response, nil)
  317. return
  318. }
  319. // updateLikeCount godoc
  320. // @Summary update token like count
  321. // @Description 토큰 좋아요 기능
  322. // @Schemes
  323. // @security ApiKeyAuth
  324. // @Tags token
  325. // @Accept json
  326. // @Produce json
  327. // @Param Like body Like true "selected target id"
  328. // @Success 200 {string} OK
  329. // @Router /token/like [patch]
  330. func (t TokenV1Router) updateLikeCount(c *gin.Context) {
  331. userID, err := gauth.GetCurrentUserIDToInt64(c)
  332. if err != nil || userID == 0 {
  333. gerror.IntegratedResponseToRequest(c, http.StatusUnauthorized, gerror.Unauthorized, nil, err)
  334. return
  335. }
  336. request := Like{}
  337. if err := c.ShouldBindJSON(&request); err != nil {
  338. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, err)
  339. return
  340. }
  341. token := models.Token{}
  342. _err := t.rDB.Where("id = ?", request.TokenID).Find(&token).Error
  343. if errors.Is(_err, gorm.ErrRecordNotFound) {
  344. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.NotFoundRecord, nil, err)
  345. return
  346. }
  347. userLike := models.UserLike{}
  348. if err := t.rDB.Where("user_id = ? AND token_id = ?", userID, token.ID).Find(&userLike).Error; err != nil {
  349. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidParameterValue, nil, err)
  350. return
  351. }
  352. if (userLike.IsLike == 1 && request.IsLike) || (userLike.IsLike == 0 && !request.IsLike) {
  353. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidParameterValue, nil, err)
  354. return
  355. }
  356. tx := t.mDB.Begin()
  357. defer common.DBTransaction(tx)
  358. if userLike.ID == 0 {
  359. userLike.UserID = userID
  360. userLike.TokenID = token.ID
  361. userLike.IsLike = 1
  362. if err := tx.Save(&userLike).Error; err != nil {
  363. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  364. tx.Rollback()
  365. return
  366. }
  367. } else {
  368. if err := tx.Model(&userLike).Update("is_like", request.IsLike).Error; err != nil {
  369. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.InvalidParameterValue, nil, err)
  370. tx.Rollback()
  371. return
  372. }
  373. }
  374. if request.IsLike {
  375. token.LikeCount += 1
  376. } else {
  377. token.LikeCount -= 1
  378. }
  379. if err := tx.Save(&token).Error; err != nil {
  380. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  381. tx.Rollback()
  382. return
  383. }
  384. if err := tx.Commit().Error; err != nil {
  385. gerror.IntegratedResponseToRequest(c, http.StatusInternalServerError, gerror.MysqlSaveError, nil, err)
  386. tx.Rollback()
  387. return
  388. }
  389. gerror.IntegratedResponseToRequest(c, http.StatusOK, gerror.OK, nil, nil)
  390. return
  391. }
  392. // getTokenLog godoc
  393. // @Summary get token log
  394. // @Description NFT 판매 페이지 기록 탭
  395. // @Schemes
  396. // @Tags token
  397. // @Accept json
  398. // @Produce json
  399. // @Success 200 {object} common.ActivityItem
  400. // @Param token_id path string true "token id"
  401. // @Router /token/log/{token_id} [get]
  402. func (t TokenV1Router) getTokenLog(c *gin.Context) {
  403. tokenID := c.Param("token_id")
  404. if tokenID == "" {
  405. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, errors.New("invalid parameter value"))
  406. return
  407. }
  408. condition := [...]string{"purchase", "create", "sell"}
  409. response := []common.ActivityItem{}
  410. err := view.GetActivityItemQuery(t.rDB).Where("log_relation.token_id = ? AND log.type in (?)", tokenID, condition).Find(&response).Error
  411. if errors.Is(err, gorm.ErrRecordNotFound) {
  412. gerror.IntegratedResponseToRequest(c, http.StatusNotFound, gerror.NotFoundRecord, nil, err)
  413. return
  414. }
  415. gerror.IntegratedResponseToRequest(c, http.StatusOK, gerror.OK, response, nil)
  416. return
  417. }
  418. // getOwnerList godoc
  419. // @Summary get owner list
  420. // @Description NFT 1155타입의 소유자 탭
  421. // @Schemes
  422. // @Tags token
  423. // @Accept json
  424. // @Produce json
  425. // @Success 200 {object} view.TokenOwnerList
  426. // @Param token_uid query string true "type"
  427. // @Router /token/owner [get]
  428. func (t TokenV1Router) getOwnerList(c *gin.Context) {
  429. tokenUID := c.Query("token_uid")
  430. if tokenUID == "" {
  431. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, errors.New("invalid parameter value"))
  432. return
  433. }
  434. response := []view.TokenOwnerList{}
  435. err := view.GetOwnerList(t.rDB).Where("token.uid = ?", tokenUID).Order("token.id desc").Find(&response).Error
  436. if errors.Is(err, gorm.ErrRecordNotFound) {
  437. gerror.IntegratedResponseToRequest(c, http.StatusNotFound, gerror.NotFoundRecord, nil, err)
  438. return
  439. }
  440. gerror.IntegratedResponseToRequest(c, http.StatusOK, gerror.OK, response, nil)
  441. return
  442. }
  443. // getTokenResaleInfo godoc
  444. // @Summary get resale data
  445. // @Description 토큰 재판매 시 설정해야하는 기본 데이터
  446. // @Schemes
  447. // @security ApiKeyAuth
  448. // @Tags token
  449. // @Accept json
  450. // @Produce json
  451. // @Success 200 {object} view.TokenResaleData
  452. // @Param token_id path string true "token id"
  453. // @Router /token/resaleinfo/{token_id} [get]
  454. func (t TokenV1Router) getTokenResaleInfo(c *gin.Context) {
  455. userID, _err := gauth.GetCurrentUserIDToInt64(c)
  456. if _err != nil || userID == 0 {
  457. gerror.IntegratedResponseToRequest(c, http.StatusUnauthorized, gerror.Unauthorized, nil, _err)
  458. return
  459. }
  460. tokenID := c.Param("token_id")
  461. if tokenID == "" {
  462. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, errors.New("invalid parameter value"))
  463. return
  464. }
  465. //NOTE x 토큰의 오너인지, 세일이 없는 아이인지 확인하기
  466. _t := models.Token{}
  467. err := t.rDB.Where("id = ?", tokenID).Find(&_t).Error
  468. if errors.Is(err, gorm.ErrRecordNotFound) {
  469. gerror.IntegratedResponseToRequest(c, http.StatusNotFound, gerror.NotFoundRecord, nil, err)
  470. return
  471. }
  472. _uw := models.UserWallet{}
  473. err = t.rDB.Where("user_id = ?", userID).Find(&_uw).Error
  474. if errors.Is(err, gorm.ErrRecordNotFound) {
  475. gerror.IntegratedResponseToRequest(c, http.StatusNotFound, gerror.NotFoundRecord, nil, err)
  476. return
  477. }
  478. if _t.OwnerAddress != _uw.Address {
  479. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, err)
  480. return
  481. }
  482. _s := []models.Sale{}
  483. t.rDB.Where("token_id = ? AND status = 'ongoing'", tokenID).Find(&_s)
  484. if len(_s) > 0 {
  485. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, err)
  486. return
  487. }
  488. response := view.TokenResaleData{}
  489. err = view.GetResaleInfo(t.rDB).Where("token.id = ?", tokenID).Find(&response.Token).Error
  490. if errors.Is(err, gorm.ErrRecordNotFound) {
  491. gerror.IntegratedResponseToRequest(c, http.StatusNotFound, gerror.NotFoundRecord, nil, err)
  492. return
  493. }
  494. _setting := models.Setting{}
  495. err = t.rDB.Find(&_setting).Error
  496. if errors.Is(err, gorm.ErrRecordNotFound) {
  497. gerror.IntegratedResponseToRequest(c, http.StatusNotFound, gerror.NotFoundRecord, nil, err)
  498. return
  499. }
  500. response.Token.Commission = _setting.Commission
  501. t.rDB.Where("token_id = ?", tokenID).Find(&response.Traits)
  502. gerror.IntegratedResponseToRequest(c, http.StatusOK, gerror.OK, response, nil)
  503. return
  504. }
  505. // getTokenDetailInfo godoc
  506. // @Summary get token detail
  507. // @Description 토큰 상세페이지
  508. // @Schemes
  509. // @Tags token
  510. // @Accept json
  511. // @Produce json
  512. // @Success 200 {object} view.TokenDetailData
  513. // @Param token_id path string true "token id"
  514. // @Router /token/{token_id} [get]
  515. func (t TokenV1Router) getTokenDetailInfo(c *gin.Context) {
  516. userID, _ := gauth.GetCurrentUserIDToInt64(c)
  517. tokenID := c.Param("token_id")
  518. if tokenID == "" {
  519. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, errors.New("invalid parameter value"))
  520. return
  521. }
  522. _s := []models.Sale{}
  523. err := t.rDB.Where("token_id = ? AND status = 'ongoing'", tokenID).Find(&_s).Error
  524. if len(_s) > 0 {
  525. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.InvalidParameterValue, nil, err)
  526. return
  527. }
  528. response := view.TokenDetailData{}
  529. err = view.GetTokenDetail(t.rDB, userID).Where("token.id = ?", tokenID).Find(&response.Token).Error
  530. if errors.Is(err, gorm.ErrRecordNotFound) {
  531. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.NotFoundRecord, nil, err)
  532. return
  533. }
  534. err = t.rDB.Where("token_id = ?", tokenID).Find(&response.Traits).Error
  535. if errors.Is(err, gorm.ErrRecordNotFound) {
  536. gerror.IntegratedResponseToRequest(c, http.StatusBadRequest, gerror.NotFoundRecord, nil, err)
  537. return
  538. }
  539. gerror.IntegratedResponseToRequest(c, http.StatusOK, gerror.OK, response, nil)
  540. }