index.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. const request = require('request')
  2. const purest = require('purest')({ request })
  3. const utils = require('../../helpers/utils')
  4. const logger = require('../../logger')
  5. const adapter = require('./adapter')
  6. const AuthError = require('../error')
  7. class Facebook {
  8. constructor (options) {
  9. this.authProvider = options.provider = Facebook.authProvider
  10. this.client = purest(options)
  11. }
  12. static get authProvider () {
  13. return 'facebook'
  14. }
  15. list ({ directory, token, query = {} }, done) {
  16. const qs = {
  17. fields: 'name,cover_photo,created_time,type'
  18. }
  19. if (query.cursor) {
  20. qs.after = query.cursor
  21. }
  22. let path = 'me/albums'
  23. if (directory) {
  24. path = `${directory}/photos`
  25. qs.fields = 'icon,images,name,width,height,created_time'
  26. }
  27. this.client
  28. .get(path)
  29. .qs(qs)
  30. .auth(token)
  31. .request((err, resp, body) => {
  32. if (err || resp.statusCode !== 200) {
  33. err = this._error(err, resp)
  34. logger.error(err, 'provider.facebook.list.error')
  35. return done(err)
  36. } else {
  37. this._getUsername(token, (err, username) => {
  38. err ? done(err) : done(null, this.adaptData(body, username, directory, query))
  39. })
  40. }
  41. })
  42. }
  43. _getUsername (token, done) {
  44. this.client
  45. .get('me')
  46. .qs({ fields: 'email' })
  47. .auth(token)
  48. .request((err, resp, body) => {
  49. if (err || resp.statusCode !== 200) {
  50. err = this._error(err, resp)
  51. logger.error(err, 'provider.facebook.user.error')
  52. return done(err)
  53. } else {
  54. done(null, body.email)
  55. }
  56. })
  57. }
  58. _getMediaUrl (body) {
  59. const sortedImages = adapter.sortImages(body.images)
  60. return sortedImages[sortedImages.length - 1].source
  61. }
  62. download ({ id, token }, onData) {
  63. return this.client
  64. .get(id)
  65. .qs({ fields: 'images' })
  66. .auth(token)
  67. .request((err, resp, body) => {
  68. if (err) return logger.error(err, 'provider.facebook.download.error')
  69. request(this._getMediaUrl(body))
  70. .on('data', onData)
  71. .on('end', () => onData(null))
  72. .on('error', (err) => {
  73. logger.error(err, 'provider.facebook.download.url.error')
  74. })
  75. })
  76. }
  77. thumbnail (_, done) {
  78. // not implementing this because a public thumbnail from facebook will be used instead
  79. const err = new Error('call to thumbnail is not implemented')
  80. logger.error(err, 'provider.facebook.thumbnail.error')
  81. return done(err)
  82. }
  83. size ({ id, token }, done) {
  84. return this.client
  85. .get(id)
  86. .qs({ fields: 'images' })
  87. .auth(token)
  88. .request((err, resp, body) => {
  89. if (err || resp.statusCode !== 200) {
  90. err = this._error(err, resp)
  91. logger.error(err, 'provider.facebook.size.error')
  92. return done(err)
  93. }
  94. utils.getURLMeta(this._getMediaUrl(body))
  95. .then(({ size }) => done(null, size))
  96. .catch((err) => {
  97. logger.error(err, 'provider.facebook.size.error')
  98. done()
  99. })
  100. })
  101. }
  102. adaptData (res, username, directory, currentQuery) {
  103. const data = { username: username, items: [] }
  104. const items = adapter.getItemSubList(res)
  105. items.forEach((item) => {
  106. data.items.push({
  107. isFolder: adapter.isFolder(item),
  108. icon: adapter.getItemIcon(item),
  109. name: adapter.getItemName(item),
  110. mimeType: adapter.getMimeType(item),
  111. id: adapter.getItemId(item),
  112. thumbnail: adapter.getItemThumbnailUrl(item),
  113. requestPath: adapter.getItemRequestPath(item),
  114. modifiedDate: adapter.getItemModifiedDate(item)
  115. })
  116. })
  117. data.nextPagePath = adapter.getNextPagePath(res, currentQuery, directory)
  118. return data
  119. }
  120. _error (err, resp) {
  121. if (resp) {
  122. if (resp.body && resp.body.error.code === 190) {
  123. // Invalid OAuth 2.0 Access Token
  124. return new AuthError()
  125. }
  126. const msg = resp.body && resp.body.error ? resp.body.error.message : ''
  127. return new Error(`request to ${this.authProvider} returned status: ${resp.statusCode}, message: ${msg}`)
  128. }
  129. return err
  130. }
  131. }
  132. module.exports = Facebook