2
1

account.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. import * as Sequelize from 'sequelize'
  2. import {
  3. AllowNull,
  4. BeforeDestroy,
  5. BelongsTo,
  6. Column,
  7. CreatedAt,
  8. Default,
  9. DefaultScope,
  10. ForeignKey,
  11. HasMany,
  12. Is,
  13. Model,
  14. Table,
  15. UpdatedAt
  16. } from 'sequelize-typescript'
  17. import { Account } from '../../../shared/models/actors'
  18. import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts'
  19. import { sendDeleteActor } from '../../lib/activitypub/send'
  20. import { ActorModel } from '../activitypub/actor'
  21. import { ApplicationModel } from '../application/application'
  22. import { ServerModel } from '../server/server'
  23. import { getSort, throwIfNotValid } from '../utils'
  24. import { VideoChannelModel } from '../video/video-channel'
  25. import { VideoCommentModel } from '../video/video-comment'
  26. import { UserModel } from './user'
  27. @DefaultScope({
  28. include: [
  29. {
  30. model: () => ActorModel, // Default scope includes avatar and server
  31. required: true
  32. }
  33. ]
  34. })
  35. @Table({
  36. tableName: 'account',
  37. indexes: [
  38. {
  39. fields: [ 'actorId' ],
  40. unique: true
  41. },
  42. {
  43. fields: [ 'applicationId' ]
  44. },
  45. {
  46. fields: [ 'userId' ]
  47. }
  48. ]
  49. })
  50. export class AccountModel extends Model<AccountModel> {
  51. @AllowNull(false)
  52. @Column
  53. name: string
  54. @AllowNull(true)
  55. @Default(null)
  56. @Is('AccountDescription', value => throwIfNotValid(value, isAccountDescriptionValid, 'description'))
  57. @Column
  58. description: string
  59. @CreatedAt
  60. createdAt: Date
  61. @UpdatedAt
  62. updatedAt: Date
  63. @ForeignKey(() => ActorModel)
  64. @Column
  65. actorId: number
  66. @BelongsTo(() => ActorModel, {
  67. foreignKey: {
  68. allowNull: false
  69. },
  70. onDelete: 'cascade'
  71. })
  72. Actor: ActorModel
  73. @ForeignKey(() => UserModel)
  74. @Column
  75. userId: number
  76. @BelongsTo(() => UserModel, {
  77. foreignKey: {
  78. allowNull: true
  79. },
  80. onDelete: 'cascade'
  81. })
  82. User: UserModel
  83. @ForeignKey(() => ApplicationModel)
  84. @Column
  85. applicationId: number
  86. @BelongsTo(() => ApplicationModel, {
  87. foreignKey: {
  88. allowNull: true
  89. },
  90. onDelete: 'cascade'
  91. })
  92. Application: ApplicationModel
  93. @HasMany(() => VideoChannelModel, {
  94. foreignKey: {
  95. allowNull: false
  96. },
  97. onDelete: 'cascade',
  98. hooks: true
  99. })
  100. VideoChannels: VideoChannelModel[]
  101. @HasMany(() => VideoCommentModel, {
  102. foreignKey: {
  103. allowNull: false
  104. },
  105. onDelete: 'cascade',
  106. hooks: true
  107. })
  108. VideoComments: VideoCommentModel[]
  109. @BeforeDestroy
  110. static async sendDeleteIfOwned (instance: AccountModel, options) {
  111. if (!instance.Actor) {
  112. instance.Actor = await instance.$get('Actor', { transaction: options.transaction }) as ActorModel
  113. }
  114. if (instance.isOwned()) {
  115. return sendDeleteActor(instance.Actor, options.transaction)
  116. }
  117. return undefined
  118. }
  119. static load (id: number, transaction?: Sequelize.Transaction) {
  120. return AccountModel.findById(id, { transaction })
  121. }
  122. static loadByUUID (uuid: string) {
  123. const query = {
  124. include: [
  125. {
  126. model: ActorModel,
  127. required: true,
  128. where: {
  129. uuid
  130. }
  131. }
  132. ]
  133. }
  134. return AccountModel.findOne(query)
  135. }
  136. static loadLocalByName (name: string) {
  137. const query = {
  138. where: {
  139. [ Sequelize.Op.or ]: [
  140. {
  141. userId: {
  142. [ Sequelize.Op.ne ]: null
  143. }
  144. },
  145. {
  146. applicationId: {
  147. [ Sequelize.Op.ne ]: null
  148. }
  149. }
  150. ]
  151. },
  152. include: [
  153. {
  154. model: ActorModel,
  155. required: true,
  156. where: {
  157. preferredUsername: name
  158. }
  159. }
  160. ]
  161. }
  162. return AccountModel.findOne(query)
  163. }
  164. static loadByNameAndHost (name: string, host: string) {
  165. const query = {
  166. include: [
  167. {
  168. model: ActorModel,
  169. required: true,
  170. where: {
  171. preferredUsername: name
  172. },
  173. include: [
  174. {
  175. model: ServerModel,
  176. required: true,
  177. where: {
  178. host
  179. }
  180. }
  181. ]
  182. }
  183. ]
  184. }
  185. return AccountModel.findOne(query)
  186. }
  187. static loadByUrl (url: string, transaction?: Sequelize.Transaction) {
  188. const query = {
  189. include: [
  190. {
  191. model: ActorModel,
  192. required: true,
  193. where: {
  194. url
  195. }
  196. }
  197. ],
  198. transaction
  199. }
  200. return AccountModel.findOne(query)
  201. }
  202. static listForApi (start: number, count: number, sort: string) {
  203. const query = {
  204. offset: start,
  205. limit: count,
  206. order: getSort(sort)
  207. }
  208. return AccountModel.findAndCountAll(query)
  209. .then(({ rows, count }) => {
  210. return {
  211. data: rows,
  212. total: count
  213. }
  214. })
  215. }
  216. static listLocalsForSitemap (sort: string) {
  217. const query = {
  218. attributes: [ ],
  219. offset: 0,
  220. order: getSort(sort),
  221. include: [
  222. {
  223. attributes: [ 'preferredUsername', 'serverId' ],
  224. model: ActorModel.unscoped(),
  225. where: {
  226. serverId: null
  227. }
  228. }
  229. ]
  230. }
  231. return AccountModel
  232. .unscoped()
  233. .findAll(query)
  234. }
  235. toFormattedJSON (): Account {
  236. const actor = this.Actor.toFormattedJSON()
  237. const account = {
  238. id: this.id,
  239. displayName: this.getDisplayName(),
  240. description: this.description,
  241. createdAt: this.createdAt,
  242. updatedAt: this.updatedAt,
  243. userId: this.userId ? this.userId : undefined
  244. }
  245. return Object.assign(actor, account)
  246. }
  247. toActivityPubObject () {
  248. const obj = this.Actor.toActivityPubObject(this.name, 'Account')
  249. return Object.assign(obj, {
  250. summary: this.description
  251. })
  252. }
  253. isOwned () {
  254. return this.Actor.isOwned()
  255. }
  256. getDisplayName () {
  257. return this.name
  258. }
  259. }