video-share.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import * as Sequelize from 'sequelize'
  2. import * as Bluebird from 'bluebird'
  3. import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
  4. import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
  5. import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
  6. import { AccountModel } from '../account/account'
  7. import { ActorModel } from '../activitypub/actor'
  8. import { throwIfNotValid } from '../utils'
  9. import { VideoModel } from './video'
  10. import { VideoChannelModel } from './video-channel'
  11. enum ScopeNames {
  12. FULL = 'FULL',
  13. WITH_ACTOR = 'WITH_ACTOR'
  14. }
  15. @Scopes(() => ({
  16. [ScopeNames.FULL]: {
  17. include: [
  18. {
  19. model: ActorModel,
  20. required: true
  21. },
  22. {
  23. model: VideoModel,
  24. required: true
  25. }
  26. ]
  27. },
  28. [ScopeNames.WITH_ACTOR]: {
  29. include: [
  30. {
  31. model: ActorModel,
  32. required: true
  33. }
  34. ]
  35. }
  36. }))
  37. @Table({
  38. tableName: 'videoShare',
  39. indexes: [
  40. {
  41. fields: [ 'actorId' ]
  42. },
  43. {
  44. fields: [ 'videoId' ]
  45. },
  46. {
  47. fields: [ 'url' ],
  48. unique: true
  49. }
  50. ]
  51. })
  52. export class VideoShareModel extends Model<VideoShareModel> {
  53. @AllowNull(false)
  54. @Is('VideoShareUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
  55. @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_SHARE.URL.max))
  56. url: string
  57. @CreatedAt
  58. createdAt: Date
  59. @UpdatedAt
  60. updatedAt: Date
  61. @ForeignKey(() => ActorModel)
  62. @Column
  63. actorId: number
  64. @BelongsTo(() => ActorModel, {
  65. foreignKey: {
  66. allowNull: false
  67. },
  68. onDelete: 'cascade'
  69. })
  70. Actor: ActorModel
  71. @ForeignKey(() => VideoModel)
  72. @Column
  73. videoId: number
  74. @BelongsTo(() => VideoModel, {
  75. foreignKey: {
  76. allowNull: false
  77. },
  78. onDelete: 'cascade'
  79. })
  80. Video: VideoModel
  81. static load (actorId: number, videoId: number, t?: Sequelize.Transaction) {
  82. return VideoShareModel.scope(ScopeNames.WITH_ACTOR).findOne({
  83. where: {
  84. actorId,
  85. videoId
  86. },
  87. transaction: t
  88. })
  89. }
  90. static loadByUrl (url: string, t: Sequelize.Transaction) {
  91. return VideoShareModel.scope(ScopeNames.FULL).findOne({
  92. where: {
  93. url
  94. },
  95. transaction: t
  96. })
  97. }
  98. static loadActorsByShare (videoId: number, t: Sequelize.Transaction) {
  99. const query = {
  100. where: {
  101. videoId
  102. },
  103. include: [
  104. {
  105. model: ActorModel,
  106. required: true
  107. }
  108. ],
  109. transaction: t
  110. }
  111. return VideoShareModel.scope(ScopeNames.FULL).findAll(query)
  112. .then(res => res.map(r => r.Actor))
  113. }
  114. static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> {
  115. const query = {
  116. attributes: [],
  117. include: [
  118. {
  119. model: ActorModel,
  120. required: true
  121. },
  122. {
  123. attributes: [],
  124. model: VideoModel,
  125. required: true,
  126. include: [
  127. {
  128. attributes: [],
  129. model: VideoChannelModel.unscoped(),
  130. required: true,
  131. include: [
  132. {
  133. attributes: [],
  134. model: AccountModel.unscoped(),
  135. required: true,
  136. where: {
  137. actorId: actorOwnerId
  138. }
  139. }
  140. ]
  141. }
  142. ]
  143. }
  144. ],
  145. transaction: t
  146. }
  147. return VideoShareModel.scope(ScopeNames.FULL).findAll(query)
  148. .then(res => res.map(r => r.Actor))
  149. }
  150. static loadActorsByVideoChannel (videoChannelId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> {
  151. const query = {
  152. attributes: [],
  153. include: [
  154. {
  155. model: ActorModel,
  156. required: true
  157. },
  158. {
  159. attributes: [],
  160. model: VideoModel,
  161. required: true,
  162. where: {
  163. channelId: videoChannelId
  164. }
  165. }
  166. ],
  167. transaction: t
  168. }
  169. return VideoShareModel.scope(ScopeNames.FULL)
  170. .findAll(query)
  171. .then(res => res.map(r => r.Actor))
  172. }
  173. static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Sequelize.Transaction) {
  174. const query = {
  175. offset: start,
  176. limit: count,
  177. where: {
  178. videoId
  179. },
  180. transaction: t
  181. }
  182. return VideoShareModel.findAndCountAll(query)
  183. }
  184. static cleanOldSharesOf (videoId: number, beforeUpdatedAt: Date) {
  185. const query = {
  186. where: {
  187. updatedAt: {
  188. [Sequelize.Op.lt]: beforeUpdatedAt
  189. },
  190. videoId
  191. }
  192. }
  193. return VideoShareModel.destroy(query)
  194. }
  195. }