creation.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. package dao
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/hmac"
  6. "crypto/sha1"
  7. "encoding/base64"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "hash"
  12. "net/http"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "database/sql"
  17. artmdl "go-common/app/interface/openplatform/article/model"
  18. xsql "go-common/library/database/sql"
  19. "go-common/library/ecode"
  20. "go-common/library/log"
  21. xtime "go-common/library/time"
  22. "go-common/library/xstr"
  23. )
  24. const (
  25. // article
  26. _addArticleMetaSQL = "INSERT INTO articles (category_id,title,summary,banner_url,template_id,state,mid,reprint,image_urls,attributes,words,dynamic_intro,origin_image_urls,act_id,media_id,spoiler,apply_time) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
  27. _addArticleContentSQL = "INSERT INTO article_contents_%s (article_id,content,tags) values (?,?,?)"
  28. _addArticleVersionSQL = "INSERT INTO article_versions (article_id,category_id,title,state,content,summary,banner_url,template_id,mid,reprint,image_urls,attributes,words,dynamic_intro,origin_image_urls,act_id,media_id,spoiler,apply_time,ext_msg)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
  29. _updateArticleVersionSQL = "UPDATE article_versions SET category_id=?,title=?,state=?,content=?,summary=?,banner_url=?,template_id=?,mid=?,reprint=?,image_urls=?,attributes=?,words=?,dynamic_intro=?,origin_image_urls=?,spoiler=?,apply_time=?,ext_msg=? where article_id=? and deleted_time=0"
  30. _updateArticleMetaSQL = "UPDATE articles SET category_id=?,title=?,summary=?,banner_url=?,template_id=?,state=?,mid=?,reprint=?,image_urls=?,attributes=?,words=?,dynamic_intro=?,origin_image_urls =?,spoiler=?,apply_time=? WHERE id=?"
  31. _updateArticleContentSQL = "UPDATE article_contents_%s SET content=?, tags=? WHERE article_id=?"
  32. _deleteArticleMetaSQL = "UPDATE articles SET deleted_time=? WHERE id=?"
  33. _deleteArticleContentSQL = "UPDATE article_contents_%s SET deleted_time=? WHERE article_id=?"
  34. _deleteArticleVerionSQL = "UPDATE article_versions SET deleted_time=? WHERE article_id=?"
  35. _updateArticleStateSQL = "UPDATE articles SET state=? WHERE id=?"
  36. _updateArticleStateApplyTimeSQL = "UPDATE articles SET state=?,apply_time=? WHERE id=?"
  37. _upperArticlesMetaCreationSQL = `SELECT id,category_id,title,summary,banner_url,template_id,state,mid,reprint,image_urls,publish_time,ctime,reason, attributes, dynamic_intro, origin_image_urls FROM articles WHERE mid=? and deleted_time=0
  38. and state in (%s)`
  39. _upperArticleCountCreationSQL = "SELECT state FROM articles WHERE mid=? and deleted_time=0"
  40. _articleMetaCreationSQL = "SELECT id,category_id,title,summary,banner_url, template_id, state, mid, reprint, image_urls, publish_time,ctime, attributes, dynamic_intro, origin_image_urls, media_id, spoiler FROM articles WHERE id = ? and deleted_time = 0"
  41. _articleContentCreationSQL = "SELECT content FROM article_contents_%s WHERE article_id=? AND deleted_time=0"
  42. _countEditTimesSQL = "SELECT count(*) FROM article_histories_%s WHERE article_id=? AND deleted_time=0 AND state in (5,6,7)"
  43. _articleVersionSQL = "SELECT article_id,category_id,title,state,content,summary,banner_url,template_id,reprint,image_urls,attributes,words,dynamic_intro,origin_image_urls,media_id,spoiler,apply_time,ext_msg FROM article_versions WHERE article_id=? AND deleted_time=0"
  44. _reasonOfVersion = "SELECT reason FROM article_versions WHERE article_id=? AND state=? AND deleted_time=0 ORDER BY id DESC LIMIT 1"
  45. )
  46. // TxAddArticleMeta adds article's meta via transaction.
  47. func (d *Dao) TxAddArticleMeta(c context.Context, tx *xsql.Tx, a *artmdl.Meta, actID int64) (id int64, err error) {
  48. a.ImageURLs = artmdl.CleanURLs(a.ImageURLs)
  49. a.OriginImageURLs = artmdl.CleanURLs(a.OriginImageURLs)
  50. a.BannerURL = artmdl.CleanURL(a.BannerURL)
  51. var (
  52. res sql.Result
  53. imageUrls = strings.Join(a.ImageURLs, ",")
  54. originImageUrls = strings.Join(a.OriginImageURLs, ",")
  55. applyTime = time.Now().Format("2006-01-02 15:04:05")
  56. )
  57. if res, err = tx.Exec(_addArticleMetaSQL, a.Category.ID, a.Title, a.Summary, a.BannerURL, a.TemplateID, a.State, a.Author.Mid, a.Reprint, imageUrls, a.Attributes, a.Words, a.Dynamic, originImageUrls, actID, a.Media.MediaID, a.Media.Spoiler, applyTime); err != nil {
  58. PromError("db:新增文章meta")
  59. log.Error("tx.Exec() error(%+v)", err)
  60. return
  61. }
  62. if id, err = res.LastInsertId(); err != nil {
  63. log.Error("res.LastInsertId() error(%+v)", err)
  64. }
  65. return
  66. }
  67. // TxAddArticleContent adds article's body via transaction.
  68. func (d *Dao) TxAddArticleContent(c context.Context, tx *xsql.Tx, aid int64, content string, tags []string) (err error) {
  69. var sqlStr = fmt.Sprintf(_addArticleContentSQL, d.hit(aid))
  70. if _, err = tx.Exec(sqlStr, aid, content, strings.Join(tags, "\001")); err != nil {
  71. PromError("db:新增文章content")
  72. log.Error("tx.Exec(%s,%d) error(%+v)", sqlStr, aid, err)
  73. }
  74. return
  75. }
  76. // TxAddArticleVersion adds article version.
  77. func (d *Dao) TxAddArticleVersion(c context.Context, tx *xsql.Tx, id int64, a *artmdl.Article, actID int64) (err error) {
  78. a.ImageURLs = artmdl.CleanURLs(a.ImageURLs)
  79. a.OriginImageURLs = artmdl.CleanURLs(a.OriginImageURLs)
  80. a.BannerURL = artmdl.CleanURL(a.BannerURL)
  81. var (
  82. applyTime = time.Now().Format("2006-01-02 15:04:05")
  83. imageUrls = strings.Join(a.ImageURLs, ",")
  84. originImageUrls = strings.Join(a.OriginImageURLs, ",")
  85. extMsg = &artmdl.ExtMsg{
  86. Tags: a.Tags,
  87. }
  88. extStr []byte
  89. )
  90. if extStr, err = json.Marshal(extMsg); err != nil {
  91. log.Error("json.Marshal error(%+v)", err)
  92. return
  93. }
  94. if _, err = tx.Exec(_addArticleVersionSQL, id, a.Category.ID, a.Title, a.State, a.Content, a.Summary, a.BannerURL, a.TemplateID, a.Author.Mid, a.Reprint, imageUrls, a.Attributes, a.Words, a.Dynamic, originImageUrls, actID, a.Media.MediaID, a.Media.Spoiler, applyTime, string(extStr)); err != nil {
  95. PromError("db:新增版本")
  96. log.Error("tx.Exec() error(%+v)", err)
  97. }
  98. return
  99. }
  100. // TxUpdateArticleVersion updates article version.
  101. func (d *Dao) TxUpdateArticleVersion(c context.Context, tx *xsql.Tx, id int64, a *artmdl.Article, actID int64) (err error) {
  102. a.ImageURLs = artmdl.CleanURLs(a.ImageURLs)
  103. a.OriginImageURLs = artmdl.CleanURLs(a.OriginImageURLs)
  104. a.BannerURL = artmdl.CleanURL(a.BannerURL)
  105. var (
  106. applyTime = time.Now().Format("2006-01-02 15:04:05")
  107. imageUrls = strings.Join(a.ImageURLs, ",")
  108. originImageUrls = strings.Join(a.OriginImageURLs, ",")
  109. extMsg = &artmdl.ExtMsg{
  110. Tags: a.Tags,
  111. }
  112. extStr []byte
  113. )
  114. if extStr, err = json.Marshal(extMsg); err != nil {
  115. log.Error("json.Marshal error(%+v)", err)
  116. return
  117. }
  118. if _, err = tx.Exec(_updateArticleVersionSQL, a.Category.ID, a.Title, a.State, a.Content, a.Summary, a.BannerURL, a.TemplateID, a.Author.Mid, a.Reprint, imageUrls, a.Attributes, a.Words, a.Dynamic, originImageUrls, a.Media.Spoiler, applyTime, string(extStr), id); err != nil {
  119. PromError("db:更新版本")
  120. log.Error("tx.Exec() error(%+v)", err)
  121. }
  122. return
  123. }
  124. // TxUpdateArticleMeta updates article's meta via transaction.
  125. func (d *Dao) TxUpdateArticleMeta(c context.Context, tx *xsql.Tx, a *artmdl.Meta) (err error) {
  126. a.ImageURLs = artmdl.CleanURLs(a.ImageURLs)
  127. a.OriginImageURLs = artmdl.CleanURLs(a.OriginImageURLs)
  128. a.BannerURL = artmdl.CleanURL(a.BannerURL)
  129. var (
  130. imageURLs = strings.Join(a.ImageURLs, ",")
  131. originImageURLs = strings.Join(a.OriginImageURLs, ",")
  132. applyTime = time.Now().Format("2006-01-02 15:04:05")
  133. )
  134. if _, err = tx.Exec(_updateArticleMetaSQL, a.Category.ID, a.Title, a.Summary, a.BannerURL, a.TemplateID, a.State, a.Author.Mid, a.Reprint, imageURLs, a.Attributes, a.Words, a.Dynamic, originImageURLs, a.Media.Spoiler, applyTime, a.ID); err != nil {
  135. PromError("db:更新文章meta")
  136. log.Error("tx.Exec() error(%+v)", err)
  137. }
  138. return
  139. }
  140. // TxUpdateArticleContent updates article's body via transaction.
  141. func (d *Dao) TxUpdateArticleContent(c context.Context, tx *xsql.Tx, aid int64, content string, tags []string) (err error) {
  142. var sqlStr = fmt.Sprintf(_updateArticleContentSQL, d.hit(aid))
  143. if _, err = tx.Exec(sqlStr, content, strings.Join(tags, "\001"), aid); err != nil {
  144. PromError("db:更新文章content")
  145. log.Error("tx.Exec(%s,%d) error(%+v)", sqlStr, aid, err)
  146. }
  147. return
  148. }
  149. // TxDeleteArticleMeta deletes article's meta via transaction.
  150. func (d *Dao) TxDeleteArticleMeta(c context.Context, tx *xsql.Tx, aid int64) (err error) {
  151. var now = time.Now().Unix()
  152. if _, err = tx.Exec(_deleteArticleMetaSQL, now, aid); err != nil {
  153. PromError("db:删除文章meta")
  154. log.Error("tx.Exec() error(%+v)", err)
  155. }
  156. return
  157. }
  158. // TxDeleteArticleContent deletes article's meta via transaction.
  159. func (d *Dao) TxDeleteArticleContent(c context.Context, tx *xsql.Tx, aid int64) (err error) {
  160. var (
  161. now = time.Now().Unix()
  162. sqlStr = fmt.Sprintf(_deleteArticleContentSQL, d.hit(aid))
  163. )
  164. if _, err = tx.Exec(sqlStr, now, aid); err != nil {
  165. PromError("db:删除文章content")
  166. log.Error("tx.Exec(%s,%d,%d) error(%+v)", sqlStr, now, aid, err)
  167. }
  168. return
  169. }
  170. // TxDelArticleVersion deletes article version.
  171. func (d *Dao) TxDelArticleVersion(c context.Context, tx *xsql.Tx, aid int64) (err error) {
  172. var now = time.Now().Unix()
  173. if _, err = tx.Exec(_deleteArticleVerionSQL, now, aid); err != nil {
  174. PromError("db:删除文章版本content")
  175. log.Error("tx.Exec(%s,%d,%d) error(%+v)", _deleteArticleVerionSQL, now, aid, err)
  176. }
  177. return
  178. }
  179. // TxDelFilteredArtMeta delete filetered article meta
  180. func (d *Dao) TxDelFilteredArtMeta(c context.Context, tx *xsql.Tx, aid int64) (err error) {
  181. if _, err = tx.Exec(_delFilteredArtMetaSQL, aid); err != nil {
  182. PromError("db:删除过滤文章")
  183. log.Error("dao.DelFilteredArtMeta exec(%v) error(%+v)", aid, err)
  184. }
  185. return
  186. }
  187. //TxDelFilteredArtContent delete filtered article content
  188. func (d *Dao) TxDelFilteredArtContent(c context.Context, tx *xsql.Tx, aid int64) (err error) {
  189. contentSQL := fmt.Sprintf(_delFilteredArtContentSQL, d.hit(aid))
  190. if _, err = tx.Exec(contentSQL, aid); err != nil {
  191. PromError("db:删除过滤文章正文")
  192. log.Error("dao.DelFilteredArtContent exec(%v) error(%+v)", aid, err)
  193. }
  194. return
  195. }
  196. // UpdateArticleState updates article's state.
  197. func (d *Dao) UpdateArticleState(c context.Context, aid int64, state int) (err error) {
  198. var res sql.Result
  199. if res, err = d.updateArticleStateStmt.Exec(c, state, aid); err != nil {
  200. PromError("db:更新文章状态")
  201. log.Error("s.dao.UpdateArticleState.Exec(aid: %v, state: %v) error(%+v)", aid, state, err)
  202. return
  203. }
  204. if count, _ := res.RowsAffected(); count == 0 {
  205. err = ecode.NothingFound
  206. }
  207. return
  208. }
  209. // TxUpdateArticleState updates article's state.
  210. func (d *Dao) TxUpdateArticleState(c context.Context, tx *xsql.Tx, aid int64, state int32) (err error) {
  211. var res sql.Result
  212. if res, err = tx.Exec(_updateArticleStateSQL, state, aid); err != nil {
  213. PromError("db:更新文章状态")
  214. log.Error("s.dao.TxUpdateArticleState.Exec(aid: %v, state: %v) error(%+v)", aid, state, err)
  215. return
  216. }
  217. if count, _ := res.RowsAffected(); count == 0 {
  218. err = ecode.NothingFound
  219. }
  220. return
  221. }
  222. // TxUpdateArticleStateApplyTime updates article's state and apply time.
  223. func (d *Dao) TxUpdateArticleStateApplyTime(c context.Context, tx *xsql.Tx, aid int64, state int32) (err error) {
  224. var (
  225. res sql.Result
  226. applyTime = time.Now().Format("2006-01-02 15:03:04")
  227. )
  228. if res, err = tx.Exec(_updateArticleStateApplyTimeSQL, state, applyTime, aid); err != nil {
  229. PromError("db:更新文章状态和申请时间")
  230. log.Error("s.dao.TxUpdateArticleStateApplyTime.Exec(aid: %v, state: %v) error(%+v)", aid, state, err)
  231. return
  232. }
  233. if count, _ := res.RowsAffected(); count == 0 {
  234. err = ecode.NothingFound
  235. }
  236. return
  237. }
  238. // UpperArticlesMeta gets article list by mid.
  239. func (d *Dao) UpperArticlesMeta(c context.Context, mid int64, group, category int) (as []*artmdl.Meta, err error) {
  240. var (
  241. rows *xsql.Rows
  242. sqlStr string
  243. )
  244. sqlStr = fmt.Sprintf(_upperArticlesMetaCreationSQL, xstr.JoinInts(artmdl.Group2State(group)))
  245. if category > 0 {
  246. sqlStr += " and category_id=" + strconv.Itoa(category)
  247. }
  248. if rows, err = d.articleDB.Query(c, sqlStr, mid); err != nil {
  249. PromError("db:获取文章meta")
  250. log.Error("d.articleDB.Query(%s,%s) error(%+v)", sqlStr, err)
  251. return
  252. }
  253. defer rows.Close()
  254. for rows.Next() {
  255. a := &artmdl.Meta{Category: &artmdl.Category{}, Author: &artmdl.Author{}}
  256. var (
  257. ptime int64
  258. ctime time.Time
  259. imageURLs, originImageURLs string
  260. )
  261. if err = rows.Scan(&a.ID, &a.Category.ID, &a.Title, &a.Summary, &a.BannerURL, &a.TemplateID, &a.State, &a.Author.Mid, &a.Reprint, &imageURLs, &ptime, &ctime, &a.Reason, &a.Attributes, &a.Dynamic, &originImageURLs); err != nil {
  262. promErrorCheck(err)
  263. log.Error("rows.Scan error(%+v)", err)
  264. return
  265. }
  266. if imageURLs == "" {
  267. a.ImageURLs = []string{}
  268. } else {
  269. a.ImageURLs = strings.Split(imageURLs, ",")
  270. }
  271. if originImageURLs == "" {
  272. a.OriginImageURLs = []string{}
  273. } else {
  274. a.OriginImageURLs = strings.Split(originImageURLs, ",")
  275. }
  276. a.PublishTime = xtime.Time(ptime)
  277. a.Ctime = xtime.Time(ctime.Unix())
  278. a.BannerURL = artmdl.CompleteURL(a.BannerURL)
  279. a.ImageURLs = artmdl.CompleteURLs(a.ImageURLs)
  280. a.OriginImageURLs = artmdl.CompleteURLs(a.OriginImageURLs)
  281. as = append(as, a)
  282. }
  283. err = rows.Err()
  284. promErrorCheck(err)
  285. return
  286. }
  287. // UpperArticlesTypeCount gets article count by type.
  288. func (d *Dao) UpperArticlesTypeCount(c context.Context, mid int64) (res *artmdl.CreationArtsType, err error) {
  289. var rows *xsql.Rows
  290. res = &artmdl.CreationArtsType{}
  291. if rows, err = d.upperArtCntCreationStmt.Query(c, mid); err != nil {
  292. PromError("db:获取各种文章状态总数")
  293. log.Error("d.articleDB.Query(%d) error(%+v)", mid, err)
  294. return
  295. }
  296. defer rows.Close()
  297. for rows.Next() {
  298. var state int
  299. if err = rows.Scan(&state); err != nil {
  300. promErrorCheck(err)
  301. return
  302. }
  303. switch state {
  304. case artmdl.StateAutoLock, artmdl.StateLock, artmdl.StateReject, artmdl.StateOpenReject:
  305. res.NotPassed++
  306. case artmdl.StateAutoPass, artmdl.StateOpen, artmdl.StateRePass, artmdl.StateReReject:
  307. res.Passed++
  308. case artmdl.StatePending, artmdl.StateOpenPending, artmdl.StateRePending:
  309. res.Audit++
  310. }
  311. }
  312. err = rows.Err()
  313. promErrorCheck(err)
  314. res.All = res.NotPassed + res.Passed + res.Audit
  315. return
  316. }
  317. // CreationArticleMeta querys article's meta info for creation center by aid.
  318. func (d *Dao) CreationArticleMeta(c context.Context, id int64) (am *artmdl.Meta, err error) {
  319. var (
  320. imageURLs, originImageURLs string
  321. category = &artmdl.Category{}
  322. author = &artmdl.Author{}
  323. ptime int64
  324. ct time.Time
  325. )
  326. am = &artmdl.Meta{Media: &artmdl.Media{}}
  327. if err = d.articleMetaCreationStmt.QueryRow(c, id).Scan(&am.ID, &category.ID, &am.Title, &am.Summary,
  328. &am.BannerURL, &am.TemplateID, &am.State, &author.Mid, &am.Reprint, &imageURLs, &ptime, &ct, &am.Attributes, &am.Dynamic, &originImageURLs, &am.Media.MediaID, &am.Media.Spoiler); err != nil {
  329. if err == sql.ErrNoRows {
  330. err = nil
  331. am = nil
  332. return
  333. }
  334. PromError("db:文章内容表")
  335. log.Error("row.ArticleContent.QueryRow error(%+v)", err)
  336. return
  337. }
  338. am.Category = category
  339. am.Author = author
  340. am.Ctime = xtime.Time(ct.Unix())
  341. if imageURLs == "" {
  342. am.ImageURLs = []string{}
  343. } else {
  344. am.ImageURLs = strings.Split(imageURLs, ",")
  345. }
  346. if originImageURLs == "" {
  347. am.OriginImageURLs = []string{}
  348. } else {
  349. am.OriginImageURLs = strings.Split(originImageURLs, ",")
  350. }
  351. am.PublishTime = xtime.Time(ptime)
  352. am.BannerURL = artmdl.CompleteURL(am.BannerURL)
  353. am.ImageURLs = artmdl.CompleteURLs(am.ImageURLs)
  354. am.OriginImageURLs = artmdl.CompleteURLs(am.OriginImageURLs)
  355. return
  356. }
  357. // CreationArticleContent gets article's content.
  358. func (d *Dao) CreationArticleContent(c context.Context, aid int64) (res string, err error) {
  359. contentSQL := fmt.Sprintf(_articleContentCreationSQL, d.hit(aid))
  360. if err = d.articleDB.QueryRow(c, contentSQL, aid).Scan(&res); err != nil {
  361. if err == sql.ErrNoRows {
  362. err = nil
  363. return
  364. }
  365. PromError("db:CreationArticleContent")
  366. log.Error("dao.CreationArticleContent(%s) error(%+v)", contentSQL, err)
  367. }
  368. return
  369. }
  370. // UploadImage upload bfs.
  371. func (d *Dao) UploadImage(c context.Context, fileType string, bs []byte) (location string, err error) {
  372. req, err := http.NewRequest(d.c.BFS.Method, d.c.BFS.URL, bytes.NewBuffer(bs))
  373. if err != nil {
  374. PromError("creation:UploadImage")
  375. log.Error("creation: http.NewRequest error (%v) | fileType(%s)", err, fileType)
  376. return
  377. }
  378. expire := time.Now().Unix()
  379. authorization := authorize(d.c.BFS.Key, d.c.BFS.Secret, d.c.BFS.Method, d.c.BFS.Bucket, expire)
  380. req.Header.Set("Host", d.c.BFS.URL)
  381. req.Header.Add("Date", fmt.Sprint(expire))
  382. req.Header.Add("Authorization", authorization)
  383. req.Header.Add("Content-Type", fileType)
  384. // timeout
  385. ctx, cancel := context.WithTimeout(c, time.Duration(d.c.BFS.Timeout))
  386. req = req.WithContext(ctx)
  387. defer cancel()
  388. resp, err := d.bfsClient.Do(req)
  389. if err != nil {
  390. PromError("creation:UploadImage")
  391. log.Error("creation: d.Client.Do error(%v) | url(%s)", err, d.c.BFS.URL)
  392. err = ecode.BfsUploadServiceUnavailable
  393. return
  394. }
  395. if resp.StatusCode != http.StatusOK {
  396. log.Error("creation: Upload http.StatusCode nq http.StatusOK (%d) | url(%s)", resp.StatusCode, d.c.BFS.URL)
  397. PromError("creation:UploadImage")
  398. err = errors.New("Upload failed")
  399. return
  400. }
  401. header := resp.Header
  402. code := header.Get("Code")
  403. if code != strconv.Itoa(http.StatusOK) {
  404. log.Error("creation: strconv.Itoa err, code(%s) | url(%s)", code, d.c.BFS.URL)
  405. PromError("creation:UploadImage")
  406. err = errors.New("Upload failed")
  407. return
  408. }
  409. location = header.Get("Location")
  410. return
  411. }
  412. // authorize returns authorization for upload file to bfs
  413. func authorize(key, secret, method, bucket string, expire int64) (authorization string) {
  414. var (
  415. content string
  416. mac hash.Hash
  417. signature string
  418. )
  419. content = fmt.Sprintf("%s\n%s\n\n%d\n", method, bucket, expire)
  420. mac = hmac.New(sha1.New, []byte(secret))
  421. mac.Write([]byte(content))
  422. signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
  423. authorization = fmt.Sprintf("%s:%s:%d", key, signature, expire)
  424. return
  425. }
  426. // EditTimes count times of article edited.
  427. func (d *Dao) EditTimes(c context.Context, id int64) (count int, err error) {
  428. var sqlStr = fmt.Sprintf(_countEditTimesSQL, d.hit(id))
  429. row := d.articleDB.QueryRow(c, sqlStr, id)
  430. if err = row.Scan(&count); err != nil {
  431. if err == sql.ErrNoRows {
  432. err = nil
  433. return
  434. }
  435. PromError("db:EditTimes")
  436. log.Error("dao.EditTimes error(%+v)", err)
  437. }
  438. return
  439. }
  440. // ArticleVersion .
  441. func (d *Dao) ArticleVersion(c context.Context, aid int64) (a *artmdl.Article, err error) {
  442. var (
  443. extStr string
  444. extMsg artmdl.ExtMsg
  445. imageURLs, originURLs string
  446. )
  447. row := d.articleDB.QueryRow(c, _articleVersionSQL, aid)
  448. a = &artmdl.Article{
  449. Meta: &artmdl.Meta{
  450. Media: &artmdl.Media{},
  451. Category: &artmdl.Category{},
  452. List: &artmdl.List{},
  453. },
  454. }
  455. if err = row.Scan(&a.ID, &a.Category.ID, &a.Title, &a.State, &a.Content, &a.Summary, &a.BannerURL, &a.TemplateID, &a.Reprint, &imageURLs, &a.Attributes, &a.Words, &a.Dynamic, &originURLs, &a.Media.MediaID, &a.Media.Spoiler, &a.ApplyTime, &extStr); err != nil {
  456. log.Error("dao.ArticleHistory.Scan error(%+v)", err)
  457. return
  458. }
  459. if err = json.Unmarshal([]byte(extStr), &extMsg); err != nil {
  460. log.Error("dao.ArticleHistory.Unmarshal error(%+v)", err)
  461. return
  462. }
  463. a.ImageURLs = strings.Split(imageURLs, ",")
  464. a.OriginImageURLs = strings.Split(originURLs, ",")
  465. a.BannerURL = artmdl.CompleteURL(a.BannerURL)
  466. a.ImageURLs = artmdl.CompleteURLs(a.ImageURLs)
  467. a.OriginImageURLs = artmdl.CompleteURLs(a.OriginImageURLs)
  468. a.Tags = extMsg.Tags
  469. return
  470. }
  471. // LastReason return last reason from article_versions by aid and state.
  472. func (d *Dao) LastReason(c context.Context, id int64, state int32) (res string, err error) {
  473. if err = d.articleDB.QueryRow(c, _reasonOfVersion, id, state).Scan(&res); err != nil {
  474. if err == sql.ErrNoRows {
  475. err = nil
  476. return
  477. }
  478. PromError("db:LastReason")
  479. log.Error("dao.LastReason(%s) error(%+v)", _reasonOfVersion, err)
  480. }
  481. return
  482. }