server-blocklist.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import { Op, QueryTypes } from 'sequelize'
  2. import { BelongsTo, Column, CreatedAt, ForeignKey, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
  3. import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/types/models/index.js'
  4. import { ServerBlock } from '@peertube/peertube-models'
  5. import { AccountModel } from '../account/account.js'
  6. import { SequelizeModel, createSafeIn, getSort, searchAttribute } from '../shared/index.js'
  7. import { ServerModel } from './server.js'
  8. enum ScopeNames {
  9. WITH_ACCOUNT = 'WITH_ACCOUNT',
  10. WITH_SERVER = 'WITH_SERVER'
  11. }
  12. @Scopes(() => ({
  13. [ScopeNames.WITH_ACCOUNT]: {
  14. include: [
  15. {
  16. model: AccountModel,
  17. required: true
  18. }
  19. ]
  20. },
  21. [ScopeNames.WITH_SERVER]: {
  22. include: [
  23. {
  24. model: ServerModel,
  25. required: true
  26. }
  27. ]
  28. }
  29. }))
  30. @Table({
  31. tableName: 'serverBlocklist',
  32. indexes: [
  33. {
  34. fields: [ 'accountId', 'targetServerId' ],
  35. unique: true
  36. },
  37. {
  38. fields: [ 'targetServerId' ]
  39. }
  40. ]
  41. })
  42. export class ServerBlocklistModel extends SequelizeModel<ServerBlocklistModel> {
  43. @CreatedAt
  44. createdAt: Date
  45. @UpdatedAt
  46. updatedAt: Date
  47. @ForeignKey(() => AccountModel)
  48. @Column
  49. accountId: number
  50. @BelongsTo(() => AccountModel, {
  51. foreignKey: {
  52. name: 'accountId',
  53. allowNull: false
  54. },
  55. onDelete: 'CASCADE'
  56. })
  57. ByAccount: Awaited<AccountModel>
  58. @ForeignKey(() => ServerModel)
  59. @Column
  60. targetServerId: number
  61. @BelongsTo(() => ServerModel, {
  62. foreignKey: {
  63. allowNull: false
  64. },
  65. onDelete: 'CASCADE'
  66. })
  67. BlockedServer: Awaited<ServerModel>
  68. static isServerMutedByAccounts (accountIds: number[], targetServerId: number) {
  69. const query = {
  70. attributes: [ 'accountId', 'id' ],
  71. where: {
  72. accountId: {
  73. [Op.in]: accountIds
  74. },
  75. targetServerId
  76. },
  77. raw: true
  78. }
  79. return ServerBlocklistModel.unscoped()
  80. .findAll(query)
  81. .then(rows => {
  82. const result: { [accountId: number]: boolean } = {}
  83. for (const accountId of accountIds) {
  84. result[accountId] = !!rows.find(r => r.accountId === accountId)
  85. }
  86. return result
  87. })
  88. }
  89. static loadByAccountAndHost (accountId: number, host: string): Promise<MServerBlocklist> {
  90. const query = {
  91. where: {
  92. accountId
  93. },
  94. include: [
  95. {
  96. model: ServerModel,
  97. where: {
  98. host
  99. },
  100. required: true
  101. }
  102. ]
  103. }
  104. return ServerBlocklistModel.findOne(query)
  105. }
  106. static listHostsBlockedBy (accountIds: number[]): Promise<string[]> {
  107. const query = {
  108. attributes: [ ],
  109. where: {
  110. accountId: {
  111. [Op.in]: accountIds
  112. }
  113. },
  114. include: [
  115. {
  116. attributes: [ 'host' ],
  117. model: ServerModel.unscoped(),
  118. required: true
  119. }
  120. ]
  121. }
  122. return ServerBlocklistModel.findAll(query)
  123. .then(entries => entries.map(e => e.BlockedServer.host))
  124. }
  125. static getBlockStatus (byAccountIds: number[], hosts: string[]): Promise<{ host: string, accountId: number }[]> {
  126. const rawQuery = `SELECT "server"."host", "serverBlocklist"."accountId" ` +
  127. `FROM "serverBlocklist" ` +
  128. `INNER JOIN "server" ON "server"."id" = "serverBlocklist"."targetServerId" ` +
  129. `WHERE "server"."host" IN (:hosts) ` +
  130. `AND "serverBlocklist"."accountId" IN (${createSafeIn(ServerBlocklistModel.sequelize, byAccountIds)})`
  131. return ServerBlocklistModel.sequelize.query(rawQuery, {
  132. type: QueryTypes.SELECT as QueryTypes.SELECT,
  133. replacements: { hosts }
  134. })
  135. }
  136. static listForApi (parameters: {
  137. start: number
  138. count: number
  139. sort: string
  140. search?: string
  141. accountId: number
  142. }) {
  143. const { start, count, sort, search, accountId } = parameters
  144. const query = {
  145. offset: start,
  146. limit: count,
  147. order: getSort(sort),
  148. where: {
  149. accountId,
  150. ...searchAttribute(search, '$BlockedServer.host$')
  151. }
  152. }
  153. return Promise.all([
  154. ServerBlocklistModel.scope(ScopeNames.WITH_SERVER).count(query),
  155. ServerBlocklistModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_SERVER ]).findAll<MServerBlocklistAccountServer>(query)
  156. ]).then(([ total, data ]) => ({ total, data }))
  157. }
  158. toFormattedJSON (this: MServerBlocklistFormattable): ServerBlock {
  159. return {
  160. byAccount: this.ByAccount.toFormattedJSON(),
  161. blockedServer: this.BlockedServer.toFormattedJSON(),
  162. createdAt: this.createdAt
  163. }
  164. }
  165. }