From 57ce741be285ee38c4fc25bc8047207b08d59008 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 30 Sep 2024 15:10:16 -0600 Subject: [PATCH 01/22] update mongo driver to v6.9.0 - remove old @type definitions - mongo now provides typescript types --- server/package.json | 8 +-- server/pnpm-lock.yaml | 117 ++++++++++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 45 deletions(-) diff --git a/server/package.json b/server/package.json index cf9032e030..afa13fe941 100644 --- a/server/package.json +++ b/server/package.json @@ -126,7 +126,7 @@ "metascraper-description": "^5.22.5", "metascraper-image": "^5.22.5", "metascraper-title": "^5.22.5", - "mongodb": "^3.5.9", + "mongodb": "^6.9.0", "mongodb-core": "^3.2.7", "ms": "^2.1.2", "node-fetch": "^2.6.1", @@ -201,7 +201,6 @@ "@types/luxon": "^1.22.0", "@types/marked": "^0.7.3", "@types/mini-css-extract-plugin": "^1.4.3", - "@types/mongodb": "3.1.22", "@types/ms": "^0.7.31", "@types/node": "^12.12.34", "@types/node-fetch": "^2.5.5", @@ -363,11 +362,6 @@ "Newer versions has problems with using nunjucks.", "Update when the following issue is resolved:", "https://github.com/tj/consolidate.js/issues/244" - ], - "@types/mongodb@3.1.22": [ - "Newer versions has problems with optional fields when querying with null", - "Update when the following issue is resolved:", - "https://github.com/DefinitelyTyped/DefinitelyTyped/issues/47686" ] }, "graphql-schema-linter": { diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml index dd0add7802..0c8d528adc 100644 --- a/server/pnpm-lock.yaml +++ b/server/pnpm-lock.yaml @@ -228,8 +228,8 @@ dependencies: specifier: ^5.22.5 version: 5.22.5 mongodb: - specifier: ^3.5.9 - version: 3.5.9 + specifier: ^6.9.0 + version: 6.9.0 mongodb-core: specifier: ^3.2.7 version: 3.2.7 @@ -448,9 +448,6 @@ devDependencies: '@types/mini-css-extract-plugin': specifier: ^1.4.3 version: 1.4.3(webpack-cli@3.3.12) - '@types/mongodb': - specifier: 3.1.22 - version: 3.1.22 '@types/ms': specifier: ^0.7.31 version: 0.7.31 @@ -3187,6 +3184,12 @@ packages: /@microsoft/fetch-event-source@2.0.1: resolution: {integrity: sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==} + /@mongodb-js/saslprep@1.1.9: + resolution: {integrity: sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==} + dependencies: + sparse-bitfield: 3.0.3 + dev: false + /@mrmlnc/readdir-enhanced@2.2.1: resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} engines: {node: '>=4'} @@ -3671,12 +3674,6 @@ packages: '@types/connect': 3.4.32 '@types/node': 12.20.55 - /@types/bson@4.0.2: - resolution: {integrity: sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==} - dependencies: - '@types/node': 18.11.5 - dev: true - /@types/bull@3.14.2: resolution: {integrity: sha512-+g3Qha7ObdadnM4v/Sz9WDx8eKEaRL4usQmkeUEC25uAltFLioDbAaLnUggfWHONVzW2AxOgzS19ekMmx6zLzA==} dependencies: @@ -4139,13 +4136,6 @@ packages: resolution: {integrity: sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==} dev: true - /@types/mongodb@3.1.22: - resolution: {integrity: sha512-hvNR0txBlJJAy1eZOeIDshW4dnQaC694COou4eHHaMdIcteCfoCQATD7sYNlXxNxfTc1iIbHUi7A8CAhQe08uA==} - dependencies: - '@types/bson': 4.0.2 - '@types/node': 18.11.5 - dev: true - /@types/ms@0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true @@ -4386,6 +4376,10 @@ packages: '@types/node': 18.11.5 dev: true + /@types/webidl-conversions@7.0.3: + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + dev: false + /@types/webpack-assets-manifest@4.0.2: resolution: {integrity: sha512-KIIJAyI3PeHgftaY7dxNvrgK7XeS/e2qUpxtsfprijq63BTsR5eOKKK5ZOwxxcuNyOoUU2Xjskx3XAUbHt2Nmg==} dependencies: @@ -4433,6 +4427,12 @@ packages: dependencies: '@types/node': 12.12.34 + /@types/whatwg-url@11.0.5: + resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + dependencies: + '@types/webidl-conversions': 7.0.3 + dev: false + /@types/ws@7.2.3: resolution: {integrity: sha512-VT/GK7nvDA7lfHy40G3LKM+ICqmdIsBLBHGXcWD97MtqQEjNMX+7Gudo8YGpaSlYdTX7IFThhCE8Jx09HegymQ==} dependencies: @@ -6590,13 +6590,6 @@ packages: resolution: {integrity: sha512-tbaUB1QpTIj4cKY8c1rvNAvEQXA+ekzHmbe4jzNfW3QWsF9GnnP/BRWyl6/qqS53heoYJ93naaFcm/jooONH8g==} dev: false - /bl@2.2.1: - resolution: {integrity: sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==} - dependencies: - readable-stream: 2.3.6 - safe-buffer: 5.2.1 - dev: false - /bl@3.0.1: resolution: {integrity: sha512-jrCW5ZhfQ/Vt07WX1Ngs+yn9BDqPL/gw28S7s9H6QK/gupnizNzJAss5akW20ISgOrbLTlXOOCTJeNUQqruAWQ==} dependencies: @@ -6811,6 +6804,11 @@ packages: engines: {node: '>=0.6.19'} dev: false + /bson@6.8.0: + resolution: {integrity: sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==} + engines: {node: '>=16.20.1'} + dev: false + /btoa@1.2.1: resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==} engines: {node: '>= 0.4.0'} @@ -14641,7 +14639,6 @@ packages: resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} requiresBuild: true dev: false - optional: true /mensch@0.3.4: resolution: {integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==} @@ -14960,6 +14957,13 @@ packages: /moment@2.29.4: resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} + /mongodb-connection-string-url@3.0.1: + resolution: {integrity: sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==} + dependencies: + '@types/whatwg-url': 11.0.5 + whatwg-url: 13.0.0 + dev: false + /mongodb-core@3.2.7: resolution: {integrity: sha512-WypKdLxFNPOH/Jy6i9z47IjG2wIldA54iDZBmHMINcgKOUcWJh8og+Wix76oGd7EyYkHJKssQ2FAOw5Su/n4XQ==} dependencies: @@ -14970,17 +14974,36 @@ packages: saslprep: 1.0.3 dev: false - /mongodb@3.5.9: - resolution: {integrity: sha512-vXHBY1CsGYcEPoVWhwgxIBeWqP3dSu9RuRDsoLRPTITrcrgm1f0Ubu1xqF9ozMwv53agmEiZm0YGo+7WL3Nbug==} - engines: {node: '>=4'} + /mongodb@6.9.0: + resolution: {integrity: sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==} + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.2.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true dependencies: - bl: 2.2.1 - bson: 1.1.4 - denque: 1.4.1 - require_optional: 1.0.1 - safe-buffer: 5.2.1 - optionalDependencies: - saslprep: 1.0.3 + '@mongodb-js/saslprep': 1.1.9 + bson: 6.8.0 + mongodb-connection-string-url: 3.0.1 dev: false /moo@0.5.1: @@ -17233,6 +17256,11 @@ packages: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: false + /pure-rand@6.0.3: resolution: {integrity: sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==} dev: true @@ -18737,7 +18765,6 @@ packages: dependencies: memory-pager: 1.5.0 dev: false - optional: true /spdx-correct@3.0.0: resolution: {integrity: sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==} @@ -19649,6 +19676,13 @@ packages: punycode: 2.1.1 dev: true + /tr46@4.1.1: + resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} + engines: {node: '>=14'} + dependencies: + punycode: 2.3.1 + dev: false + /traverse@0.6.6: resolution: {integrity: sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==} dev: true @@ -20697,7 +20731,6 @@ packages: /webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - dev: true /webpack-assets-manifest@4.0.6(webpack@4.46.0): resolution: {integrity: sha512-9MsBOINUoGcj3D7XHQOOuQri7VEDArkhn5gqnpCqPungLj8Vy3utlVZ6vddAVU5feYroj+DEncktbaZhnBxdeQ==} @@ -20977,6 +21010,14 @@ packages: webidl-conversions: 7.0.0 dev: true + /whatwg-url@13.0.0: + resolution: {integrity: sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==} + engines: {node: '>=16'} + dependencies: + tr46: 4.1.1 + webidl-conversions: 7.0.0 + dev: false + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: From 71f6275983b864ba7374aea87a838ca55ea5ae46 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 30 Sep 2024 15:16:08 -0600 Subject: [PATCH 02/22] WIP: update query types --- .../src/core/server/models/action/comment.ts | 12 +- .../src/core/server/models/comment/comment.ts | 14 +- .../server/models/comment/counts/counts.ts | 2 +- .../core/server/models/dsaReport/report.ts | 10 +- .../src/core/server/models/helpers/query.ts | 29 +- .../core/server/models/migration/migration.ts | 10 +- .../settings/signingSecret/signingSecret.ts | 4 +- server/src/core/server/models/site/index.ts | 2 +- server/src/core/server/models/story/story.ts | 30 +- .../models/tenant/externalModerationPhase.ts | 8 +- server/src/core/server/models/tenant/sso.ts | 4 +- .../src/core/server/models/tenant/tenant.ts | 20 +- .../server/models/tenant/webhookEndpoint.ts | 8 +- server/src/core/server/models/user/user.ts | 330 +++++++++--------- .../src/core/server/services/users/delete.ts | 2 +- .../core/server/stacks/reviewCommentAction.ts | 2 +- 16 files changed, 246 insertions(+), 241 deletions(-) diff --git a/server/src/core/server/models/action/comment.ts b/server/src/core/server/models/action/comment.ts index 2905771274..641a90eaa3 100644 --- a/server/src/core/server/models/action/comment.ts +++ b/server/src/core/server/models/action/comment.ts @@ -254,7 +254,7 @@ export async function createAction( }; // Extract the filter parameters. - const filter: FilterQuery = { + const filter = { tenantID, ...rest, }; @@ -283,7 +283,7 @@ export async function createAction( // False to return the updated document instead of the original document. // This lets us detect if the document was updated or not. - returnOriginal: false, + returnDocument: "after", }); // Check to see if this was a new action that was upserted, or one was found @@ -294,12 +294,12 @@ export async function createAction( // Because it's relevant that we know that the action was just created, or // was just looked up, we need to return the action with an object that // indicates if it was upserted. - const wasUpserted = result.value!.id === id; + const wasUpserted = result?.id === id; // Return the action that was created/found with a boolean indicating if this // action was just upserted (and therefore was newly created). return { - action: result.value!, + action: result!, wasUpserted, }; } @@ -494,8 +494,8 @@ export async function removeAction( // Remove the action from the database, returning the action that was deleted. const result = await mongo.commentActions().findOneAndDelete(filter); return { - action: result.value, - wasRemoved: Boolean(result.ok && result.value), + action: result ?? undefined, + wasRemoved: Boolean(result), }; } diff --git a/server/src/core/server/models/comment/comment.ts b/server/src/core/server/models/comment/comment.ts index ddadca204d..65d0468b02 100644 --- a/server/src/core/server/models/comment/comment.ts +++ b/server/src/core/server/models/comment/comment.ts @@ -253,7 +253,7 @@ export async function pushChildCommentIDOntoParent( $inc: { childCount: 1 }, }, { - returnOriginal: false, + returnDocument: "after", } ); @@ -379,7 +379,7 @@ export async function editComment( update, { // True to return the original document instead of the updated document. - returnOriginal: true, + returnDocument: "before", } ); if (!result.value) { @@ -854,7 +854,7 @@ export async function updateCommentEmbeddedAt( { // True to return the original document instead of the updated // document. - returnOriginal: true, + returnDocument: "before", } ); if (!result.value) { @@ -892,7 +892,7 @@ export async function updateCommentStatus( { // True to return the original document instead of the updated // document. - returnOriginal: true, + returnDocument: "before", } ); if (!result.value) { @@ -942,7 +942,7 @@ export async function updateCommentActionCounts( arrayFilters: [{ "revision.id": revisionID }], // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -1021,7 +1021,7 @@ export async function addCommentTag( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -1063,7 +1063,7 @@ export async function removeCommentTag( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { diff --git a/server/src/core/server/models/comment/counts/counts.ts b/server/src/core/server/models/comment/counts/counts.ts index 2dfc0a45f0..3ef3630db4 100644 --- a/server/src/core/server/models/comment/counts/counts.ts +++ b/server/src/core/server/models/comment/counts/counts.ts @@ -256,7 +256,7 @@ export async function updateRelatedCommentCounts< { $inc }, // False to return the updated document instead of the original // document. - { returnOriginal: false } + { returnDocument: "after" } ); return result.value || null; diff --git a/server/src/core/server/models/dsaReport/report.ts b/server/src/core/server/models/dsaReport/report.ts index c0af30359c..b41812de1a 100644 --- a/server/src/core/server/models/dsaReport/report.ts +++ b/server/src/core/server/models/dsaReport/report.ts @@ -335,7 +335,7 @@ export async function createDSAReportNote( history: note, }, }, - { returnOriginal: false } + { returnDocument: "after" } ); if (!updatedReport.value) { @@ -384,7 +384,7 @@ export async function createDSAReportShare( history: note, }, }, - { returnOriginal: false } + { returnDocument: "after" } ); if (!updatedReport.value) { @@ -422,7 +422,7 @@ export async function deleteDSAReportNote( history: { id: { $eq: id } }, }, }, - { returnOriginal: false } + { returnDocument: "after" } ); if (!updatedReport.value) { @@ -474,7 +474,7 @@ export async function changeDSAReportStatus( }, $set: { status }, }, - { returnOriginal: false } + { returnDocument: "after" } ); if (!updatedReport.value) { @@ -549,7 +549,7 @@ export async function makeDSAReportDecision( status: GQLDSAReportStatus.COMPLETED, }, }, - { returnOriginal: false } + { returnDocument: "after" } ); if (!updatedReport.value) { diff --git a/server/src/core/server/models/helpers/query.ts b/server/src/core/server/models/helpers/query.ts index 6dedecf7b8..4ad35bfcab 100644 --- a/server/src/core/server/models/helpers/query.ts +++ b/server/src/core/server/models/helpers/query.ts @@ -1,7 +1,13 @@ import { isUndefined, omitBy } from "lodash"; -import { Collection, Cursor, FilterQuery as MongoFilterQuery } from "mongodb"; +import { + Collection, + Document, + Filter, + FindCursor, + SortDirection, + WithId, +} from "mongodb"; -import { Writable } from "coral-common/common/lib/types"; import logger from "coral-server/logger"; /** @@ -9,20 +15,20 @@ import logger from "coral-server/logger"; * Writable, partial set of properties while also including MongoDB specific * properties (like $lt, or $gte). */ -export type FilterQuery = MongoFilterQuery>>; +export type FilterQuery = Filter; /** * Query is a convenience class used to wrap the existing MongoDB driver to * provide easier complex query management. */ -export default class Query { - public filter: FilterQuery; - public projection: FilterQuery; +export default class Query { + public filter: Filter; + public projection: Filter; private collection: Collection; private skip?: number; private limit?: number; - private sort?: object; + private sort?: { [key: string]: SortDirection }; constructor(collection: Collection) { this.collection = collection; @@ -33,12 +39,12 @@ export default class Query { * where will merge the given filter into the existing query. * @param filter the filter to merge into the existing query */ - public where(filter: FilterQuery): Query { + public where(filter: Filter): Query { this.filter = { ...this.filter, ...omitBy(filter, isUndefined) }; return this; } - public project(projection: FilterQuery): Query { + public project(projection: Filter): Query { this.projection = projection; return this; } @@ -65,7 +71,8 @@ export default class Query { * orderBy will apply sorting to the query filter when executed. * @param sort the sorting option for the documents */ - public orderBy(sort: object): Query { + public orderBy(sort: { [key: string]: SortDirection }): Query { + // todo: merge sort's together this.sort = { ...this.sort, ...sort }; return this; } @@ -73,7 +80,7 @@ export default class Query { /** * exec will return a cursor to the query. */ - public async exec(): Promise> { + public async exec(): Promise>> { logger.trace( { collection: this.collection.collectionName, diff --git a/server/src/core/server/models/migration/migration.ts b/server/src/core/server/models/migration/migration.ts index 726ad50e94..096efa7c02 100644 --- a/server/src/core/server/models/migration/migration.ts +++ b/server/src/core/server/models/migration/migration.ts @@ -33,15 +33,15 @@ export async function startMigration( }, { // False to return the updated document instead of the original document. - returnOriginal: false, + returnDocument: "after", upsert: true, } ); - if (!result.value) { + if (!result) { throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -71,11 +71,11 @@ async function updateMigrationState( }, { // False to return the updated document instead of the original document. - returnOriginal: false, + returnDocument: "after", } ); - return result.value || null; + return result; } export async function finishMigration( diff --git a/server/src/core/server/models/settings/signingSecret/signingSecret.ts b/server/src/core/server/models/settings/signingSecret/signingSecret.ts index 06f44b1789..e856af32f1 100644 --- a/server/src/core/server/models/settings/signingSecret/signingSecret.ts +++ b/server/src/core/server/models/settings/signingSecret/signingSecret.ts @@ -135,7 +135,7 @@ async function pushNewSigningSecret({ const options: FindOneAndUpdateOption = { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", }; if (id) { options.arrayFilters = [ @@ -246,7 +246,7 @@ async function deprecateOldSigningSecrets( const options: FindOneAndUpdateOption = { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", arrayFilters: [ // Select any signing secrets with the given ids. { "signingSecret.kid": { $in: secretKIDsToDeprecate } }, diff --git a/server/src/core/server/models/site/index.ts b/server/src/core/server/models/site/index.ts index 97f18cd8f5..226acaa6bd 100644 --- a/server/src/core/server/models/site/index.ts +++ b/server/src/core/server/models/site/index.ts @@ -167,7 +167,7 @@ export async function updateSite( update, // False to return the updated document instead of the original // document. - { returnOriginal: false } + { returnDocument: "after" } ); return result.value || null; } catch (err) { diff --git a/server/src/core/server/models/story/story.ts b/server/src/core/server/models/story/story.ts index 8a530a7e0e..291eb76af5 100644 --- a/server/src/core/server/models/story/story.ts +++ b/server/src/core/server/models/story/story.ts @@ -143,7 +143,7 @@ export async function upsertStory( url, }, }, - { returnOriginal: false } + { returnDocument: "after" } ); if (!result.ok || !result.value) { @@ -196,7 +196,7 @@ export async function upsertStory( // True to return the original document instead of the updated document. // This will ensure that when an upsert operation adds a new Story, it // should return null. - returnOriginal: true, + returnDocument: "before", } ); @@ -423,7 +423,7 @@ export async function updateStory( update, // False to return the updated document instead of the original // document. - { returnOriginal: false } + { returnDocument: "after" } ); if (!result.value) { throw new StoryNotFoundError(id); @@ -463,7 +463,7 @@ export async function updateStorySettings( update, // False to return the updated document instead of the original // document. - { returnOriginal: false } + { returnDocument: "after" } ); if (!result.value) { throw new StoryNotFoundError(id); @@ -494,7 +494,7 @@ export async function openStory( }, // False to return the updated document instead of the original // document. - { returnOriginal: false } + { returnDocument: "after" } ); if (!result.value) { throw new StoryNotFoundError(id); @@ -520,7 +520,7 @@ export async function closeStory( }, // False to return the updated document instead of the original // document. - { returnOriginal: false } + { returnDocument: "after" } ); if (!result.value) { throw new StoryNotFoundError(id); @@ -698,7 +698,7 @@ export async function addStoryExpert( }, }, { - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -725,7 +725,7 @@ export async function removeStoryExpert( }, }, { - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -752,7 +752,7 @@ export async function setStoryMode( }, }, { - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -813,7 +813,7 @@ export async function forceMarkStoryForArchiving( }, getMarkStoryForArchivingSetParam(now), { - returnOriginal: false, + returnDocument: "after", } ); @@ -836,7 +836,7 @@ export async function markStoryForArchiving( }, getMarkStoryForArchivingSetParam(now), { - returnOriginal: false, + returnDocument: "after", } ); @@ -865,7 +865,7 @@ export async function markStoryForUnarchiving( }, }, { - returnOriginal: false, + returnDocument: "after", } ); @@ -893,7 +893,7 @@ export async function retrieveStoryToBeUnarchived( }, }, { - returnOriginal: false, + returnDocument: "after", maxTimeMS: 30 * 60 * 1000, } ); @@ -995,7 +995,7 @@ export async function markStoryAsArchived( }, }, { - returnOriginal: false, + returnDocument: "after", } ); @@ -1022,7 +1022,7 @@ export async function markStoryAsUnarchived( }, }, { - returnOriginal: false, + returnDocument: "after", } ); diff --git a/server/src/core/server/models/tenant/externalModerationPhase.ts b/server/src/core/server/models/tenant/externalModerationPhase.ts index 46af68cd68..f8d3fb66af 100644 --- a/server/src/core/server/models/tenant/externalModerationPhase.ts +++ b/server/src/core/server/models/tenant/externalModerationPhase.ts @@ -61,7 +61,7 @@ export async function createTenantExternalModerationPhase( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -114,7 +114,7 @@ export async function updateTenantExternalModerationPhase( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", arrayFilters: [{ "phase.id": phaseID }], } ); @@ -157,7 +157,7 @@ export async function deleteTenantExternalModerationPhase( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -187,7 +187,7 @@ export async function deleteTenantExternalModerationPhaseSigningSecrets( }, }, }, - { returnOriginal: false, arrayFilters: [{ "phase.id": phaseID }] } + { returnDocument: "after", arrayFilters: [{ "phase.id": phaseID }] } ); if (!result.value) { const tenant = await retrieveTenant(mongo, id); diff --git a/server/src/core/server/models/tenant/sso.ts b/server/src/core/server/models/tenant/sso.ts index 8ec0218abd..7e8d3d8bf4 100644 --- a/server/src/core/server/models/tenant/sso.ts +++ b/server/src/core/server/models/tenant/sso.ts @@ -37,7 +37,7 @@ export async function deactivateTenantSSOSigningSecret( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", // Add an ArrayFilter to only update one of the keys. arrayFilters: [{ "signingSecrets.kid": kid }], } @@ -65,7 +65,7 @@ export async function deleteTenantSSOSigningSecret( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { diff --git a/server/src/core/server/models/tenant/tenant.ts b/server/src/core/server/models/tenant/tenant.ts index 27d2e489d6..7bd36bbad3 100644 --- a/server/src/core/server/models/tenant/tenant.ts +++ b/server/src/core/server/models/tenant/tenant.ts @@ -425,7 +425,7 @@ export async function updateTenant( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -452,7 +452,7 @@ export async function enableTenantFeatureFlag( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -479,7 +479,7 @@ export async function disableTenantFeatureFlag( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -514,7 +514,7 @@ export async function createTenantAnnouncement( }, }, { - returnOriginal: false, + returnDocument: "after", } ); return result.value; @@ -545,7 +545,7 @@ export async function createTenantFlairBadge( $push: { "flairBadges.badges": { name: input.name, url: input.url } }, }, { - returnOriginal: false, + returnDocument: "after", } ); return result.value; @@ -568,7 +568,7 @@ export async function deleteTenantFlairBadge( }, }, { - returnOriginal: false, + returnDocument: "after", } ); return result.value; @@ -607,7 +607,7 @@ export async function createTenantEmailDomain( $push: { emailDomainModeration: emailDomain }, }, { - returnOriginal: false, + returnDocument: "after", } ); return result.value; @@ -650,7 +650,7 @@ export async function updateTenantEmailDomain( }, }, { - returnOriginal: false, + returnDocument: "after", } ); return result.value; @@ -673,7 +673,7 @@ export async function deleteTenantEmailDomain( }, }, { - returnOriginal: false, + returnDocument: "after", } ); return result.value; @@ -691,7 +691,7 @@ export async function deleteTenantAnnouncement( }, }, { - returnOriginal: false, + returnDocument: "after", } ); return result.value; diff --git a/server/src/core/server/models/tenant/webhookEndpoint.ts b/server/src/core/server/models/tenant/webhookEndpoint.ts index 59cadd7b34..946b3c7a88 100644 --- a/server/src/core/server/models/tenant/webhookEndpoint.ts +++ b/server/src/core/server/models/tenant/webhookEndpoint.ts @@ -57,7 +57,7 @@ export async function createTenantWebhookEndpoint( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { @@ -109,7 +109,7 @@ export async function updateTenantWebhookEndpoint( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", arrayFilters: [{ "endpoint.id": endpointID }], } ); @@ -145,7 +145,7 @@ export async function deleteTenantWebhookEndpointSigningSecrets( "webhooks.endpoints.$[endpoint].signingSecrets": { kid: { $in: kids } }, }, }, - { returnOriginal: false, arrayFilters: [{ "endpoint.id": endpointID }] } + { returnDocument: "after", arrayFilters: [{ "endpoint.id": endpointID }] } ); if (!result.value) { const tenant = await retrieveTenant(mongo, id); @@ -181,7 +181,7 @@ export async function deleteTenantWebhookEndpoint( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); if (!result.value) { diff --git a/server/src/core/server/models/user/user.ts b/server/src/core/server/models/user/user.ts index b084fc1a81..046252c61f 100644 --- a/server/src/core/server/models/user/user.ts +++ b/server/src/core/server/models/user/user.ts @@ -830,14 +830,14 @@ export async function findOrCreateUser( // True to return the original document instead of the updated document. // This will ensure that when an upsert operation adds a new User, it // should return null. - returnOriginal: true, + returnDocument: "before", upsert: true, } ); return { - user: result.value || user, - wasUpserted: !result.value, + user: result || user, + wasUpserted: !result, }; } catch (err) { // Evaluate the error, if it is in regards to violating the unique index, @@ -925,7 +925,7 @@ export async function retrieveUserWithProfile( mongo: MongoContext, tenantID: string, profile: Partial> -) { +): Promise | null> { return mongo.users().findOne({ tenantID, profiles: { @@ -993,14 +993,14 @@ export async function updateUserRole( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(id); } - return result.value; + return result; } export async function mergeUserSiteModerationScopes( @@ -1019,14 +1019,14 @@ export async function mergeUserSiteModerationScopes( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(id); } - return result.value; + return result; } export async function pullUserSiteModerationScopes( @@ -1045,15 +1045,15 @@ export async function pullUserSiteModerationScopes( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(id); } - return result.value; + return result; } export async function mergeUserMembershipScopes( @@ -1073,15 +1073,15 @@ export async function mergeUserMembershipScopes( }, }, { - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(userID); } - return result.value; + return result; } export async function pullUserMembershipScopes( @@ -1101,15 +1101,15 @@ export async function pullUserMembershipScopes( }, }, { - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(userID); } - return result.value; + return result; } export async function updateUserModerationScopes( @@ -1124,14 +1124,14 @@ export async function updateUserModerationScopes( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(id); } - return result.value; + return result; } export async function updateUserMembershipScopes( @@ -1144,15 +1144,15 @@ export async function updateUserMembershipScopes( .users() .findOneAndUpdate( { id: userID, tenantID }, - { $set: { membershipScopes: { siteIDs } } }, - { returnOriginal: false } + { $set: { "membershipScopes.siteIDs": siteIDs } }, + { returnDocument: "after" } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(userID); } - return result.value; + return result; } export async function verifyUserPassword( @@ -1203,10 +1203,10 @@ export async function updateUserPassword( arrayFilters: [{ "profiles.type": "local" }], // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, id); if (!user) { throw new UserNotFoundError(id); @@ -1224,7 +1224,7 @@ export async function updateUserPassword( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function scheduleDeletionDate( @@ -1256,14 +1256,14 @@ export async function scheduleDeletionDate( }, }, { - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(userID); } - return result.value; + return result; } export async function clearDeletionDate( @@ -1296,14 +1296,14 @@ export async function clearDeletionDate( // We want to return edited user so that // we send back the cleared scheduledDeletionDate // to the client - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(userID); } - return result.value; + return result; } export interface UpdateUserInput { @@ -1340,10 +1340,10 @@ export async function updateUserFromSSO( arrayFilters: [{ "profiles.type": "sso" }], // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUserWithProfile(mongo, tenantID, { type: "sso", id, @@ -1355,7 +1355,7 @@ export async function updateUserFromSSO( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -1379,7 +1379,7 @@ export async function setUserUsername( { tenantID, id, - username: null, + username: undefined, }, { $set: { @@ -1389,10 +1389,10 @@ export async function setUserUsername( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Try to get the current user to discover what happened. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -1406,7 +1406,7 @@ export async function setUserUsername( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -1446,11 +1446,11 @@ export async function updateUserUsername( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, id); if (!user) { throw new UserNotFoundError(id); @@ -1459,7 +1459,7 @@ export async function updateUserUsername( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -1493,7 +1493,7 @@ export async function setUserEmail( { tenantID, id, - email: null, + email: undefined, }, { $set: { @@ -1506,10 +1506,10 @@ export async function setUserEmail( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Try to get the current user to discover what happened. user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -1523,7 +1523,7 @@ export async function setUserEmail( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -1560,10 +1560,10 @@ export async function updateUserEmail( }, { arrayFilters: [{ "profiles.type": "local" }], - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Try to get the current user to discover what happened. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -1572,7 +1572,7 @@ export async function updateUserEmail( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } catch (err) { if (err instanceof MongoError && err.code === 11000) { throw new DuplicateEmailError(email); @@ -1611,10 +1611,10 @@ export async function updateUserBio( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Try to get the current user to discover what happened. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -1624,7 +1624,7 @@ export async function updateUserBio( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -1657,10 +1657,10 @@ export async function updateUserAvatar( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Try to get the current user to discover what happened. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -1670,7 +1670,7 @@ export async function updateUserAvatar( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -1730,10 +1730,10 @@ export async function setUserLocalProfile( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Try to get the current user to discover what happened. user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -1749,7 +1749,7 @@ export async function setUserLocalProfile( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function createUserToken( @@ -1777,15 +1777,15 @@ export async function createUserToken( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(userID); } return { - user: result.value, + user: result, token, }; } @@ -1813,11 +1813,11 @@ export async function updateUserSSOProfileID( arrayFilters: [{ "profiles.type": "sso" }], // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, userID); if (!user) { throw new UserNotFoundError(userID); @@ -1831,7 +1831,7 @@ export async function updateUserSSOProfileID( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function deactivateUserToken( @@ -1853,10 +1853,10 @@ export async function deactivateUserToken( { // True to return the original document instead of the updated // document. - returnOriginal: true, + returnDocument: "before", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, userID); if (!user) { throw new UserNotFoundError(id); @@ -1872,12 +1872,12 @@ export async function deactivateUserToken( // We have to typecast here because we know at this point that the record does // contain the Token. - const token: Token = result.value.tokens.find((t) => t.id === id) as Token; + const token: Token = result.tokens.find((t) => t.id === id) as Token; // Mutate the user in order to remove the Token from the list of Token's. const updatedUser: Readonly = { - ...result.value, - tokens: result.value.tokens.filter((t) => t.id !== id), + ...result, + tokens: result.tokens.filter((t) => t.id !== id), }; return { @@ -1973,10 +1973,10 @@ export async function premodUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ban operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -1992,7 +1992,7 @@ export async function premodUser( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -2035,11 +2035,11 @@ export async function removeUserPremod( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ban operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2050,7 +2050,7 @@ export async function removeUserPremod( return user; } - return result.value; + return result; } export async function siteBanUser( @@ -2091,11 +2091,11 @@ export async function siteBanUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ban operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2105,7 +2105,7 @@ export async function siteBanUser( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -2153,10 +2153,10 @@ export async function banUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ban operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2166,7 +2166,7 @@ export async function banUser( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function removeUserSiteBan( @@ -2203,11 +2203,11 @@ export async function removeUserSiteBan( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ban operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2218,7 +2218,7 @@ export async function removeUserSiteBan( return user; } - return result.value; + return result; } /** @@ -2277,10 +2277,10 @@ export async function removeUserBan( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ban operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2291,7 +2291,7 @@ export async function removeUserBan( return user; } - return result.value; + return result; } /** @@ -2352,10 +2352,10 @@ export async function suspendUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the suspend operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2374,7 +2374,7 @@ export async function suspendUser( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -2420,10 +2420,10 @@ export async function removeActiveUserSuspensions( ], // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the suspend operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2436,7 +2436,7 @@ export async function removeActiveUserSuspensions( logger.debug({ result }, "finished update operation"); - return result.value; + return result; } export async function warnUser( @@ -2474,10 +2474,10 @@ export async function warnUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ban operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2493,7 +2493,7 @@ export async function warnUser( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -2548,10 +2548,10 @@ export async function removeUserWarning( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the warn operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2562,7 +2562,7 @@ export async function removeUserWarning( return user; } - return result.value; + return result; } /** @@ -2607,10 +2607,10 @@ export async function acknowledgeOwnWarning( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the warn operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2621,7 +2621,7 @@ export async function acknowledgeOwnWarning( return user; } - return result.value; + return result; } export async function sendModMessageUser( @@ -2657,11 +2657,11 @@ export async function sendModMessageUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the message operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2671,7 +2671,7 @@ export async function sendModMessageUser( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -2715,10 +2715,10 @@ export async function acknowledgeOwnModMessage( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the acknowledge mod message operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -2729,7 +2729,7 @@ export async function acknowledgeOwnModMessage( return user; } - return result.value; + return result; } export type ConsolidatedBanStatus = Omit & @@ -2926,10 +2926,10 @@ export async function createOrRetrieveUserPasswordResetID( arrayFilters: [{ "profiles.type": "local" }], // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, id); if (!user) { throw new UserNotFoundError(id); @@ -2965,8 +2965,8 @@ export async function createOrRetrieveUserEmailVerificationID( id, // This ensures that we don't set a emailVerificationID when there is one // already. - emailVerificationID: null, - $or: [{ emailVerified: false }, { emailVerified: null }], + emailVerificationID: undefined, + $or: [{ emailVerified: false }, { emailVerified: undefined }], }, { $set: { @@ -2976,10 +2976,10 @@ export async function createOrRetrieveUserEmailVerificationID( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, id); if (!user) { throw new UserNotFoundError(id); @@ -3039,10 +3039,10 @@ export async function resetUserPassword( arrayFilters: [{ "profiles.type": "local", "profiles.resetID": resetID }], // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, id); if (!user) { throw new UserNotFoundError(id); @@ -3064,7 +3064,7 @@ export async function resetUserPassword( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function confirmUserEmail( @@ -3093,10 +3093,10 @@ export async function confirmUserEmail( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { const user = await retrieveUser(mongo, tenantID, id); if (!user) { throw new UserNotFoundError(id); @@ -3113,7 +3113,7 @@ export async function confirmUserEmail( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function ignoreUser( @@ -3132,11 +3132,9 @@ export async function ignoreUser( { id, tenantID, - ignoredUsers: { + "ignoredUsers.id": { $not: { - $eq: { - id: ignoreUserID, - }, + $eq: ignoreUserID, }, }, }, @@ -3146,10 +3144,10 @@ export async function ignoreUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ignore operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -3168,7 +3166,7 @@ export async function ignoreUser( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function removeUserIgnore( @@ -3189,10 +3187,10 @@ export async function removeUserIgnore( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ignore operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -3211,7 +3209,7 @@ export async function removeUserIgnore( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function setUserLastDownloadedAt( @@ -3231,10 +3229,10 @@ export async function setUserLastDownloadedAt( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the ignore operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -3244,7 +3242,7 @@ export async function setUserLastDownloadedAt( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export type EmailNotificationSettingsInput = @@ -3267,10 +3265,10 @@ export async function updateUserEmailNotificationSettings( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the update operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -3280,7 +3278,7 @@ export async function updateUserEmailNotificationSettings( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export type InPageNotificationSettingsInput = @@ -3303,10 +3301,10 @@ export async function updateUserInPageNotificationSettings( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the update operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -3316,7 +3314,7 @@ export async function updateUserInPageNotificationSettings( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export type UpdateUserMediaSettingsInput = Partial; @@ -3338,10 +3336,10 @@ export async function updateUserMediaSettings( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the update operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -3351,7 +3349,7 @@ export async function updateUserMediaSettings( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -3392,10 +3390,10 @@ export async function insertUserNotificationDigests( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { // Get the user so we can figure out why the update operation failed. const user = await retrieveUser(mongo, tenantID, id); if (!user) { @@ -3405,7 +3403,7 @@ export async function insertUserNotificationDigests( throw new Error("an unexpected error occurred"); } - return result.value; + return result; } /** @@ -3430,11 +3428,11 @@ export async function pullUserNotificationDigests( { $set: { digests: [], hasDigests: false } }, { // True to return the original document instead of the updated document. - returnOriginal: true, + returnDocument: "before", } ); - return result.value || null; + return result; } /** @@ -3470,11 +3468,11 @@ export async function retrieveLockedUserScheduledForDeletion( { // We want to get back the user with // modified scheduledDeletionDate - returnOriginal: false, + returnDocument: "after", } ); - return result.value || null; + return result; } /** @@ -3510,14 +3508,14 @@ export async function createModeratorNote( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(id); } - return result.value; + return result; } /** @@ -3546,13 +3544,13 @@ export async function deleteModeratorNote( }, }, { - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(id); } - return result.value; + return result; } export async function linkUsers( @@ -3566,13 +3564,13 @@ export async function linkUsers( id: sourceUserID, tenantID, }); - if (!source.value) { + if (!source) { throw new UserNotFoundError(sourceUserID); } // If the source user doesn't have any profiles, we have nothing to do. We // should abort. - if (!source.value.profiles) { + if (!source.profiles) { throw new Error( "cannot link a user with no profiles, failed source authentication precondition" ); @@ -3587,16 +3585,16 @@ export async function linkUsers( { $push: { profiles: { - $each: source.value.profiles, + $each: source.profiles, }, }, } ); - if (!dest.value) { + if (!dest) { throw new UserNotFoundError(destinationUserID); } - return dest.value; + return dest; } export const updateUserCommentCounts = ( @@ -3623,11 +3621,11 @@ export const updateLastFeaturedDate = async ( }, }, { - returnOriginal: false, + returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new UserNotFoundError(userID); } - return result.value; + return result; }; diff --git a/server/src/core/server/services/users/delete.ts b/server/src/core/server/services/users/delete.ts index 822317ffa7..c013aee7c4 100644 --- a/server/src/core/server/services/users/delete.ts +++ b/server/src/core/server/services/users/delete.ts @@ -428,7 +428,7 @@ export async function deleteUser( { // False to return the updated document instead of the original // document. - returnOriginal: false, + returnDocument: "after", } ); diff --git a/server/src/core/server/stacks/reviewCommentAction.ts b/server/src/core/server/stacks/reviewCommentAction.ts index 76d11d55c1..dc44600bd8 100644 --- a/server/src/core/server/stacks/reviewCommentAction.ts +++ b/server/src/core/server/stacks/reviewCommentAction.ts @@ -22,7 +22,7 @@ const reviewCommentAction = async ( }, }, { - returnOriginal: false, + returnDocument: "after", } ); From b526cc61d8e3ff9a86a003442daa406b9cf81944 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Tue, 1 Oct 2024 14:03:22 -0600 Subject: [PATCH 03/22] WIP: more type updates across various server files --- server/src/core/server/app/middleware/csp.ts | 5 +++ .../src/core/server/app/middleware/tenant.ts | 6 ++- .../server/data/cache/commentCache.spec.ts | 4 +- .../core/server/data/cache/commentCache.ts | 10 +++-- server/src/core/server/data/context.ts | 4 +- server/src/core/server/errors/index.ts | 9 ++++ server/src/core/server/errors/translations.ts | 1 + .../server/events/listeners/perspective.ts | 2 +- .../core/server/events/listeners/webhook.ts | 4 +- .../src/core/server/models/action/comment.ts | 2 +- .../src/core/server/models/comment/comment.ts | 45 +++++++++---------- .../core/server/models/helpers/connection.ts | 6 ++- .../src/core/server/models/helpers/query.ts | 5 +-- server/src/core/server/models/site/index.ts | 2 +- server/src/core/server/models/story/story.ts | 2 +- .../src/core/server/models/tenant/tenant.ts | 34 +++++++------- .../migrations/1579189174931_create_sites.ts | 18 ++++---- .../src/core/server/services/mongodb/index.ts | 28 ++++++++---- .../src/core/server/services/users/delete.ts | 8 ++-- .../services/users/download/download.ts | 2 +- .../src/core/server/stacks/createComment.ts | 6 +-- server/src/core/server/stacks/editComment.ts | 4 +- .../server/stacks/helpers/retrieveParent.ts | 2 +- .../core/server/stacks/reviewCommentAction.ts | 2 +- 24 files changed, 122 insertions(+), 89 deletions(-) diff --git a/server/src/core/server/app/middleware/csp.ts b/server/src/core/server/app/middleware/csp.ts index 5d58591da4..169a08630b 100644 --- a/server/src/core/server/app/middleware/csp.ts +++ b/server/src/core/server/app/middleware/csp.ts @@ -6,6 +6,7 @@ import { AppOptions } from "coral-server/app"; import { getOrigin, prefixSchemeIfRequired } from "coral-server/app/url"; import { Config } from "coral-server/config"; import { MongoContext } from "coral-server/data/context"; +import { SiteNotFoundError } from "coral-server/errors"; import { retrieveSite, retrieveSiteByOrigin, @@ -50,6 +51,10 @@ async function retrieveSiteFromQuery( return null; } + if (!story.siteID) { + throw new SiteNotFoundError(null, storyID); + } + // If the site can't be found based on it's allowed origins and the story // URL (which is a allowed list), then we know it isn't allowed. return retrieveSite(mongo, tenant.id, story.siteID); diff --git a/server/src/core/server/app/middleware/tenant.ts b/server/src/core/server/app/middleware/tenant.ts index 45b880ee34..f960ba5615 100644 --- a/server/src/core/server/app/middleware/tenant.ts +++ b/server/src/core/server/app/middleware/tenant.ts @@ -1,7 +1,7 @@ import { v1 as uuid } from "uuid"; import { MongoContext } from "coral-server/data/context"; -import { TenantNotFoundError } from "coral-server/errors"; +import { SiteNotFoundError, TenantNotFoundError } from "coral-server/errors"; import logger from "coral-server/logger"; import { retrieveSite, @@ -110,6 +110,10 @@ async function retrieveSiteFromQuery( return null; } + if (!story.siteID) { + throw new SiteNotFoundError(null, storyID); + } + // If the site can't be found based on it's allowed origins and the story // URL (which is a allowed list), then we know it isn't allowed. return retrieveSite(mongo, tenant.id, story.siteID); diff --git a/server/src/core/server/data/cache/commentCache.spec.ts b/server/src/core/server/data/cache/commentCache.spec.ts index 720e18bbcf..b2832ac65a 100644 --- a/server/src/core/server/data/cache/commentCache.spec.ts +++ b/server/src/core/server/data/cache/commentCache.spec.ts @@ -24,8 +24,8 @@ const createRedis = (): AugmentedRedis => { const createMongo = async (): Promise => { const uri = "mongodb://127.0.0.1:27017/coral"; - const live = await createMongoDB(uri); - const archive = await createMongoDB(uri); + const live = (await createMongoDB(uri)).db; + const archive = (await createMongoDB(uri)).db; const context = new MongoContextImpl(live, archive); diff --git a/server/src/core/server/data/cache/commentCache.ts b/server/src/core/server/data/cache/commentCache.ts index 2fb9a733de..2daa6eafc8 100644 --- a/server/src/core/server/data/cache/commentCache.ts +++ b/server/src/core/server/data/cache/commentCache.ts @@ -127,7 +127,11 @@ export class CommentCache implements IDataCache { : this.mongo.comments(); const comments = await collection - .find({ tenantID, storyID, status: { $in: ["APPROVED", "NONE"] } }) + .find({ + tenantID, + storyID, + status: { $in: [GQLCOMMENT_STATUS.APPROVED, GQLCOMMENT_STATUS.NONE] }, + }) .toArray(); if (!comments || comments.length === 0) { return []; @@ -357,13 +361,13 @@ export class CommentCache implements IDataCache { tenantID, storyID, parentID, - status: { $in: ["APPROVED", "NONE"] }, + status: { $in: [GQLCOMMENT_STATUS.APPROVED, GQLCOMMENT_STATUS.NONE] }, } : { tenantID, storyID, parentID: null, - status: { $in: ["APPROVED", "NONE"] }, + status: { $in: [GQLCOMMENT_STATUS.APPROVED, GQLCOMMENT_STATUS.NONE] }, }; const collection = isArchived diff --git a/server/src/core/server/data/context.ts b/server/src/core/server/data/context.ts index 6811b77065..d51c94ffba 100644 --- a/server/src/core/server/data/context.ts +++ b/server/src/core/server/data/context.ts @@ -142,7 +142,7 @@ export async function createMongoContext( ): Promise { // Setup MongoDB. const liveURI = config.get("mongodb"); - const live = await createMongoDB(liveURI); + const live = (await createMongoDB(liveURI)).db; // If we have an archive URI, use it, otherwise, default // to using the live database @@ -154,7 +154,7 @@ export async function createMongoContext( ) { archive = live; } else { - archive = await createMongoDB(archiveURI); + archive = (await createMongoDB(archiveURI)).db; } return new MongoContextImpl(live, archive); diff --git a/server/src/core/server/errors/index.ts b/server/src/core/server/errors/index.ts index 4ba018309b..f012396b25 100644 --- a/server/src/core/server/errors/index.ts +++ b/server/src/core/server/errors/index.ts @@ -564,6 +564,15 @@ export class StoryNotFoundError extends CoralError { } } +export class SiteNotFoundError extends CoralError { + constructor(siteID?: string | null, storyID?: string | null) { + super({ + code: ERROR_CODES.SITE_NOT_FOUND, + context: { pub: { siteID, storyID } }, + }); + } +} + export class CommentNotFoundError extends CoralError { constructor(commentID: string) { super({ diff --git a/server/src/core/server/errors/translations.ts b/server/src/core/server/errors/translations.ts index 7b31959a20..a026abf16d 100644 --- a/server/src/core/server/errors/translations.ts +++ b/server/src/core/server/errors/translations.ts @@ -86,4 +86,5 @@ export const ERROR_TRANSLATIONS: Record = { DSA_REPORT_ADDITIONAL_INFO_TOO_LONG: "error-dsaReportAdditionalInfoTooLong", UNABLE_TO_PRIME_CACHED_COMMENTS_FOR_STORY: "error-unableToPrimeCachedCommentsForStory", + SITE_NOT_FOUND: "error-siteNotFound", }; diff --git a/server/src/core/server/events/listeners/perspective.ts b/server/src/core/server/events/listeners/perspective.ts index 1800d1ea45..757bbf40ee 100644 --- a/server/src/core/server/events/listeners/perspective.ts +++ b/server/src/core/server/events/listeners/perspective.ts @@ -97,7 +97,7 @@ export class PerspectiveCoralEventListener body: { text: getHTMLPlainText(revision.body), commentID: comment.id, - commentParentID: comment.parentID, + commentParentID: comment.parentID ?? undefined, commentStatus: status, storyURL: story.url, model, diff --git a/server/src/core/server/events/listeners/webhook.ts b/server/src/core/server/events/listeners/webhook.ts index c42a3373d7..8e18eb4a3b 100644 --- a/server/src/core/server/events/listeners/webhook.ts +++ b/server/src/core/server/events/listeners/webhook.ts @@ -40,7 +40,7 @@ export class WebhookCoralEventListener ); // Based on the incoming event, determine which endpoints we should send. - const endpoints = tenant.webhooks.endpoints.filter((endpoint) => { + const endpoints = tenant.webhooks?.endpoints.filter((endpoint) => { // If the endpoint is disabled, don't include it. if (!endpoint.enabled) { return false; @@ -66,7 +66,7 @@ export class WebhookCoralEventListener }); // Log some important details. - if (endpoints.length === 0) { + if (!endpoints || endpoints.length === 0) { log.debug("no endpoints matched for event"); return; } diff --git a/server/src/core/server/models/action/comment.ts b/server/src/core/server/models/action/comment.ts index 641a90eaa3..fe4ba87c7b 100644 --- a/server/src/core/server/models/action/comment.ts +++ b/server/src/core/server/models/action/comment.ts @@ -130,7 +130,7 @@ export interface CommentAction extends TenantResource { /** * siteID represents the ID of the Site where the comment was left on. */ - siteID: string; + siteID: string | null; /** * userID is the ID of the User that left this Action. In the event that the diff --git a/server/src/core/server/models/comment/comment.ts b/server/src/core/server/models/comment/comment.ts index 65d0468b02..70496b3cd1 100644 --- a/server/src/core/server/models/comment/comment.ts +++ b/server/src/core/server/models/comment/comment.ts @@ -69,7 +69,7 @@ export interface Comment extends TenantResource { /** * parentID is the ID of the parent Comment if this Comment is a reply. */ - parentID?: string; + parentID?: string | null; /** * parentRevisionID is the ID of the Revision on the Comment referenced by the @@ -90,7 +90,7 @@ export interface Comment extends TenantResource { /** * siteID stores the ID of the Site that this Comment was left on. */ - siteID: string; + siteID: string | null; /** * section is the section of the story that this comment was left on. If the @@ -257,7 +257,7 @@ export async function pushChildCommentIDOntoParent( } ); - return result.value; + return result; } export type EditCommentInput = Pick & { @@ -382,7 +382,7 @@ export async function editComment( returnDocument: "before", } ); - if (!result.value) { + if (!result) { // Try to get the comment. const comment = await retrieveComment(mongo.comments(), tenantID, id); if (!comment) { @@ -400,20 +400,17 @@ export async function editComment( // Create a new "after" where the same changes were applied to it as // we did to the MongoDB document. const after: Comment = { - ...result.value, + ...result, // $set status status, // $inc actionCounts - actionCounts: mergeCommentActionCounts( - result.value.actionCounts, - actionCounts - ), + actionCounts: mergeCommentActionCounts(result.actionCounts, actionCounts), // $push revisions - revisions: [...result.value.revisions, revision], + revisions: [...result.revisions, revision], }; return { - before: result.value, + before: result, after, revision, }; @@ -857,14 +854,14 @@ export async function updateCommentEmbeddedAt( returnDocument: "before", } ); - if (!result.value) { + if (!result) { return null; } return { - before: result.value, + before: result, after: { - ...result.value, + ...result, embeddedAt, }, }; @@ -895,14 +892,14 @@ export async function updateCommentStatus( returnDocument: "before", } ); - if (!result.value) { + if (!result) { return null; } return { - before: result.value, + before: result, after: { - ...result.value, + ...result, status, }, }; @@ -945,11 +942,11 @@ export async function updateCommentActionCounts( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new CommentRevisionNotFoundError(id, revisionID); } - return result.value; + return result; } /** @@ -1066,7 +1063,7 @@ export async function removeCommentTag( returnDocument: "after", } ); - if (!result.value) { + if (!result) { const comment = await retrieveComment( mongo.comments(), tenantID, @@ -1079,7 +1076,7 @@ export async function removeCommentTag( throw new Error("could not add a tag for an unexpected reason"); } - return result.value; + return result; } function isCountEmpty(counts: GQLCommentTagCounts): boolean { @@ -1233,12 +1230,12 @@ export async function initializeCommentTagCountsForStory( } ); - if (!result.ok || !result.value) { + if (!result) { throw new Error("unable to initialize the comment tag counts"); } return { - story: result.value, + story: result, tagCounts: tagCounts[0], }; } @@ -1693,7 +1690,7 @@ export async function retrieveFeaturedComments( ]) .toArray(); - return results; + return results as Comment[]; } export async function retrieveLatestFeaturedCommentForAuthor( diff --git a/server/src/core/server/models/helpers/connection.ts b/server/src/core/server/models/helpers/connection.ts index 4c0811e1c5..f6cb341f20 100644 --- a/server/src/core/server/models/helpers/connection.ts +++ b/server/src/core/server/models/helpers/connection.ts @@ -1,5 +1,6 @@ import { merge } from "lodash"; +import { Document } from "mongodb"; import Query, { FilterQuery } from "./query"; export type Cursor = Date | number | string | null; @@ -132,7 +133,7 @@ export function doesNotContainNull(items: Array): items is T[] { * @param input the pagination arguments * @param transformer the node transformer which converts a node to a custor */ -export async function resolveConnection( +export async function resolveConnection( query: Query, input: PaginationArgs, transformer: NodeToCursorTransformer @@ -147,7 +148,8 @@ export async function resolveConnection( // Convert the nodes to edges (which will include the extra edge we don't need // if there is more results). - const edges = nodesToEdges(nodes, transformer); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const edges = nodesToEdges(nodes, transformer as any); // Get the pageInfo for the connection. We will use this to also determine if // we need to trim off the extra edge that we requested by comparing its diff --git a/server/src/core/server/models/helpers/query.ts b/server/src/core/server/models/helpers/query.ts index 4ad35bfcab..7c5824c5be 100644 --- a/server/src/core/server/models/helpers/query.ts +++ b/server/src/core/server/models/helpers/query.ts @@ -5,7 +5,6 @@ import { Filter, FindCursor, SortDirection, - WithId, } from "mongodb"; import logger from "coral-server/logger"; @@ -80,7 +79,7 @@ export default class Query { /** * exec will return a cursor to the query. */ - public async exec(): Promise>> { + public async exec(): Promise> { logger.trace( { collection: this.collection.collectionName, @@ -113,6 +112,6 @@ export default class Query { cursor = cursor.skip(this.skip); } - return cursor; + return cursor as FindCursor; } } diff --git a/server/src/core/server/models/site/index.ts b/server/src/core/server/models/site/index.ts index 226acaa6bd..0a8e0417e3 100644 --- a/server/src/core/server/models/site/index.ts +++ b/server/src/core/server/models/site/index.ts @@ -169,7 +169,7 @@ export async function updateSite( // document. { returnDocument: "after" } ); - return result.value || null; + return result; } catch (err) { // Evaluate the error, if it is in regards to violating the unique index, // then return a duplicate Story error. diff --git a/server/src/core/server/models/story/story.ts b/server/src/core/server/models/story/story.ts index 291eb76af5..13b3b583bd 100644 --- a/server/src/core/server/models/story/story.ts +++ b/server/src/core/server/models/story/story.ts @@ -106,7 +106,7 @@ export interface Story extends TenantResource { /** * siteID references the site the story belongs to */ - siteID: string; + siteID: string | null; isArchiving?: boolean; isArchived?: boolean; diff --git a/server/src/core/server/models/tenant/tenant.ts b/server/src/core/server/models/tenant/tenant.ts index 7bd36bbad3..2d0d2c5a93 100644 --- a/server/src/core/server/models/tenant/tenant.ts +++ b/server/src/core/server/models/tenant/tenant.ts @@ -19,6 +19,7 @@ import { BadgeConfiguration, defaultRTEConfiguration, generateSigningSecret, + NewUserModeration, Settings, SigningSecretResource, } from "coral-server/models/settings"; @@ -122,7 +123,7 @@ export interface TenantSettings * endpoints is all the configured endpoints that should receive events. */ endpoints: Endpoint[]; - }; + } | null; } /** @@ -428,11 +429,11 @@ export async function updateTenant( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new Error("tenant not found with id"); } - return result.value; + return result; } export async function enableTenantFeatureFlag( @@ -455,11 +456,11 @@ export async function enableTenantFeatureFlag( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new Error("tenant not found with id"); } - return result.value; + return result; } export async function disableTenantFeatureFlag( @@ -482,11 +483,11 @@ export async function disableTenantFeatureFlag( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new Error("tenant not found with id"); } - return result.value; + return result; } export interface CreateAnnouncementInput { @@ -500,10 +501,11 @@ export async function createTenantAnnouncement( input: CreateAnnouncementInput, now = new Date() ) { - const announcement = { + const announcement: GQLAnnouncement = { id: uuid(), ...input, createdAt: now, + disableAt: new Date(now.getTime() + input.duration), }; const result = await mongo.tenants().findOneAndUpdate( @@ -517,7 +519,7 @@ export async function createTenantAnnouncement( returnDocument: "after", } ); - return result.value; + return result; } export interface CreateFlairBadgeInput { @@ -548,7 +550,7 @@ export async function createTenantFlairBadge( returnDocument: "after", } ); - return result.value; + return result; } export interface DeleteFlairBadgeInput { @@ -571,12 +573,12 @@ export async function deleteTenantFlairBadge( returnDocument: "after", } ); - return result.value; + return result; } export interface CreateEmailDomainInput { domain: string; - newUserModeration: "BAN" | "PREMOD"; + newUserModeration: NewUserModeration; } export async function createTenantEmailDomain( @@ -610,7 +612,7 @@ export async function createTenantEmailDomain( returnDocument: "after", } ); - return result.value; + return result; } export interface UpdateEmailDomainInput { @@ -653,7 +655,7 @@ export async function updateTenantEmailDomain( returnDocument: "after", } ); - return result.value; + return result; } export interface DeleteEmailDomainInput { @@ -676,7 +678,7 @@ export async function deleteTenantEmailDomain( returnDocument: "after", } ); - return result.value; + return result; } export async function deleteTenantAnnouncement( @@ -694,7 +696,7 @@ export async function deleteTenantAnnouncement( returnDocument: "after", } ); - return result.value; + return result; } export function retrieveAnnouncementIfEnabled( diff --git a/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts b/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts index 75801e0134..f9ceeb913b 100644 --- a/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts +++ b/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts @@ -71,7 +71,7 @@ export default class extends Migration { this.log(tenant.id).info("starting stories migration"); // Add the siteID to all the stories. - let result = await mongo + const storyResult = await mongo .stories() .updateMany( { tenantID: tenant.id, siteID: null }, @@ -80,8 +80,8 @@ export default class extends Migration { this.log(tenant.id).info( { - matchedCount: result.matchedCount, - modifiedCount: result.modifiedCount, + matchedCount: storyResult.matchedCount, + modifiedCount: storyResult.modifiedCount, }, "finished stories migration" ); @@ -89,7 +89,7 @@ export default class extends Migration { this.log(tenant.id).info("starting comments migration"); // Add the siteID to all comments. - result = await mongo + const commentResult = await mongo .comments() .updateMany( { tenantID: tenant.id, siteID: null }, @@ -98,8 +98,8 @@ export default class extends Migration { this.log(tenant.id).info( { - matchedCount: result.matchedCount, - modifiedCount: result.modifiedCount, + matchedCount: commentResult.matchedCount, + modifiedCount: commentResult.modifiedCount, }, "finished comments migration" ); @@ -107,7 +107,7 @@ export default class extends Migration { this.log(tenant.id).info("starting commentActions migration"); // Add the siteID to all commentActions. - result = await mongo + const commentActionResult = await mongo .commentActions() .updateMany( { tenantID: tenant.id, siteID: null }, @@ -116,8 +116,8 @@ export default class extends Migration { this.log(tenant.id).info( { - matchedCount: result.matchedCount, - modifiedCount: result.modifiedCount, + matchedCount: commentActionResult.matchedCount, + modifiedCount: commentActionResult.modifiedCount, }, "finished commentActions migration" ); diff --git a/server/src/core/server/services/mongodb/index.ts b/server/src/core/server/services/mongodb/index.ts index faadd1bd97..95628e69be 100644 --- a/server/src/core/server/services/mongodb/index.ts +++ b/server/src/core/server/services/mongodb/index.ts @@ -6,7 +6,10 @@ import logger from "coral-server/logger"; async function createMongoClient(mongoURI: string): Promise { try { return await MongoClient.connect(mongoURI, { - useNewUrlParser: true, + // believe we don't need this since the new driver only uses + // the new URL parser. But am leaving this here in case we have + // issues with URL's and want to investigate into it. + // useNewUrlParser: true, ignoreUndefined: true, }); } catch (err) { @@ -17,26 +20,33 @@ async function createMongoClient(mongoURI: string): Promise { } } -function attachHandlers(db: Db) { - db.on("error", (err: Error) => { +function attachHandlers(client: MongoClient) { + client.on("error", (err: Error) => { logger.error({ err }, "mongodb has encountered an error"); }); - db.on("close", () => { + client.on("close", () => { logger.warn("mongodb has closed"); }); - db.on("reconnect", () => { + client.on("reconnect", () => { logger.warn("mongodb has reconnected"); }); - db.on("timeout", () => { + client.on("timeout", () => { logger.warn("mongodb has timed out"); }); } +interface CreateMongoDbResult { + client: MongoClient; + db: Db; +} + /** * create will connect to the MongoDB instance identified in the configuration. * @param config application configuration. */ -export async function createMongoDB(mongoURI: string): Promise { +export async function createMongoDB( + mongoURI: string +): Promise { // Connect and create a client for MongoDB. const client = await createMongoClient(mongoURI); @@ -47,7 +57,7 @@ export async function createMongoDB(mongoURI: string): Promise { const db = client.db(); // Attach the handlers. - attachHandlers(db); + attachHandlers(client); - return db; + return { client, db }; } diff --git a/server/src/core/server/services/users/delete.ts b/server/src/core/server/services/users/delete.ts index c013aee7c4..673fd4c228 100644 --- a/server/src/core/server/services/users/delete.ts +++ b/server/src/core/server/services/users/delete.ts @@ -1,4 +1,4 @@ -import { Collection, FilterQuery } from "mongodb"; +import { Collection, Document, Filter } from "mongodb"; import { v4 as uuid } from "uuid"; import { Config } from "coral-server/config"; @@ -23,7 +23,7 @@ import { AugmentedRedis } from "../redis"; const BATCH_SIZE = 500; -async function executeBulkOperations( +async function executeBulkOperations( collection: Collection, operations: any[] ) { @@ -132,7 +132,7 @@ async function moderateComments( config: Config, i18n: I18n, tenant: Tenant, - filter: FilterQuery, + filter: Filter, targetStatus: GQLCOMMENT_STATUS, now: Date, isArchived = false, @@ -432,5 +432,5 @@ export async function deleteUser( } ); - return result.value || null; + return result; } diff --git a/server/src/core/server/services/users/download/download.ts b/server/src/core/server/services/users/download/download.ts index 87dc2bdbbd..d987648b4e 100644 --- a/server/src/core/server/services/users/download/download.ts +++ b/server/src/core/server/services/users/download/download.ts @@ -16,7 +16,7 @@ import { } from "coral-server/models/story"; import { Tenant } from "coral-server/models/tenant"; import { User } from "coral-server/models/user"; -import { Cursor } from "mongodb"; +import { FindCursor as Cursor } from "mongodb"; const BATCH_SIZE = 100; diff --git a/server/src/core/server/stacks/createComment.ts b/server/src/core/server/stacks/createComment.ts index b85728a879..c720d236cf 100644 --- a/server/src/core/server/stacks/createComment.ts +++ b/server/src/core/server/stacks/createComment.ts @@ -166,7 +166,7 @@ const markCommentAsAnswered = async ( await updateTagCommentCounts( tenant.id, comment.storyID, - comment.siteID, + comment.siteID!, mongo, redis, // Since we removed the UNANSWERED tag, we need to recreate the @@ -247,9 +247,9 @@ export default async function create( // Check if the user is banned on this site, if they are, throw an error right // now. // NOTE: this should be removed with attribute based auth checks. - if (isSiteBanned(author, story.siteID)) { + if (isSiteBanned(author, story.siteID!)) { // Get the site in question. - const site = await retrieveSite(mongo, tenant.id, story.siteID); + const site = await retrieveSite(mongo, tenant.id, story.siteID!); if (!site) { throw new Error(`referenced site not found: ${story.siteID}`); } diff --git a/server/src/core/server/stacks/editComment.ts b/server/src/core/server/stacks/editComment.ts index 6063875375..25a17421ff 100644 --- a/server/src/core/server/stacks/editComment.ts +++ b/server/src/core/server/stacks/editComment.ts @@ -116,9 +116,9 @@ export default async function edit( // Check if the user is banned on this site, if they are, throw an error right // now. // NOTE: this should be removed with attribute based auth checks. - if (isSiteBanned(author, siteID)) { + if (isSiteBanned(author, siteID!)) { // Get the site in question. - const site = await retrieveSite(mongo, tenant.id, siteID); + const site = await retrieveSite(mongo, tenant.id, siteID!); if (!site) { throw new Error(`referenced site not found: ${siteID}`); } diff --git a/server/src/core/server/stacks/helpers/retrieveParent.ts b/server/src/core/server/stacks/helpers/retrieveParent.ts index b55d641053..023eee904f 100644 --- a/server/src/core/server/stacks/helpers/retrieveParent.ts +++ b/server/src/core/server/stacks/helpers/retrieveParent.ts @@ -14,7 +14,7 @@ import { GQLCOMMENT_STATUS } from "coral-server/graph/schema/__generated__/types async function retrieveParent( mongo: MongoContext, tenantID: string, - input: { parentID?: string; parentRevisionID?: string } + input: { parentID?: string | null; parentRevisionID?: string } ) { if (!input.parentID || !input.parentRevisionID) { return null; diff --git a/server/src/core/server/stacks/reviewCommentAction.ts b/server/src/core/server/stacks/reviewCommentAction.ts index dc44600bd8..2d34cef3cd 100644 --- a/server/src/core/server/stacks/reviewCommentAction.ts +++ b/server/src/core/server/stacks/reviewCommentAction.ts @@ -26,7 +26,7 @@ const reviewCommentAction = async ( } ); - return result.value; + return result; }; export default reviewCommentAction; From a16db72984eaca43ca4af601ebddd969fa21e950 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Tue, 1 Oct 2024 16:27:13 -0600 Subject: [PATCH 04/22] WIP: more type fixes and updates --- .../core/server/data/cache/commentCache.ts | 2 +- server/src/core/server/errors/index.ts | 3 +- .../core/server/graph/loaders/DSAReports.ts | 24 ++++++- .../src/core/server/graph/loaders/helpers.ts | 2 +- .../src/core/server/graph/mutators/Actions.ts | 2 +- .../core/server/graph/mutators/Comments.ts | 4 +- .../core/server/graph/resolvers/Comment.ts | 6 +- .../src/core/server/models/comment/comment.ts | 6 +- server/src/core/server/models/story/story.ts | 67 +++++++++---------- .../src/core/server/models/tenant/tenant.ts | 12 +++- server/src/core/server/models/user/helpers.ts | 2 +- server/src/core/server/models/user/user.ts | 4 +- .../core/server/services/comments/comments.ts | 18 ++--- .../src/core/server/services/users/delete.ts | 4 +- 14 files changed, 90 insertions(+), 66 deletions(-) diff --git a/server/src/core/server/data/cache/commentCache.ts b/server/src/core/server/data/cache/commentCache.ts index 2daa6eafc8..45c26a949f 100644 --- a/server/src/core/server/data/cache/commentCache.ts +++ b/server/src/core/server/data/cache/commentCache.ts @@ -354,7 +354,7 @@ export class CommentCache implements IDataCache { tenantID: string, storyID: string, parentID?: string | null, - isArchived?: boolean + isArchived?: boolean | null ): Promise>> { const filter = parentID ? { diff --git a/server/src/core/server/errors/index.ts b/server/src/core/server/errors/index.ts index f012396b25..ee131958f1 100644 --- a/server/src/core/server/errors/index.ts +++ b/server/src/core/server/errors/index.ts @@ -1046,9 +1046,8 @@ export class UsernameAlreadyExists extends CoralError { } export class UnableToUpdateStoryURL extends CoralError { - constructor(cause: MongoError, id: string, oldUrl: string, url: string) { + constructor(id: string, oldUrl: string, url: string) { super({ - cause, reportable: true, code: ERROR_CODES.UNABLE_TO_UPDATE_STORY_URL, context: { pvt: { id, oldUrl, url } }, diff --git a/server/src/core/server/graph/loaders/DSAReports.ts b/server/src/core/server/graph/loaders/DSAReports.ts index fad47e0d4a..a6165c7ba3 100644 --- a/server/src/core/server/graph/loaders/DSAReports.ts +++ b/server/src/core/server/graph/loaders/DSAReports.ts @@ -14,6 +14,7 @@ import { createManyBatchLoadFn } from "./util"; import { DSAReportToRelatedReportsArgs, GQLDSAREPORT_STATUS_FILTER, + GQLDSAReportStatus, GQLREPORT_SORT, QueryToDsaReportsArgs, } from "coral-server/graph/schema/__generated__/types"; @@ -24,12 +25,33 @@ export interface FindDSAReportInput { id: string; } +const convertStatusEnum = ( + status: GQLDSAREPORT_STATUS_FILTER +): GQLDSAReportStatus => { + if (status === GQLDSAREPORT_STATUS_FILTER.AWAITING_REVIEW) { + return GQLDSAReportStatus.AWAITING_REVIEW; + } + if (status === GQLDSAREPORT_STATUS_FILTER.COMPLETED) { + return GQLDSAReportStatus.COMPLETED; + } + if (status === GQLDSAREPORT_STATUS_FILTER.UNDER_REVIEW) { + return GQLDSAReportStatus.UNDER_REVIEW; + } + if (status === GQLDSAREPORT_STATUS_FILTER.VOID) { + return GQLDSAReportStatus.VOID; + } + + return GQLDSAReportStatus.VOID; +}; + const statusFilter = ( status?: GQLDSAREPORT_STATUS_FILTER[] ): DSAReportConnectionFilterInput => { if (status) { + const inStatus = status.map((s) => convertStatusEnum(s)); + return { - status: { $in: status }, + status: { $in: inStatus }, }; } return {}; diff --git a/server/src/core/server/graph/loaders/helpers.ts b/server/src/core/server/graph/loaders/helpers.ts index 9ba8466d89..b83fc25095 100644 --- a/server/src/core/server/graph/loaders/helpers.ts +++ b/server/src/core/server/graph/loaders/helpers.ts @@ -27,7 +27,7 @@ export const sectionFilter = ( } if (section) { - return { section: section.name || null }; + return { section: section.name || undefined }; } return {}; diff --git a/server/src/core/server/graph/mutators/Actions.ts b/server/src/core/server/graph/mutators/Actions.ts index b7a0bcc530..38734d0caf 100644 --- a/server/src/core/server/graph/mutators/Actions.ts +++ b/server/src/core/server/graph/mutators/Actions.ts @@ -63,7 +63,7 @@ export const Actions = (ctx: GraphContext) => ({ undefined, ctx.req, true, - story.isArchived || story.isArchiving + !!(story.isArchived || story.isArchiving) ); }, reviewCommentFlag: async (input: GQLReviewCommentFlagInput) => { diff --git a/server/src/core/server/graph/mutators/Comments.ts b/server/src/core/server/graph/mutators/Comments.ts index 5acb975310..7bfd539439 100644 --- a/server/src/core/server/graph/mutators/Comments.ts +++ b/server/src/core/server/graph/mutators/Comments.ts @@ -285,7 +285,7 @@ export const Comments = (ctx: GraphContext) => ({ await updateTagCommentCounts( ctx.tenant.id, comment.storyID, - comment.siteID, + comment.siteID!, ctx.mongo, ctx.redis, // Create a diff where "before" tags does not have a @@ -346,7 +346,7 @@ export const Comments = (ctx: GraphContext) => ({ await updateTagCommentCounts( ctx.tenant.id, comment.storyID, - comment.siteID, + comment.siteID!, ctx.mongo, ctx.redis, // Create a diff where "before" has the featured tag, diff --git a/server/src/core/server/graph/resolvers/Comment.ts b/server/src/core/server/graph/resolvers/Comment.ts index 9fe008033c..52745c43ed 100644 --- a/server/src/core/server/graph/resolvers/Comment.ts +++ b/server/src/core/server/graph/resolvers/Comment.ts @@ -112,7 +112,7 @@ export const Comment: GQLCommentTypeResolver = { ctx.mongo, ctx.tenant.id, c.id, - story.isArchived || story.isArchiving + !!(story.isArchived || story.isArchiving) ); return !rejectedAncestors; @@ -268,7 +268,7 @@ export const Comment: GQLCommentTypeResolver = { return parent; } else { return hasAncestors(c) - ? maybeLoadOnlyID(ctx, info, c.storyID, c.parentID) + ? maybeLoadOnlyID(ctx, info, c.storyID, c.parentID!) : null; } }, @@ -280,7 +280,7 @@ export const Comment: GQLCommentTypeResolver = { allChildComments: (c, input, ctx) => ctx.loaders.Comments.allChildComments(c, input), story: (c, input, ctx) => ctx.loaders.Stories.story.load(c.storyID), - site: (c, input, ctx) => ctx.loaders.Sites.site.load(c.siteID), + site: (c, input, ctx) => ctx.loaders.Sites.site.load(c.siteID!), permalink: async ({ id, storyID }, input, ctx) => { const story = await ctx.loaders.Stories.story.load(storyID); if (!story) { diff --git a/server/src/core/server/models/comment/comment.ts b/server/src/core/server/models/comment/comment.ts index 70496b3cd1..ca24870d77 100644 --- a/server/src/core/server/models/comment/comment.ts +++ b/server/src/core/server/models/comment/comment.ts @@ -90,7 +90,7 @@ export interface Comment extends TenantResource { /** * siteID stores the ID of the Site that this Comment was left on. */ - siteID: string | null; + siteID?: string | null; /** * section is the section of the story that this comment was left on. If the @@ -1697,7 +1697,7 @@ export async function retrieveLatestFeaturedCommentForAuthor( mongo: MongoContext, tenantID: string, userID: string -) { +): Promise { const $match: FilterQuery = { tenantID, authorID: userID, @@ -1714,5 +1714,5 @@ export async function retrieveLatestFeaturedCommentForAuthor( ]) .toArray(); - return results; + return results as Comment[]; } diff --git a/server/src/core/server/models/story/story.ts b/server/src/core/server/models/story/story.ts index 13b3b583bd..4800e9d34d 100644 --- a/server/src/core/server/models/story/story.ts +++ b/server/src/core/server/models/story/story.ts @@ -91,7 +91,7 @@ export interface Story extends TenantResource { * closedAt is the date that the Story was forced closed at, or false to * indicate that the story was re-opened. */ - closedAt?: Date | false; + closedAt?: Date | false | null; /** * createdAt is the date that the Story was added to the Coral database. @@ -108,9 +108,9 @@ export interface Story extends TenantResource { */ siteID: string | null; - isArchiving?: boolean; - isArchived?: boolean; - isUnarchiving?: boolean; + isArchiving?: boolean | null; + isArchived?: boolean | null; + isUnarchiving?: boolean | null; } export interface UpsertStoryInput { @@ -146,17 +146,12 @@ export async function upsertStory( { returnDocument: "after" } ); - if (!result.ok || !result.value) { - throw new UnableToUpdateStoryURL( - result.lastErrorObject as MongoError, - id, - existingStory.url, - url - ); + if (!result) { + throw new UnableToUpdateStoryURL(id, existingStory.url, url); } return { - story: result.value, + story: result, wasUpserted: true, }; } @@ -203,10 +198,10 @@ export async function upsertStory( return { // The story will either be found (via `result.value`) or upserted (via // `story`). - story: result.value || story, + story: result || story, // The story was upserted if the value isn't provided. - wasUpserted: !result.value, + wasUpserted: !result, }; } catch (err) { // Evaluate the error, if it is in regards to violating the unique index, @@ -425,11 +420,11 @@ export async function updateStory( // document. { returnDocument: "after" } ); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(id); } - return result.value; + return result; } catch (err) { // Evaluate the error, if it is in regards to violating the unique index, // then return a duplicate Story error. @@ -465,11 +460,11 @@ export async function updateStorySettings( // document. { returnDocument: "after" } ); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(id); } - return result.value; + return result; } export async function openStory( @@ -496,11 +491,11 @@ export async function openStory( // document. { returnDocument: "after" } ); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(id); } - return result.value; + return result; } export async function closeStory( @@ -522,11 +517,11 @@ export async function closeStory( // document. { returnDocument: "after" } ); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(id); } - return result.value; + return result; } export async function removeStory( @@ -538,11 +533,11 @@ export async function removeStory( id, tenantID, }); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(id); } - return result.value; + return result; } /** @@ -701,11 +696,11 @@ export async function addStoryExpert( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(storyID); } - return result.value; + return result; } export async function removeStoryExpert( @@ -728,11 +723,11 @@ export async function removeStoryExpert( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(storyID); } - return result.value; + return result; } export async function setStoryMode( @@ -755,11 +750,11 @@ export async function setStoryMode( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new StoryNotFoundError(storyID); } - return result.value; + return result; } /** @@ -817,7 +812,7 @@ export async function forceMarkStoryForArchiving( } ); - return result.value; + return result; } export async function markStoryForArchiving( @@ -840,7 +835,7 @@ export async function markStoryForArchiving( } ); - return result.value; + return result; } export async function markStoryForUnarchiving( @@ -869,7 +864,7 @@ export async function markStoryForUnarchiving( } ); - return result.value; + return result; } export async function retrieveStoryToBeUnarchived( @@ -898,7 +893,7 @@ export async function retrieveStoryToBeUnarchived( } ); - return result.value; + return result; } interface ArchiveCheckStory extends Story { @@ -999,7 +994,7 @@ export async function markStoryAsArchived( } ); - return result.value; + return result; } export async function markStoryAsUnarchived( @@ -1026,7 +1021,7 @@ export async function markStoryAsUnarchived( } ); - return result.value; + return result; } interface CountResult { diff --git a/server/src/core/server/models/tenant/tenant.ts b/server/src/core/server/models/tenant/tenant.ts index 2d0d2c5a93..a6f85a67b8 100644 --- a/server/src/core/server/models/tenant/tenant.ts +++ b/server/src/core/server/models/tenant/tenant.ts @@ -31,6 +31,7 @@ import { GQLDSA_METHOD_OF_REDRESS, GQLFEATURE_FLAG, GQLMODERATION_MODE, + GQLNEW_USER_MODERATION, GQLReactionConfiguration, GQLSettings, GQLWEBHOOK_EVENT_NAME, @@ -578,9 +579,16 @@ export async function deleteTenantFlairBadge( export interface CreateEmailDomainInput { domain: string; - newUserModeration: NewUserModeration; + newUserModeration: GQLNEW_USER_MODERATION; } +const convertUserModerationEnum = ( + value: GQLNEW_USER_MODERATION +): NewUserModeration => { + // these enums are equivalent, just do it + return value as unknown as NewUserModeration; +}; + export async function createTenantEmailDomain( mongo: MongoContext, id: string, @@ -600,7 +608,7 @@ export async function createTenantEmailDomain( const emailDomain = { id: uuid(), domain: input.domain, - newUserModeration: input.newUserModeration, + newUserModeration: convertUserModerationEnum(input.newUserModeration), }; const result = await mongo.tenants().findOneAndUpdate( diff --git a/server/src/core/server/models/user/helpers.ts b/server/src/core/server/models/user/helpers.ts index 90088bf762..1368203046 100644 --- a/server/src/core/server/models/user/helpers.ts +++ b/server/src/core/server/models/user/helpers.ts @@ -72,7 +72,7 @@ export function canModerateUnscoped( } export interface ModerationScopeResource { - siteID?: string; + siteID?: string | null; } /** diff --git a/server/src/core/server/models/user/user.ts b/server/src/core/server/models/user/user.ts index 046252c61f..4bcea4d90d 100644 --- a/server/src/core/server/models/user/user.ts +++ b/server/src/core/server/models/user/user.ts @@ -658,12 +658,12 @@ export interface User extends TenantResource { * scheduledDeletionDate is the time that a user is scheduled to be deleted. * If this is null, the user has not requested for their account to be deleted. */ - scheduledDeletionDate?: Date; + scheduledDeletionDate?: Date | null; /** * deletedAt is the time that this user was deleted from our system. */ - deletedAt?: Date; + deletedAt?: Date | null; /** * mediaSettings are optional media settings for the User. diff --git a/server/src/core/server/services/comments/comments.ts b/server/src/core/server/services/comments/comments.ts index 124550aa0e..756eb1b7bb 100644 --- a/server/src/core/server/services/comments/comments.ts +++ b/server/src/core/server/services/comments/comments.ts @@ -32,7 +32,7 @@ import { export function getCollection( mongo: MongoContext, - isArchived?: boolean + isArchived?: boolean | null ): Collection> { return isArchived && mongo.archive ? mongo.archivedComments() @@ -232,7 +232,7 @@ export async function retrieveCommentConnection( mongo: MongoContext, tenantID: string, input: CommentConnectionInput, - isArchived?: boolean + isArchived?: boolean | null ): Promise>>> { const collection = getCollection(mongo, isArchived); return retrieveCommentConnectionModel(collection, tenantID, input); @@ -253,7 +253,7 @@ export function retrieveCommentUserConnection( tenantID: string, userID: string, input: CommentConnectionInput, - isArchived?: boolean + isArchived?: boolean | null ) { const collection = getCollection(mongo, isArchived); return retrieveCommentUserConnectionModel( @@ -280,7 +280,7 @@ export function retrieveAllCommentsUserConnection( tenantID: string, userID: string, input: CommentConnectionInput, - isArchived?: boolean + isArchived?: boolean | null ) { const collection = getCollection(mongo, isArchived); return retrieveAllCommentsUserConnectionModel( @@ -310,7 +310,7 @@ export function retrieveCommentsBySitesUserConnection( userID: string, siteIDs: string[], input: CommentConnectionInput, - isArchived?: boolean + isArchived?: boolean | null ) { const collection = getCollection(mongo, isArchived); return retrieveCommentsBySitesUserConnectionModel( @@ -366,7 +366,7 @@ export async function retrieveCommentStoryConnection( tenantID: string, storyID: string, input: CommentConnectionInput, - isArchived?: boolean + isArchived?: boolean | null ) { const collection = getCollection(mongo, isArchived); const conn = await retrieveCommentStoryConnectionModel( @@ -397,7 +397,7 @@ export function retrieveCommentRepliesConnection( storyID: string, parentID: string, input: CommentConnectionInput, - isArchived?: boolean + isArchived?: boolean | null ) { const collection = getCollection(mongo, isArchived); return retrieveCommentRepliesConnectionModel( @@ -424,7 +424,7 @@ export function retrieveCommentParentsConnection( tenantID: string, comment: Comment, paginationParameters: { last: number; before?: number }, - isArchived?: boolean + isArchived?: boolean | null ) { const collection = isArchived && mongo.archive ? mongo.archivedComments() : mongo.comments(); @@ -452,7 +452,7 @@ export function retrieveChildrenForParentConnection( tenantID: string, comment: Comment, input: CommentConnectionInput, - isArchived?: boolean + isArchived?: boolean | null ) { const collection = isArchived && mongo.archive ? mongo.archivedComments() : mongo.comments(); diff --git a/server/src/core/server/services/users/delete.ts b/server/src/core/server/services/users/delete.ts index 673fd4c228..66051efc54 100644 --- a/server/src/core/server/services/users/delete.ts +++ b/server/src/core/server/services/users/delete.ts @@ -186,7 +186,7 @@ async function updateUserDSAReports( mongo: MongoContext, tenantID: string, authorID: string, - isArchived?: boolean + isArchived?: boolean | null ) { const batch: DSAReportBatch = { dsaReports: [], @@ -278,7 +278,7 @@ async function deleteUserComments( authorID: string, tenantID: string, now: Date, - isArchived?: boolean + isArchived?: boolean | null ) { const tenant = await retrieveTenant(mongo, tenantID); if (!tenant) { From a6ebd6b54a531b590639c191830be17473d3a357 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Tue, 1 Oct 2024 17:09:12 -0600 Subject: [PATCH 05/22] WIP: even more type fixes --- .../src/core/server/graph/resolvers/Story.ts | 4 +-- .../server/graph/resolvers/StorySettings.ts | 2 +- .../core/server/graph/subscriptions/server.ts | 2 +- .../src/core/server/models/comment/comment.ts | 14 +++----- .../server/models/comment/counts/counts.ts | 12 +++---- .../core/server/models/dsaReport/report.ts | 28 ++++++++------- server/src/core/server/models/invite.ts | 6 ++-- .../models/notifications/notification.ts | 2 +- .../src/core/server/models/queries/queries.ts | 2 +- .../models/seenComments/seenComments.ts | 2 +- .../settings/signingSecret/signingSecret.ts | 24 ++++++++----- .../models/tenant/externalModerationPhase.ts | 16 ++++----- .../src/core/server/models/tenant/helpers.ts | 2 +- server/src/core/server/models/tenant/sso.ts | 8 ++--- .../server/models/tenant/webhookEndpoint.ts | 16 ++++----- .../src/core/server/services/archive/index.ts | 14 ++++---- .../core/server/services/comments/actions.ts | 8 ++--- .../comments/pipeline/phases/external.ts | 2 +- .../pipeline/phases/statusPreModerate.ts | 4 +-- .../phases/statusPreModerateNewCommenter.ts | 2 +- .../comments/pipeline/phases/tagMember.ts | 2 +- .../core/server/services/events/comments.ts | 36 +++++++++---------- .../src/core/server/services/migrate/batch.ts | 13 ++++--- .../core/server/services/migrate/indexing.ts | 12 +++---- .../core/server/services/migrate/migration.ts | 3 +- .../src/core/server/services/stories/index.ts | 2 +- .../server/services/tenant/tenant.spec.ts | 9 +++-- .../src/core/server/services/users/delete.ts | 4 +-- .../stacks/helpers/updateAllCommentCounts.ts | 2 +- .../src/core/server/stacks/rejectComment.ts | 2 +- 30 files changed, 131 insertions(+), 124 deletions(-) diff --git a/server/src/core/server/graph/resolvers/Story.ts b/server/src/core/server/graph/resolvers/Story.ts index 16ccf93e94..d97d439900 100644 --- a/server/src/core/server/graph/resolvers/Story.ts +++ b/server/src/core/server/graph/resolvers/Story.ts @@ -51,7 +51,7 @@ export const Story: GQLStoryTypeResolver = { ctx.tenant ), moderationQueues: storyModerationInputResolver, - site: (s, input, ctx) => ctx.loaders.Sites.site.load(s.siteID), + site: (s, input, ctx) => ctx.loaders.Sites.site.load(s.siteID!), viewerRating: (s, input, ctx) => { if ( !hasFeatureFlag(ctx.tenant, GQLFEATURE_FLAG.ENABLE_RATINGS_AND_REVIEWS) @@ -90,7 +90,7 @@ export const Story: GQLStoryTypeResolver = { } // Return the computed count! - return ctx.loaders.Stories.viewerCount(s.siteID, s.id); + return ctx.loaders.Stories.viewerCount(s.siteID!, s.id); }, cached: async (s, input, ctx) => { return ctx.cache.comments.isCached(s.tenantID, s.id); diff --git a/server/src/core/server/graph/resolvers/StorySettings.ts b/server/src/core/server/graph/resolvers/StorySettings.ts index 08633e83ef..563a49d0d5 100644 --- a/server/src/core/server/graph/resolvers/StorySettings.ts +++ b/server/src/core/server/graph/resolvers/StorySettings.ts @@ -20,7 +20,7 @@ export const StorySettings: Required< return s.moderation; } if (ctx.tenant.moderation === GQLMODERATION_MODE.SPECIFIC_SITES_PRE) { - return ctx.tenant.premoderateAllCommentsSites.includes(s.story.siteID) + return ctx.tenant.premoderateAllCommentsSites.includes(s.story.siteID!) ? GQLMODERATION_MODE.PRE : GQLMODERATION_MODE.POST; } diff --git a/server/src/core/server/graph/subscriptions/server.ts b/server/src/core/server/graph/subscriptions/server.ts index c869d7050b..ce45d39b14 100644 --- a/server/src/core/server/graph/subscriptions/server.ts +++ b/server/src/core/server/graph/subscriptions/server.ts @@ -261,7 +261,7 @@ export function onConnect(options: OnConnectOptions): OnConnectFn { options.redis, { tenantID: tenant.id, - siteID: story.siteID, + siteID: story.siteID!, storyID: story.id, }, clientID, diff --git a/server/src/core/server/models/comment/comment.ts b/server/src/core/server/models/comment/comment.ts index ca24870d77..98f78d42c7 100644 --- a/server/src/core/server/models/comment/comment.ts +++ b/server/src/core/server/models/comment/comment.ts @@ -97,7 +97,7 @@ export interface Comment extends TenantResource { * section was not available when the comment was authored, the section will * be null here. */ - section?: string; + section?: string | null; /** * revisions stores all the revisions of the Comment body including the most @@ -1002,13 +1002,7 @@ export async function addCommentTag( { tenantID, id: commentID, - tags: { - $not: { - $eq: { - type: tag.type, - }, - }, - }, + "tags.type": { $not: { $eq: tag.type } }, }, { $push: { @@ -1021,7 +1015,7 @@ export async function addCommentTag( returnDocument: "after", } ); - if (!result.value) { + if (!result) { const comment = await retrieveComment( mongo.comments(), tenantID, @@ -1038,7 +1032,7 @@ export async function addCommentTag( throw new Error("could not add a tag for an unexpected reason"); } - return result.value; + return result; } export async function removeCommentTag( diff --git a/server/src/core/server/models/comment/counts/counts.ts b/server/src/core/server/models/comment/counts/counts.ts index 3ef3630db4..2c013e9df4 100644 --- a/server/src/core/server/models/comment/counts/counts.ts +++ b/server/src/core/server/models/comment/counts/counts.ts @@ -1,5 +1,5 @@ import { identity, isEmpty, pickBy } from "lodash"; -import { Collection } from "mongodb"; +import { Collection, Document } from "mongodb"; import { DeepPartial } from "coral-common/common/lib/types"; import logger from "coral-server/logger"; @@ -216,16 +216,14 @@ export function calculateTotalPublishedCommentCount( ); } -interface RelatedCommentCountsDocument { +interface RelatedCommentCountsDocument extends Document { id: string; tenantID: string; commentCounts: Partial; } -export async function updateRelatedCommentCounts< - T extends RelatedCommentCountsDocument ->( - collection: Collection, +export async function updateRelatedCommentCounts( + collection: Collection, tenantID: string, id: string, commentCounts: DeepPartial @@ -259,7 +257,7 @@ export async function updateRelatedCommentCounts< { returnDocument: "after" } ); - return result.value || null; + return result || null; } export const negateCommentCounts = (options: { diff --git a/server/src/core/server/models/dsaReport/report.ts b/server/src/core/server/models/dsaReport/report.ts index b41812de1a..a5223cc388 100644 --- a/server/src/core/server/models/dsaReport/report.ts +++ b/server/src/core/server/models/dsaReport/report.ts @@ -338,12 +338,12 @@ export async function createDSAReportNote( { returnDocument: "after" } ); - if (!updatedReport.value) { + if (!updatedReport) { throw new Error(); } return { - dsaReport: updatedReport.value, + dsaReport: updatedReport, }; } @@ -387,12 +387,12 @@ export async function createDSAReportShare( { returnDocument: "after" } ); - if (!updatedReport.value) { + if (!updatedReport) { throw new Error(); } return { - dsaReport: updatedReport.value, + dsaReport: updatedReport, }; } @@ -425,12 +425,12 @@ export async function deleteDSAReportNote( { returnDocument: "after" } ); - if (!updatedReport.value) { + if (!updatedReport) { throw new Error(); } return { - dsaReport: updatedReport.value, + dsaReport: updatedReport, }; } @@ -458,11 +458,13 @@ export async function changeDSAReportStatus( // Create a new ID for the DSAReportHistoryItem. const id = uuid(); - const statusChangeHistoryItem = { + const typedStatus = status as GQLDSAReportStatus; + + const statusChangeHistoryItem: ReportHistoryItem = { id, createdBy: userID, createdAt: now, - status, + status: typedStatus, type: GQLDSAReportHistoryType.STATUS_CHANGED, }; @@ -472,17 +474,17 @@ export async function changeDSAReportStatus( $push: { history: statusChangeHistoryItem, }, - $set: { status }, + $set: { status: typedStatus }, }, { returnDocument: "after" } ); - if (!updatedReport.value) { + if (!updatedReport) { throw new Error(); } return { - dsaReport: updatedReport.value, + dsaReport: updatedReport, }; } @@ -552,12 +554,12 @@ export async function makeDSAReportDecision( { returnDocument: "after" } ); - if (!updatedReport.value) { + if (!updatedReport) { throw new Error(); } return { - dsaReport: updatedReport.value, + dsaReport: updatedReport, }; } diff --git a/server/src/core/server/models/invite.ts b/server/src/core/server/models/invite.ts index c524ce7f73..62aecf62f4 100644 --- a/server/src/core/server/models/invite.ts +++ b/server/src/core/server/models/invite.ts @@ -59,11 +59,11 @@ export async function redeemInvite( ) { // Try to snag the invite from the database safely. const result = await mongo.invites().findOneAndDelete({ id, tenantID }, {}); - if (!result.value) { + if (!result) { throw new Error("an unexpected error occurred"); } - return result.value; + return result; } export async function redeemInviteFromEmail( @@ -76,7 +76,7 @@ export async function redeemInviteFromEmail( .invites() .findOneAndDelete({ email, tenantID }, {}); - return result.value || null; + return result; } export async function retrieveInviteFromEmail( diff --git a/server/src/core/server/models/notifications/notification.ts b/server/src/core/server/models/notifications/notification.ts index 81ec8e5178..ac591cff2f 100644 --- a/server/src/core/server/models/notifications/notification.ts +++ b/server/src/core/server/models/notifications/notification.ts @@ -77,7 +77,7 @@ export const createNotification = async ( ) => { const op = await mongo.notifications().insertOne(notification); - return op.result.ok ? notification : null; + return op.acknowledged ? notification : null; }; interface LastSeenNotificationChange { diff --git a/server/src/core/server/models/queries/queries.ts b/server/src/core/server/models/queries/queries.ts index 066c89fd12..0f53d963ed 100644 --- a/server/src/core/server/models/queries/queries.ts +++ b/server/src/core/server/models/queries/queries.ts @@ -32,7 +32,7 @@ export async function primeQueries( try { // Execute the bulk operations. - await bulk.execute({ w: "majority" }); + await bulk.execute({ writeConcern: { w: "majority" } }); return; } catch (err) { diff --git a/server/src/core/server/models/seenComments/seenComments.ts b/server/src/core/server/models/seenComments/seenComments.ts index 6cfed6fdb4..3b94f5536e 100644 --- a/server/src/core/server/models/seenComments/seenComments.ts +++ b/server/src/core/server/models/seenComments/seenComments.ts @@ -129,7 +129,7 @@ export async function markSeenComments( { upsert: true } ); - return result.value; + return result; } export async function markSeenCommentsBulk( diff --git a/server/src/core/server/models/settings/signingSecret/signingSecret.ts b/server/src/core/server/models/settings/signingSecret/signingSecret.ts index e856af32f1..9e7999eab7 100644 --- a/server/src/core/server/models/settings/signingSecret/signingSecret.ts +++ b/server/src/core/server/models/settings/signingSecret/signingSecret.ts @@ -1,5 +1,11 @@ import { get } from "lodash"; -import { Collection, FindOneAndUpdateOption, UpdateQuery } from "mongodb"; +import { + Collection, + Document, + FindOneAndUpdateOptions, + UpdateFilter as UpdateQuery, + WithId, +} from "mongodb"; import logger from "coral-server/logger"; import { FilterQuery } from "coral-server/models/helpers"; @@ -132,7 +138,7 @@ async function pushNewSigningSecret({ } // Generate the options for the operation. - const options: FindOneAndUpdateOption = { + const options: FindOneAndUpdateOptions = { // False to return the updated document instead of the original // document. returnDocument: "after", @@ -146,11 +152,11 @@ async function pushNewSigningSecret({ // Update the resource with this new secret. const result = await collection.findOneAndUpdate(filter, update, options); - if (!result.value) { + if (!result) { return null; } - return result.value; + return result; } function getResourceFromDoc( @@ -190,7 +196,7 @@ function getResourceFromDoc( return resource; } -async function deprecateOldSigningSecrets( +async function deprecateOldSigningSecrets( { collection, path, @@ -202,7 +208,7 @@ async function deprecateOldSigningSecrets( RotateSigningSecretOptions, "collection" | "path" | "inactiveAt" | "filter" | "id" | "now" >, - doc: Readonly + doc: Readonly | WithId> ) { // Get the resource from the value. const resource = getResourceFromDoc({ id, path }, doc); @@ -243,7 +249,7 @@ async function deprecateOldSigningSecrets( } // Construct the options for the operation. - const options: FindOneAndUpdateOption = { + const options: FindOneAndUpdateOptions = { // False to return the updated document instead of the original // document. returnDocument: "after", @@ -261,11 +267,11 @@ async function deprecateOldSigningSecrets( // Deactivate the old keys. const result = await collection.findOneAndUpdate(filter, update, options); - if (!result.value) { + if (!result) { return null; } - return result.value; + return result; } export async function rotateSigningSecret( diff --git a/server/src/core/server/models/tenant/externalModerationPhase.ts b/server/src/core/server/models/tenant/externalModerationPhase.ts index f8d3fb66af..20a4d56875 100644 --- a/server/src/core/server/models/tenant/externalModerationPhase.ts +++ b/server/src/core/server/models/tenant/externalModerationPhase.ts @@ -64,7 +64,7 @@ export async function createTenantExternalModerationPhase( returnDocument: "after", } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return { @@ -78,7 +78,7 @@ export async function createTenantExternalModerationPhase( return { phase, - tenant: result.value, + tenant: result, }; } @@ -118,7 +118,7 @@ export async function updateTenantExternalModerationPhase( arrayFilters: [{ "phase.id": phaseID }], } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return null; @@ -139,7 +139,7 @@ export async function updateTenantExternalModerationPhase( throw new Error("update failed for an unexpected reason"); } - return result.value; + return result; } export async function deleteTenantExternalModerationPhase( @@ -160,7 +160,7 @@ export async function deleteTenantExternalModerationPhase( returnDocument: "after", } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return null; @@ -169,7 +169,7 @@ export async function deleteTenantExternalModerationPhase( throw new Error("update failed for an unexpected reason"); } - return result.value; + return result; } export async function deleteTenantExternalModerationPhaseSigningSecrets( @@ -189,7 +189,7 @@ export async function deleteTenantExternalModerationPhaseSigningSecrets( }, { returnDocument: "after", arrayFilters: [{ "phase.id": phaseID }] } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return null; @@ -210,5 +210,5 @@ export async function deleteTenantExternalModerationPhaseSigningSecrets( throw new Error("update failed for an unexpected reason"); } - return result.value; + return result; } diff --git a/server/src/core/server/models/tenant/helpers.ts b/server/src/core/server/models/tenant/helpers.ts index 19d25e87d6..4f0df07364 100644 --- a/server/src/core/server/models/tenant/helpers.ts +++ b/server/src/core/server/models/tenant/helpers.ts @@ -103,7 +103,7 @@ export function getWebhookEndpoint( tenant: Pick, endpointID: string ) { - return tenant.webhooks.endpoints.find((e) => e.id === endpointID) || null; + return tenant.webhooks?.endpoints.find((e) => e.id === endpointID) || null; } export function supportsMediaType( diff --git a/server/src/core/server/models/tenant/sso.ts b/server/src/core/server/models/tenant/sso.ts index 7e8d3d8bf4..9348a0d5f5 100644 --- a/server/src/core/server/models/tenant/sso.ts +++ b/server/src/core/server/models/tenant/sso.ts @@ -42,11 +42,11 @@ export async function deactivateTenantSSOSigningSecret( arrayFilters: [{ "signingSecrets.kid": kid }], } ); - if (!result.value) { + if (!result) { throw new Error("tenant not found with id"); } - return result.value; + return result; } export async function deleteTenantSSOSigningSecret( @@ -68,9 +68,9 @@ export async function deleteTenantSSOSigningSecret( returnDocument: "after", } ); - if (!result.value) { + if (!result) { throw new Error("tenant not found with id"); } - return result.value; + return result; } diff --git a/server/src/core/server/models/tenant/webhookEndpoint.ts b/server/src/core/server/models/tenant/webhookEndpoint.ts index 946b3c7a88..ae2f427886 100644 --- a/server/src/core/server/models/tenant/webhookEndpoint.ts +++ b/server/src/core/server/models/tenant/webhookEndpoint.ts @@ -60,7 +60,7 @@ export async function createTenantWebhookEndpoint( returnDocument: "after", } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return { @@ -74,7 +74,7 @@ export async function createTenantWebhookEndpoint( return { endpoint, - tenant: result.value, + tenant: result, }; } @@ -113,7 +113,7 @@ export async function updateTenantWebhookEndpoint( arrayFilters: [{ "endpoint.id": endpointID }], } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return null; @@ -129,7 +129,7 @@ export async function updateTenantWebhookEndpoint( throw new Error("update failed for an unexpected reason"); } - return result.value; + return result; } export async function deleteTenantWebhookEndpointSigningSecrets( @@ -147,7 +147,7 @@ export async function deleteTenantWebhookEndpointSigningSecrets( }, { returnDocument: "after", arrayFilters: [{ "endpoint.id": endpointID }] } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return null; @@ -163,7 +163,7 @@ export async function deleteTenantWebhookEndpointSigningSecrets( throw new Error("update failed for an unexpected reason"); } - return result.value; + return result; } export async function deleteTenantWebhookEndpoint( @@ -184,7 +184,7 @@ export async function deleteTenantWebhookEndpoint( returnDocument: "after", } ); - if (!result.value) { + if (!result) { const tenant = await retrieveTenant(mongo, id); if (!tenant) { return null; @@ -193,7 +193,7 @@ export async function deleteTenantWebhookEndpoint( throw new Error("update failed for an unexpected reason"); } - return result.value; + return result; } function lastUsedAtTenantSSOSigningSecret(id: string): string { diff --git a/server/src/core/server/services/archive/index.ts b/server/src/core/server/services/archive/index.ts index 41d3077a9a..5871c41d7c 100644 --- a/server/src/core/server/services/archive/index.ts +++ b/server/src/core/server/services/archive/index.ts @@ -1,4 +1,4 @@ -import { Collection, FilterQuery } from "mongodb"; +import { Collection, Document, Filter as FilterQuery, WithId } from "mongodb"; import { MongoContext } from "coral-server/data/context"; import { StoryNotFoundError } from "coral-server/errors"; @@ -86,7 +86,7 @@ export async function archiveStory( }); logger.info("updating site counts for archive"); - await updateSiteCounts(mongo, tenantID, targetStory.siteID, commentCounts); + await updateSiteCounts(mongo, tenantID, targetStory.siteID!, commentCounts); logger.info("updating shared counts for archive"); await updateSharedCommentCounts(redis, tenantID, commentCounts); @@ -114,7 +114,7 @@ export async function unarchiveStory( const targetStory = await mongo .stories() - .findOne({ id, tenantID }, { maxTimeMs: 30 * 60 * 1000 }); + .findOne({ id, tenantID }, { maxTimeMS: 30 * 60 * 1000 }); if (!targetStory) { throw new StoryNotFoundError(id); } @@ -172,7 +172,7 @@ export async function unarchiveStory( }); logger.info("updating site counts for unarchive"); - await updateSiteCounts(mongo, tenantID, targetStory.siteID, commentCounts); + await updateSiteCounts(mongo, tenantID, targetStory.siteID!, commentCounts); logger.info("updating shared counts for unarchive"); await updateSharedCommentCounts(redis, tenantID, commentCounts); @@ -184,7 +184,7 @@ export async function unarchiveStory( return result; } -interface MoveDocumentsOptions { +interface MoveDocumentsOptions { tenantID: string; source: Collection; filter: FilterQuery; @@ -201,11 +201,11 @@ async function moveDocuments({ returnMovedIDs = false, batchSize = 100, }: MoveDocumentsOptions) { - let insertBatch: T[] = []; + let insertBatch: Array> = []; let deleteIDs: string[] = []; const allIDs: string[] = []; - const selectionCursor = source.find(filter, { maxTimeMs: 30 * 60 * 1000 }); + const selectionCursor = source.find(filter, { maxTimeMS: 30 * 60 * 1000 }); while (await selectionCursor.hasNext()) { const document = await selectionCursor.next(); diff --git a/server/src/core/server/services/comments/actions.ts b/server/src/core/server/services/comments/actions.ts index 9fa51f381a..58dafed34b 100644 --- a/server/src/core/server/services/comments/actions.ts +++ b/server/src/core/server/services/comments/actions.ts @@ -143,9 +143,9 @@ async function addCommentAction( // Check if the user is banned on this site, if they are, throw an error right // now. // NOTE: this should be removed with attribute based auth checks. - if (author && isSiteBanned(author, siteID)) { + if (author && isSiteBanned(author, siteID!)) { // Get the site in question. - const site = await retrieveSite(mongo, tenant.id, siteID); + const site = await retrieveSite(mongo, tenant.id, siteID!); if (!site) { throw new Error(`referenced site not found: ${siteID}`); } @@ -157,9 +157,9 @@ async function addCommentAction( const action: CreateAction = { ...input, storyID, - siteID, + siteID: siteID!, userID: author ? author.id : null, - section, + section: section ?? undefined, }; // Update the actions for the comment. diff --git a/server/src/core/server/services/comments/pipeline/phases/external.ts b/server/src/core/server/services/comments/pipeline/phases/external.ts index 0b0cfb840c..c1ca6c7214 100644 --- a/server/src/core/server/services/comments/pipeline/phases/external.ts +++ b/server/src/core/server/services/comments/pipeline/phases/external.ts @@ -210,7 +210,7 @@ async function processPhase( url: story.url, }, site: { - id: story.siteID, + id: story.siteID!, }, tenantID: tenant.id, tenantDomain: tenant.domain, diff --git a/server/src/core/server/services/comments/pipeline/phases/statusPreModerate.ts b/server/src/core/server/services/comments/pipeline/phases/statusPreModerate.ts index 91c6872b06..b78d084a7f 100755 --- a/server/src/core/server/services/comments/pipeline/phases/statusPreModerate.ts +++ b/server/src/core/server/services/comments/pipeline/phases/statusPreModerate.ts @@ -28,8 +28,8 @@ export const statusPreModerate: IntermediateModerationPhase = ({ // If the settings say that we're in premod mode, then the comment is in // premod status. if ( - testModerationMode(tenant, story.siteID) || - (story.settings && testModerationMode(story.settings, story.siteID)) + testModerationMode(tenant, story.siteID!) || + (story.settings && testModerationMode(story.settings, story.siteID!)) ) { return { status: GQLCOMMENT_STATUS.PREMOD, diff --git a/server/src/core/server/services/comments/pipeline/phases/statusPreModerateNewCommenter.ts b/server/src/core/server/services/comments/pipeline/phases/statusPreModerateNewCommenter.ts index 1b164b1dfe..ac1bf0451e 100644 --- a/server/src/core/server/services/comments/pipeline/phases/statusPreModerateNewCommenter.ts +++ b/server/src/core/server/services/comments/pipeline/phases/statusPreModerateNewCommenter.ts @@ -28,7 +28,7 @@ export const statusPreModerateNewCommenter = async ({ // If premodSites doesn't include this site id, then do nothing! if ( tenant.newCommenters.moderation.premodSites && - !tenant.newCommenters.moderation.premodSites.includes(story.siteID) + !tenant.newCommenters.moderation.premodSites.includes(story.siteID!) ) { return; } diff --git a/server/src/core/server/services/comments/pipeline/phases/tagMember.ts b/server/src/core/server/services/comments/pipeline/phases/tagMember.ts index 023b8f416d..74c821185c 100644 --- a/server/src/core/server/services/comments/pipeline/phases/tagMember.ts +++ b/server/src/core/server/services/comments/pipeline/phases/tagMember.ts @@ -8,7 +8,7 @@ export const tagMember: IntermediateModerationPhase = ({ author, story }) => { const isMember = author.role === GQLUSER_ROLE.MEMBER; const isScoped = !!author.membershipScopes?.siteIDs?.length; const inScope = - isScoped && author.membershipScopes.siteIDs!.includes(story.siteID); + isScoped && author.membershipScopes.siteIDs!.includes(story.siteID!); const tagAsMember = isMember && (!isScoped || inScope); return { diff --git a/server/src/core/server/services/events/comments.ts b/server/src/core/server/services/events/comments.ts index 69c8553859..54f9011349 100644 --- a/server/src/core/server/services/events/comments.ts +++ b/server/src/core/server/services/events/comments.ts @@ -58,7 +58,7 @@ export async function publishCommentReplyCreated( ancestorIDs: comment.ancestorIDs, commentID: comment.id, storyID: comment.storyID, - siteID: comment.siteID, + siteID: comment.siteID!, }); } } @@ -71,7 +71,7 @@ export async function publishCommentCreated( await CommentCreatedCoralEvent.publish(broker, { commentID: comment.id, storyID: comment.storyID, - siteID: comment.siteID, + siteID: comment.siteID!, }); } } @@ -118,10 +118,10 @@ export async function publishCommentReactionCreated( await CommentReactionCreatedCoralEvent.publish(broker, { commentID: comment.id, commentRevisionID, - commentParentID: comment.parentID, + commentParentID: comment.parentID ?? undefined, actionUserID: userID, storyID: comment.storyID, - siteID: comment.siteID, + siteID: comment.siteID!, }); } } @@ -138,11 +138,11 @@ export async function publishCommentFlagCreated( await CommentFlagCreatedCoralEvent.publish(broker, { commentID: comment.id, commentRevisionID, - commentParentID: comment.parentID, + commentParentID: comment.parentID ?? undefined, actionUserID: userID, flagReason: reason, storyID: comment.storyID, - siteID: comment.siteID, + siteID: comment.siteID!, }); } } @@ -170,8 +170,8 @@ export async function publishModerationQueueChanges( commentID: comment.id, status: comment.status, storyID: comment.storyID, - siteID: comment.siteID, - section: comment.section, + siteID: comment.siteID!, + section: comment.section ?? undefined, }); } else if (moderationQueue.queues.pending === -1) { await CommentLeftModerationQueueCoralEvent.publish(broker, { @@ -179,8 +179,8 @@ export async function publishModerationQueueChanges( commentID: comment.id, status: comment.status, storyID: comment.storyID, - siteID: comment.siteID, - section: comment.section, + siteID: comment.siteID!, + section: comment.section ?? undefined, }); } if (moderationQueue.queues.reported === 1) { @@ -189,8 +189,8 @@ export async function publishModerationQueueChanges( commentID: comment.id, status: comment.status, storyID: comment.storyID, - siteID: comment.siteID, - section: comment.section, + siteID: comment.siteID!, + section: comment.section ?? undefined, }); } else if (moderationQueue.queues.reported === -1) { await CommentLeftModerationQueueCoralEvent.publish(broker, { @@ -198,8 +198,8 @@ export async function publishModerationQueueChanges( commentID: comment.id, status: comment.status, storyID: comment.storyID, - siteID: comment.siteID, - section: comment.section, + siteID: comment.siteID!, + section: comment.section ?? undefined, }); } if (moderationQueue.queues.unmoderated === 1) { @@ -208,8 +208,8 @@ export async function publishModerationQueueChanges( commentID: comment.id, status: comment.status, storyID: comment.storyID, - siteID: comment.siteID, - section: comment.section, + siteID: comment.siteID!, + section: comment.section ?? undefined, }); } else if (moderationQueue.queues.unmoderated === -1) { await CommentLeftModerationQueueCoralEvent.publish(broker, { @@ -217,8 +217,8 @@ export async function publishModerationQueueChanges( commentID: comment.id, status: comment.status, storyID: comment.storyID, - siteID: comment.siteID, - section: comment.section, + siteID: comment.siteID!, + section: comment.section ?? undefined, }); } } diff --git a/server/src/core/server/services/migrate/batch.ts b/server/src/core/server/services/migrate/batch.ts index b84f383259..16dcd31974 100644 --- a/server/src/core/server/services/migrate/batch.ts +++ b/server/src/core/server/services/migrate/batch.ts @@ -1,18 +1,21 @@ -import { Collection, FilterQuery, UpdateQuery } from "mongodb"; +import { + Collection, + Filter as FilterQuery, + UpdateManyModel as UpdateQuery, +} from "mongodb"; import { Logger } from "coral-server/logger"; -import { TenantResource } from "coral-server/models/tenant"; -interface UpdateOneOperation { +interface UpdateOneOperation { updateOne: { filter: FilterQuery; update: UpdateQuery; }; } -type Operation = UpdateOneOperation; +type Operation = UpdateOneOperation; -class Batch { +class Batch { private readonly logger: Logger; private readonly collection: Collection; private readonly maxBatchSize: number; diff --git a/server/src/core/server/services/migrate/indexing.ts b/server/src/core/server/services/migrate/indexing.ts index 00570d9331..3ff791a8c0 100644 --- a/server/src/core/server/services/migrate/indexing.ts +++ b/server/src/core/server/services/migrate/indexing.ts @@ -1,5 +1,5 @@ import { merge } from "lodash"; -import { Collection, IndexOptions } from "mongodb"; +import { Collection, CreateIndexesOptions, Document } from "mongodb"; import { Writable } from "coral-common/common/lib/types"; import { MongoContext } from "coral-server/data/context"; @@ -14,13 +14,13 @@ export type IndexSpecification = { type IndexCreationFunction = ( indexSpec: IndexSpecification, - indexOptions?: IndexOptions + indexOptions?: CreateIndexesOptions ) => Promise; -export async function createIndex( +export async function createIndex( collection: Collection, indexSpec: IndexSpecification, - indexOptions: IndexOptions = {} + indexOptions: CreateIndexesOptions = {} ) { const log = logger.child( { @@ -50,12 +50,12 @@ export async function createIndex( } } -export function createIndexFactory( +export function createIndexFactory( collection: Collection ): IndexCreationFunction { return async ( indexSpec: IndexSpecification, - indexOptions: IndexOptions = {} + indexOptions: CreateIndexesOptions = {} ) => createIndex(collection, indexSpec, indexOptions); } diff --git a/server/src/core/server/services/migrate/migration.ts b/server/src/core/server/services/migrate/migration.ts index 26770f7025..d8d8794b15 100644 --- a/server/src/core/server/services/migrate/migration.ts +++ b/server/src/core/server/services/migrate/migration.ts @@ -54,7 +54,8 @@ abstract class Migration { tenantID: string, size = 500 ) { - return new Batch(this.log(tenantID), collection, size, tenantID); + const coll = collection as unknown as Collection; + return new Batch(this.log(tenantID), coll, size, tenantID); } } diff --git a/server/src/core/server/services/stories/index.ts b/server/src/core/server/services/stories/index.ts index cbb886522a..822a10f383 100644 --- a/server/src/core/server/services/stories/index.ts +++ b/server/src/core/server/services/stories/index.ts @@ -148,7 +148,7 @@ export async function findOrCreate( StoryCreatedCoralEvent.publish(broker, { storyID: story.id, storyURL: story.url, - siteID: story.siteID, + siteID: story.siteID!, }).catch((err) => { logger.error({ err }, "could not publish story created event"); }); diff --git a/server/src/core/server/services/tenant/tenant.spec.ts b/server/src/core/server/services/tenant/tenant.spec.ts index 6b594168fe..0596f3d85f 100644 --- a/server/src/core/server/services/tenant/tenant.spec.ts +++ b/server/src/core/server/services/tenant/tenant.spec.ts @@ -3,7 +3,10 @@ jest.mock("coral-server/models/user"); jest.mock("coral-server/models/site"); import { UserForbiddenError } from "coral-server/errors"; -import { GQLUSER_ROLE } from "coral-server/graph/schema/__generated__/types"; +import { + GQLNEW_USER_MODERATION, + GQLUSER_ROLE, +} from "coral-server/graph/schema/__generated__/types"; import { createSiteFixture, createTenantFixture, @@ -52,7 +55,7 @@ describe("createEmailDomain", () => { mockAdmin, { domain: "badsite.com", - newUserModeration: "BAN", + newUserModeration: GQLNEW_USER_MODERATION.BAN, } ); @@ -70,7 +73,7 @@ it("does not create domain bans for protected domains", async () => { await expect(async () => createEmailDomain(mockMongo, mockRedis, mockTenantCache, tenant, viewer, { domain: protectedDomain, - newUserModeration: "BAN", + newUserModeration: GQLNEW_USER_MODERATION.BAN, }) ).rejects.toThrow("EMAIL_DOMAIN_PROTECTED"); }); diff --git a/server/src/core/server/services/users/delete.ts b/server/src/core/server/services/users/delete.ts index 66051efc54..0a57484d7e 100644 --- a/server/src/core/server/services/users/delete.ts +++ b/server/src/core/server/services/users/delete.ts @@ -301,7 +301,7 @@ async function deleteUserComments( }, GQLCOMMENT_STATUS.APPROVED, now, - isArchived + !!isArchived ); const bundle = i18n.getBundle(tenant.locale); @@ -334,7 +334,7 @@ async function deleteUserComments( }, GQLCOMMENT_STATUS.REJECTED, now, - isArchived, + !!isArchived, { code: GQLREJECTION_REASON_CODE.OTHER, detailedExplanation: translatedExplanation, diff --git a/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts b/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts index 19cf4f32cb..f87124d350 100644 --- a/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts +++ b/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts @@ -237,7 +237,7 @@ export default async function updateAllCommentCounts( } if (options.updateSite) { - await updateSiteCounts(mongo, tenant.id, siteID, { + await updateSiteCounts(mongo, tenant.id, siteID!, { action, status, moderationQueue, diff --git a/server/src/core/server/stacks/rejectComment.ts b/server/src/core/server/stacks/rejectComment.ts index 02d75dd10e..153bf2455b 100644 --- a/server/src/core/server/stacks/rejectComment.ts +++ b/server/src/core/server/stacks/rejectComment.ts @@ -61,7 +61,7 @@ const stripTag = async ( await updateTagCommentCounts( tenant.id, comment.storyID, - comment.siteID, + comment.siteID!, mongo, redis, // Create a diff where "before" tags have the target tag and From 045bd496c0c67f20d0625f65af7b725dfe4ba05a Mon Sep 17 00:00:00 2001 From: nick-funk Date: Sun, 6 Oct 2024 15:54:55 -0600 Subject: [PATCH 06/22] replace `remove` with `delete` --- server/src/core/server/services/archive/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/core/server/services/archive/index.ts b/server/src/core/server/services/archive/index.ts index 5871c41d7c..9c932505fc 100644 --- a/server/src/core/server/services/archive/index.ts +++ b/server/src/core/server/services/archive/index.ts @@ -228,7 +228,7 @@ async function moveDocuments({ await bulkInsert.execute(); const bulkDelete = source.initializeUnorderedBulkOp(); - bulkDelete.find({ tenantID, id: { $in: deleteIDs } }).remove(); + bulkDelete.find({ tenantID, id: { $in: deleteIDs } }).delete(); await bulkDelete.execute(); insertBatch = []; @@ -245,7 +245,7 @@ async function moveDocuments({ } if (deleteIDs.length > 0) { const bulkDelete = source.initializeUnorderedBulkOp(); - bulkDelete.find({ tenantID, id: { $in: deleteIDs } }).remove(); + bulkDelete.find({ tenantID, id: { $in: deleteIDs } }).delete(); await bulkDelete.execute(); } From 267dd6bb25ee4c4b0081ace371ff2bba44849e5f Mon Sep 17 00:00:00 2001 From: nick-funk Date: Sun, 6 Oct 2024 16:03:36 -0600 Subject: [PATCH 07/22] resolve types for `signingSecret` logic --- .../settings/signingSecret/signingSecret.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/server/src/core/server/models/settings/signingSecret/signingSecret.ts b/server/src/core/server/models/settings/signingSecret/signingSecret.ts index 9e7999eab7..ea3472a40d 100644 --- a/server/src/core/server/models/settings/signingSecret/signingSecret.ts +++ b/server/src/core/server/models/settings/signingSecret/signingSecret.ts @@ -1,11 +1,5 @@ import { get } from "lodash"; -import { - Collection, - Document, - FindOneAndUpdateOptions, - UpdateFilter as UpdateQuery, - WithId, -} from "mongodb"; +import { Collection, Document, FindOneAndUpdateOptions, WithId } from "mongodb"; import logger from "coral-server/logger"; import { FilterQuery } from "coral-server/models/helpers"; @@ -122,7 +116,7 @@ async function pushNewSigningSecret({ const secret = generateSigningSecret(prefix, now); // Generate the update for the operation. - let update: UpdateQuery; + let update: object = {}; if (id) { update = { $push: { @@ -230,7 +224,7 @@ async function deprecateOldSigningSecrets( ); // Construct the update operation for rotating the secret. - let update: UpdateQuery; + let update: object = {}; if (id) { update = { $set: { @@ -278,16 +272,16 @@ export async function rotateSigningSecret( options: RotateSigningSecretOptions ) { // Push the new secret into the resource and return it. - let doc = await pushNewSigningSecret(options); - if (!doc) { + const pushResult = await pushNewSigningSecret(options); + if (!pushResult) { return null; } // Deprecate any old secrets on the document. - doc = await deprecateOldSigningSecrets(options, doc); - if (!doc) { + const deprecateResult = await deprecateOldSigningSecrets(options, pushResult); + if (!deprecateResult) { return null; } - return doc; + return deprecateResult; } From cbbb564b33f28c44341c8fbe2236aa94e87a7c6d Mon Sep 17 00:00:00 2001 From: nick-funk Date: Sun, 6 Oct 2024 16:06:47 -0600 Subject: [PATCH 08/22] update tenant cache types --- server/src/core/server/services/tenant/cache/cache.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/server/src/core/server/services/tenant/cache/cache.ts b/server/src/core/server/services/tenant/cache/cache.ts index 6f4e9af375..57a61b5343 100644 --- a/server/src/core/server/services/tenant/cache/cache.ts +++ b/server/src/core/server/services/tenant/cache/cache.ts @@ -14,6 +14,7 @@ import { Tenant, } from "coral-server/models/tenant"; +import { WithId } from "mongodb"; import { parse, stringify } from "./json"; const TENANT_CACHE_CHANNEL_VERSION = 1; @@ -114,7 +115,9 @@ export default class TenantCache { tenants .filter((t) => t !== null) - .forEach((t: Readonly) => this.tenantCountCache.add(t.id)); + .forEach((t: WithId>) => + this.tenantCountCache.add(t.id) + ); return tenants; }, @@ -134,7 +137,9 @@ export default class TenantCache { tenants .filter((t) => t !== null) - .forEach((t: Readonly) => this.tenantCountCache.add(t.id)); + .forEach((t: WithId>) => + this.tenantCountCache.add(t.id) + ); return tenants; }, From 222e71d3f01258dc13b6f9334dbc9cb36bee7595 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Sun, 6 Oct 2024 16:14:46 -0600 Subject: [PATCH 09/22] resolve types for metrics - fix date parsing - handle TS->JS for-loop type safety loss --- .../src/core/server/models/comment/metrics.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/server/src/core/server/models/comment/metrics.ts b/server/src/core/server/models/comment/metrics.ts index b4ca68bfde..44ee6f709e 100644 --- a/server/src/core/server/models/comment/metrics.ts +++ b/server/src/core/server/models/comment/metrics.ts @@ -58,8 +58,10 @@ export async function retrieveTodayCommentMetrics( timezone: string, now: Date ) { - const start = DateTime.fromJSDate(now).setZone(timezone).startOf("day"); - const end = DateTime.fromJSDate(now); + const start = new Date( + DateTime.fromJSDate(now).setZone(timezone).startOf("day").toISO() + ); + const end = new Date(DateTime.fromJSDate(now).toISO()); const allCommentsInRange = mongo.comments().find({ tenantID, @@ -116,10 +118,12 @@ export async function retrieveTodayCommentMetrics( continue; } + const mod = moderator; + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const isSiteMod = isSiteModerator(moderator); - if (isSiteMod && !moderator.moderationScopes.siteIDs?.includes(siteID)) { - const count = moderatorComments.get(moderator.id)?.size ?? 0; + if (isSiteMod && !mod.moderationScopes?.siteIDs?.includes(siteID)) { + const count = moderatorComments.get(mod.id)?.size ?? 0; siteModsNotResponsibleForSiteCommentCount += count; } } @@ -180,10 +184,12 @@ export async function retrieveAllTimeStaffCommentMetrics( continue; } + const mod = moderator; + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const isSiteMod = isSiteModerator(moderator); - if (isSiteMod && !moderator.moderationScopes.siteIDs?.includes(siteID)) { - const count = moderatorComments.get(moderator.id)?.size ?? 0; + if (isSiteMod && mod.moderationScopes?.siteIDs?.includes(siteID)) { + const count = moderatorComments.get(mod.id)?.size ?? 0; siteModsNotResponsibleForSiteCommentCount += count; } } From 33c914af90e99b00516949fa9025a32c923aab2c Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 09:28:08 -0600 Subject: [PATCH 10/22] fix `seenComments` types --- server/src/core/server/models/seenComments/seenComments.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/core/server/models/seenComments/seenComments.ts b/server/src/core/server/models/seenComments/seenComments.ts index 3b94f5536e..cc4d8f03f6 100644 --- a/server/src/core/server/models/seenComments/seenComments.ts +++ b/server/src/core/server/models/seenComments/seenComments.ts @@ -6,6 +6,7 @@ import { FindSeenCommentsInput } from "coral-server/graph/loaders/SeenComments"; import SeenCommentsCollection from "coral-server/graph/seenCommentsCollection"; import { dotize } from "coral-server/utils/dotize"; +import { AnyBulkWriteOperation } from "mongodb"; import { TenantResource } from "../tenant"; /** @@ -138,7 +139,7 @@ export async function markSeenCommentsBulk( seenComments: SeenCommentsCollection, now: Date ) { - const operations: object[] = []; + const operations: Array>> = []; const keys = seenComments.keys(); for (const { userID, storyID } of keys) { From 6e635a9beff3585099ef398106c09eb0a4ac693b Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 09:32:26 -0600 Subject: [PATCH 11/22] update types for site batch update in migration --- .../migrate/migrations/1579189174931_create_sites.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts b/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts index f9ceeb913b..2c71d230b7 100644 --- a/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts +++ b/server/src/core/server/services/migrate/migrations/1579189174931_create_sites.ts @@ -191,10 +191,12 @@ export default class extends Migration { // Push the update and process it if we need to. await batch.add( - // Find the story by ID. { id: doc._id }, // Dotize set the action counts on the story. - { $set: dotize(encodedActionCounts) } + { + filter: { id: doc._id }, + update: { $set: dotize(encodedActionCounts) }, + } ); } From a6a8f3811ce0af0a576f9764c86d7f4d08f6e943 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 09:38:46 -0600 Subject: [PATCH 12/22] create section and connection filter types for comment actions --- .../server/graph/loaders/CommentActions.ts | 9 ++++-- .../src/core/server/graph/loaders/helpers.ts | 32 ++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/server/src/core/server/graph/loaders/CommentActions.ts b/server/src/core/server/graph/loaders/CommentActions.ts index 1b94d9e6bf..223fadd6e3 100644 --- a/server/src/core/server/graph/loaders/CommentActions.ts +++ b/server/src/core/server/graph/loaders/CommentActions.ts @@ -14,7 +14,10 @@ import { GQLSectionFilter, } from "../schema/__generated__/types"; -import { requiredPropertyFilter, sectionFilter } from "./helpers"; +import { + commentActionRequiredPropertyFilter, + commentActionSectionFilter, +} from "./helpers"; interface FilteredConnectionInput { first?: number; @@ -58,11 +61,11 @@ export default (ctx: Context) => ({ after, filter: { ...filter, - ...sectionFilter(ctx.tenant, section), + ...commentActionSectionFilter(ctx.tenant, section), // If these properties are not provided or are null, remove them from // the filter because they do not exist in a nullable state on the // database model. - ...requiredPropertyFilter({ storyID, siteID }), + ...commentActionRequiredPropertyFilter({ storyID, siteID }), }, orderBy: defaultTo(orderBy, GQLCOMMENT_SORT.CREATED_AT_DESC), }); diff --git a/server/src/core/server/graph/loaders/helpers.ts b/server/src/core/server/graph/loaders/helpers.ts index b83fc25095..e8cfb5c0e1 100644 --- a/server/src/core/server/graph/loaders/helpers.ts +++ b/server/src/core/server/graph/loaders/helpers.ts @@ -4,7 +4,12 @@ import { SectionFilter } from "coral-common/common/lib/section"; import { CommentConnectionInput } from "coral-server/models/comment"; import { hasFeatureFlag, Tenant } from "coral-server/models/tenant"; -import { GQLFEATURE_FLAG } from "../schema/__generated__/types"; +import { CommentAction } from "coral-server/models/action/comment"; +import { OrderedConnectionInput } from "coral-server/models/helpers"; +import { + GQLCOMMENT_SORT, + GQLFEATURE_FLAG, +} from "../schema/__generated__/types"; /** * requiredPropertyFilter will remove those properties that are nil from the @@ -32,3 +37,28 @@ export const sectionFilter = ( return {}; }; + +export type CommentActionConnectionInput = OrderedConnectionInput< + CommentAction, + GQLCOMMENT_SORT +>; + +export const commentActionRequiredPropertyFilter = ( + props: CommentActionConnectionInput["filter"] +): CommentActionConnectionInput["filter"] => omitBy(props, isNil); + +export const commentActionSectionFilter = ( + tenant: Pick, + section?: SectionFilter +): CommentActionConnectionInput["filter"] => { + // Don't filter by section if the feature flag is disabled. + if (!hasFeatureFlag(tenant, GQLFEATURE_FLAG.SECTIONS)) { + return {}; + } + + if (section) { + return { section: section.name || undefined }; + } + + return {}; +}; From 169eab489a9f0f17a736a9b305b4f8e6dedba652 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 09:43:00 -0600 Subject: [PATCH 13/22] fix merged moderation queue filter types --- .../graph/resolvers/ModerationQueues.ts | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/server/src/core/server/graph/resolvers/ModerationQueues.ts b/server/src/core/server/graph/resolvers/ModerationQueues.ts index b3af7e078b..57446f8e4a 100644 --- a/server/src/core/server/graph/resolvers/ModerationQueues.ts +++ b/server/src/core/server/graph/resolvers/ModerationQueues.ts @@ -32,17 +32,29 @@ const mergeModerationInputFilters = filter: FilterQuery, selector: keyof CommentModerationCountsPerQueue ) => - (input: ModerationQueuesInput): ModerationQueueInput => ({ - selector, - connection: { - ...input.connection, - filter: { - ...input.connection.filter, - ...filter, + (input: ModerationQueuesInput): ModerationQueueInput => { + // this is merging multiple fitler types together + // Mongo types really don't like this, but it has worked + // for years, because when TS compiles to JS, it has no + // concept of "data types", it just knows filters. + // + // If we merge this down into an object, it's the same as + // it was prior to upgrading our TS Mongo types to be more + // picky. + const mergedFilter: object = { + ...input.connection.filter, + ...filter, + }; + + return { + selector, + connection: { + ...input.connection, + filter: mergedFilter, }, - }, - count: input.counts ? input.counts[selector] : null, - }); + count: input.counts ? input.counts[selector] : null, + }; + }; /** * siteModerationInputResolver can be used to retrieve the moderationQueue for From de2bf8f1a0700c81f453f4ab5f586d569958fa69 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 10:15:30 -0600 Subject: [PATCH 14/22] replace collection type on `updateRelatedCommentCounts` --- server/src/core/server/models/comment/counts/counts.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/core/server/models/comment/counts/counts.ts b/server/src/core/server/models/comment/counts/counts.ts index 2c013e9df4..5a38598af0 100644 --- a/server/src/core/server/models/comment/counts/counts.ts +++ b/server/src/core/server/models/comment/counts/counts.ts @@ -12,6 +12,7 @@ import { GQLCommentTagCounts, } from "coral-server/graph/schema/__generated__/types"; +import { Story } from "coral-server/models/story"; import { createEmptyCommentModerationQueueCounts, createEmptyCommentStatusCounts, @@ -223,7 +224,7 @@ interface RelatedCommentCountsDocument extends Document { } export async function updateRelatedCommentCounts( - collection: Collection, + collection: Collection>, tenantID: string, id: string, commentCounts: DeepPartial From fb56ddfd2a9a807337dec7f34a2f6e5a13ecb45e Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 10:19:45 -0600 Subject: [PATCH 15/22] fix comment count generics updates --- .../src/core/server/models/comment/counts/counts.ts | 3 +-- server/src/core/server/models/site/index.ts | 12 ++++++++++-- server/src/core/server/models/story/story.ts | 12 ++++++++++-- server/src/core/server/models/user/user.ts | 12 ++++++++++-- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/server/src/core/server/models/comment/counts/counts.ts b/server/src/core/server/models/comment/counts/counts.ts index 5a38598af0..7748d8730a 100644 --- a/server/src/core/server/models/comment/counts/counts.ts +++ b/server/src/core/server/models/comment/counts/counts.ts @@ -12,7 +12,6 @@ import { GQLCommentTagCounts, } from "coral-server/graph/schema/__generated__/types"; -import { Story } from "coral-server/models/story"; import { createEmptyCommentModerationQueueCounts, createEmptyCommentStatusCounts, @@ -224,7 +223,7 @@ interface RelatedCommentCountsDocument extends Document { } export async function updateRelatedCommentCounts( - collection: Collection>, + collection: Collection, tenantID: string, id: string, commentCounts: DeepPartial diff --git a/server/src/core/server/models/site/index.ts b/server/src/core/server/models/site/index.ts index 0a8e0417e3..6c9b4cc740 100644 --- a/server/src/core/server/models/site/index.ts +++ b/server/src/core/server/models/site/index.ts @@ -1,5 +1,5 @@ import { identity, isNumber } from "lodash"; -import { MongoError } from "mongodb"; +import { Collection, MongoError } from "mongodb"; import { v4 as uuid } from "uuid"; import { FirstDeepPartial } from "coral-common/common/lib/types"; @@ -186,4 +186,12 @@ export const updateSiteCounts = ( tenantID: string, id: string, commentCounts: FirstDeepPartial -) => updateRelatedCommentCounts(mongo.sites(), tenantID, id, commentCounts); +) => + updateRelatedCommentCounts( + // the generics on this won't let us extend to + // all Coral types + mongo.sites() as unknown as Collection, + tenantID, + id, + commentCounts + ); diff --git a/server/src/core/server/models/story/story.ts b/server/src/core/server/models/story/story.ts index 4800e9d34d..bc19966286 100644 --- a/server/src/core/server/models/story/story.ts +++ b/server/src/core/server/models/story/story.ts @@ -1,4 +1,4 @@ -import { MongoError } from "mongodb"; +import { Collection, MongoError } from "mongodb"; import { v4 as uuid } from "uuid"; import { DeepPartial, FirstDeepPartial } from "coral-common/common/lib/types"; @@ -674,7 +674,15 @@ export const updateStoryCounts = ( tenantID: string, id: string, commentCounts: FirstDeepPartial -) => updateRelatedCommentCounts(mongo.stories(), tenantID, id, commentCounts); +) => + updateRelatedCommentCounts( + // the generics on this won't let us extend to + // all Coral types + mongo.stories() as unknown as Collection, + tenantID, + id, + commentCounts + ); export async function addStoryExpert( mongo: MongoContext, diff --git a/server/src/core/server/models/user/user.ts b/server/src/core/server/models/user/user.ts index 4bcea4d90d..2e177c80a1 100644 --- a/server/src/core/server/models/user/user.ts +++ b/server/src/core/server/models/user/user.ts @@ -1,6 +1,6 @@ import bcrypt from "bcryptjs"; import { DateTime, DurationObject } from "luxon"; -import { MongoError } from "mongodb"; +import { Collection, MongoError } from "mongodb"; import { v4 as uuid } from "uuid"; import { DeepPartial, Sub } from "coral-common/common/lib/types"; @@ -3602,7 +3602,15 @@ export const updateUserCommentCounts = ( tenantID: string, id: string, commentCounts: DeepPartial -) => updateRelatedCommentCounts(mongo.users(), tenantID, id, commentCounts); +) => + updateRelatedCommentCounts( + // the generics on this won't let us extend to + // all Coral types + mongo.users() as unknown as Collection, + tenantID, + id, + commentCounts + ); export const updateLastFeaturedDate = async ( mongo: MongoContext, From e2d2dfab9fac4549701a84c9c066cab10aac1b0f Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 11:13:04 -0600 Subject: [PATCH 16/22] make update count type happy for story update --- .../core/server/stacks/helpers/updateAllCommentCounts.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts b/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts index f87124d350..37550df278 100644 --- a/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts +++ b/server/src/core/server/stacks/helpers/updateAllCommentCounts.ts @@ -14,7 +14,7 @@ import { import { PUBLISHED_STATUSES } from "coral-server/models/comment/constants"; import { CommentTag } from "coral-server/models/comment/tag"; import { updateSiteCounts } from "coral-server/models/site"; -import { updateStoryCounts } from "coral-server/models/story"; +import { Story, updateStoryCounts } from "coral-server/models/story"; import { hasFeatureFlag, Tenant } from "coral-server/models/tenant"; import { updateUserCommentCounts } from "coral-server/models/user"; import { @@ -171,12 +171,12 @@ export default async function updateAllCommentCounts( if (options.updateStory) { // Update the story, site, and user comment counts. - const updatedStory = await updateStoryCounts(mongo, tenant.id, storyID, { + const updatedStory = (await updateStoryCounts(mongo, tenant.id, storyID, { action, status, moderationQueue, tags, - }); + })) as Readonly | null; // only update Redis cache for comment counts if jsonp_response_cache set to true if (config.get("jsonp_response_cache")) { From 0dd78416c5f3f1256af44b5c966d63d6b93589ca Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 11:36:33 -0600 Subject: [PATCH 17/22] add `SITE_NOT_FOUND` error code to common lib --- common/lib/errors.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/lib/errors.ts b/common/lib/errors.ts index 3eedff8c70..2be3521e0d 100644 --- a/common/lib/errors.ts +++ b/common/lib/errors.ts @@ -472,5 +472,10 @@ export enum ERROR_CODES { * priming of comments for the story in the data caches `commentCache` returns an undefined * result. This usually means something went very wrong loading from Redis or Mongo. */ - UNABLE_TO_PRIME_CACHED_COMMENTS_FOR_STORY = "UNABLE_TO_PRIME_CACHED_COMMENTS_FOR_STORY" + UNABLE_TO_PRIME_CACHED_COMMENTS_FOR_STORY = "UNABLE_TO_PRIME_CACHED_COMMENTS_FOR_STORY", + /** + * SITE_NOT_FOUND is returned when the site being looked up via an ID does not + * exist in the database or when a siteID has been deleted from a document. + */ + SITE_NOT_FOUND = "SITE_NOT_FOUND", } From 6010f68ed52b3fb3a14e24ba9243347a6e0903b0 Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 11:40:06 -0600 Subject: [PATCH 18/22] force story types on merge mutator --- server/src/core/server/services/stories/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/src/core/server/services/stories/index.ts b/server/src/core/server/services/stories/index.ts index 822a10f383..0b674bce43 100644 --- a/server/src/core/server/services/stories/index.ts +++ b/server/src/core/server/services/stories/index.ts @@ -528,7 +528,10 @@ export async function merge( log.debug({ deletedStories: deletedCount }, "deleted source stories"); // Return the story that had the other stories merged into. - return destinationStory; + // casting to type as we know this is what it should be, we + // just can't get the generics right on the update calls, so + // we have to assume type here. + return destinationStory as unknown as Readonly; } export async function addExpert( From 6c66630487d4dce1029017fcf44f2b5e3d07dfcf Mon Sep 17 00:00:00 2001 From: nick-funk Date: Mon, 7 Oct 2024 14:21:07 -0600 Subject: [PATCH 19/22] patch text encode/decode global for affected tests --- server/src/core/server/app/middleware/csp.spec.ts | 3 +++ .../middleware/passport/strategies/verifiers/jwt.spec.ts | 3 +++ .../middleware/passport/strategies/verifiers/sso.spec.ts | 3 +++ .../server/services/comments/moderation/moderate.spec.ts | 3 +++ .../services/comments/pipeline/phases/storyClosed.spec.ts | 3 +++ .../server/services/comments/pipeline/pipeline.spec.ts | 3 +++ server/src/core/server/services/oidc/oidc.spec.ts | 3 +++ .../core/server/services/stories/scraper/scraper.spec.ts | 3 +++ server/src/core/server/services/tenant/tenant.spec.ts | 3 +++ .../src/core/server/services/users/auth/confirm.spec.ts | 3 +++ server/src/core/server/services/users/auth/reset.spec.ts | 3 +++ .../core/server/services/users/user.updateRole.spec.ts | 3 +++ server/src/core/server/services/users/users.spec.ts | 3 +++ server/src/core/server/test/textEncoder.ts | 8 ++++++++ 14 files changed, 47 insertions(+) create mode 100644 server/src/core/server/test/textEncoder.ts diff --git a/server/src/core/server/app/middleware/csp.spec.ts b/server/src/core/server/app/middleware/csp.spec.ts index 352cf2166c..a8cc7ba0cd 100644 --- a/server/src/core/server/app/middleware/csp.spec.ts +++ b/server/src/core/server/app/middleware/csp.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { generateFrameOptions } from "coral-server/app/middleware/csp"; import { Request } from "coral-server/types/express"; diff --git a/server/src/core/server/app/middleware/passport/strategies/verifiers/jwt.spec.ts b/server/src/core/server/app/middleware/passport/strategies/verifiers/jwt.spec.ts index 8936f2d599..0d02c8d5c9 100644 --- a/server/src/core/server/app/middleware/passport/strategies/verifiers/jwt.spec.ts +++ b/server/src/core/server/app/middleware/passport/strategies/verifiers/jwt.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import jwt from "jsonwebtoken"; import { DateTime } from "luxon"; diff --git a/server/src/core/server/app/middleware/passport/strategies/verifiers/sso.spec.ts b/server/src/core/server/app/middleware/passport/strategies/verifiers/sso.spec.ts index dfb5b45eb5..fb5c19c1a7 100644 --- a/server/src/core/server/app/middleware/passport/strategies/verifiers/sso.spec.ts +++ b/server/src/core/server/app/middleware/passport/strategies/verifiers/sso.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { SSOTokenSchema, SSOUserProfileSchema, diff --git a/server/src/core/server/services/comments/moderation/moderate.spec.ts b/server/src/core/server/services/comments/moderation/moderate.spec.ts index e9bc849995..7dc6cc4a9a 100644 --- a/server/src/core/server/services/comments/moderation/moderate.spec.ts +++ b/server/src/core/server/services/comments/moderation/moderate.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { Config } from "coral-server/config"; import { createCommentFixture, diff --git a/server/src/core/server/services/comments/pipeline/phases/storyClosed.spec.ts b/server/src/core/server/services/comments/pipeline/phases/storyClosed.spec.ts index ba1b13f347..e8fb39f38b 100644 --- a/server/src/core/server/services/comments/pipeline/phases/storyClosed.spec.ts +++ b/server/src/core/server/services/comments/pipeline/phases/storyClosed.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { DateTime } from "luxon"; import { storyClosed } from "coral-server/services/comments/pipeline/phases/storyClosed"; diff --git a/server/src/core/server/services/comments/pipeline/pipeline.spec.ts b/server/src/core/server/services/comments/pipeline/pipeline.spec.ts index fba3d9068a..88ddd927fc 100644 --- a/server/src/core/server/services/comments/pipeline/pipeline.spec.ts +++ b/server/src/core/server/services/comments/pipeline/pipeline.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { ACTION_TYPE } from "coral-server/models/action/comment"; import { diff --git a/server/src/core/server/services/oidc/oidc.spec.ts b/server/src/core/server/services/oidc/oidc.spec.ts index 0cb62e56c4..07d2ae4c23 100644 --- a/server/src/core/server/services/oidc/oidc.spec.ts +++ b/server/src/core/server/services/oidc/oidc.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { validateSchema } from "coral-server/helpers"; import { OIDCIDTokenSchema } from "./oidc"; diff --git a/server/src/core/server/services/stories/scraper/scraper.spec.ts b/server/src/core/server/services/stories/scraper/scraper.spec.ts index 0130b323a0..b7fc0b5b71 100644 --- a/server/src/core/server/services/stories/scraper/scraper.spec.ts +++ b/server/src/core/server/services/stories/scraper/scraper.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { scraper } from "./scraper"; describe("Scraper", () => { diff --git a/server/src/core/server/services/tenant/tenant.spec.ts b/server/src/core/server/services/tenant/tenant.spec.ts index 0596f3d85f..a69d77b389 100644 --- a/server/src/core/server/services/tenant/tenant.spec.ts +++ b/server/src/core/server/services/tenant/tenant.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { createEmailDomain } from "./tenant"; jest.mock("coral-server/models/user"); jest.mock("coral-server/models/site"); diff --git a/server/src/core/server/services/users/auth/confirm.spec.ts b/server/src/core/server/services/users/auth/confirm.spec.ts index e8ef86d4e6..111cb7f565 100644 --- a/server/src/core/server/services/users/auth/confirm.spec.ts +++ b/server/src/core/server/services/users/auth/confirm.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { v1 as uuid } from "uuid"; import { ConfirmToken, isConfirmToken } from "./confirm"; diff --git a/server/src/core/server/services/users/auth/reset.spec.ts b/server/src/core/server/services/users/auth/reset.spec.ts index 5ef781778e..d68e426ae7 100644 --- a/server/src/core/server/services/users/auth/reset.spec.ts +++ b/server/src/core/server/services/users/auth/reset.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { v1 as uuid } from "uuid"; import { isResetToken, ResetToken } from "./reset"; diff --git a/server/src/core/server/services/users/user.updateRole.spec.ts b/server/src/core/server/services/users/user.updateRole.spec.ts index 0bb52398cc..2da2f5e62e 100644 --- a/server/src/core/server/services/users/user.updateRole.spec.ts +++ b/server/src/core/server/services/users/user.updateRole.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { MongoContext } from "coral-server/data/context"; import { UserForbiddenError } from "coral-server/errors"; import { GQLUSER_ROLE } from "coral-server/graph/schema/__generated__/types"; diff --git a/server/src/core/server/services/users/users.spec.ts b/server/src/core/server/services/users/users.spec.ts index 435df2455d..baab27180e 100644 --- a/server/src/core/server/services/users/users.spec.ts +++ b/server/src/core/server/services/users/users.spec.ts @@ -1,3 +1,6 @@ +import { patchTextUtil } from "coral-server/test/textEncoder"; +patchTextUtil(); + import { pureMerge } from "coral-common/common/lib/utils"; jest.mock("coral-server/models/user"); diff --git a/server/src/core/server/test/textEncoder.ts b/server/src/core/server/test/textEncoder.ts new file mode 100644 index 0000000000..230ddb42c0 --- /dev/null +++ b/server/src/core/server/test/textEncoder.ts @@ -0,0 +1,8 @@ +// eslint-disable-next-line @typescript-eslint/tslint/config +import { TextEncoder, TextDecoder } from "util"; + +export const patchTextUtil = () => { + const glob = global as any; + glob.TextEncoder = TextEncoder; + glob.TextDecoder = TextDecoder; +}; From 370106b7338574d7f78b0eeef64af031350daf0d Mon Sep 17 00:00:00 2001 From: nick-funk Date: Tue, 8 Oct 2024 10:06:40 -0600 Subject: [PATCH 20/22] remove todo as it is resolved --- server/src/core/server/models/helpers/query.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/core/server/models/helpers/query.ts b/server/src/core/server/models/helpers/query.ts index 7c5824c5be..1191d0206b 100644 --- a/server/src/core/server/models/helpers/query.ts +++ b/server/src/core/server/models/helpers/query.ts @@ -71,7 +71,6 @@ export default class Query { * @param sort the sorting option for the documents */ public orderBy(sort: { [key: string]: SortDirection }): Query { - // todo: merge sort's together this.sort = { ...this.sort, ...sort }; return this; } From 4ad39f500b03835b49922b7f71cd1f45051a8a3b Mon Sep 17 00:00:00 2001 From: nick-funk Date: Tue, 8 Oct 2024 10:08:32 -0600 Subject: [PATCH 21/22] use `countDocuments` over `count` in `countTenantSites` --- server/src/core/server/models/site/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/core/server/models/site/index.ts b/server/src/core/server/models/site/index.ts index 6c9b4cc740..6fc220249d 100644 --- a/server/src/core/server/models/site/index.ts +++ b/server/src/core/server/models/site/index.ts @@ -132,7 +132,7 @@ async function retrieveConnection( } export async function countTenantSites(mongo: MongoContext, tenantID: string) { - return mongo.sites().find({ tenantID }).count(); + return mongo.sites().countDocuments({ tenantID }); } export async function retrieveSiteConnection( From 89c72bc0b86fe8b2369ea3c8888e0a45166316c1 Mon Sep 17 00:00:00 2001 From: Tessa Thornton Date: Thu, 10 Oct 2024 09:07:09 -0400 Subject: [PATCH 22/22] update verison no --- client/package.json | 2 +- common/package.json | 2 +- config/package.json | 2 +- server/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/package.json b/client/package.json index 2423056b67..4cd4f8e8c5 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@coralproject/talk", - "version": "9.4.1", + "version": "9.5.0", "author": "The Coral Project", "homepage": "https://coralproject.net/", "sideEffects": [ diff --git a/common/package.json b/common/package.json index 9ee911401d..0eba08b2c0 100644 --- a/common/package.json +++ b/common/package.json @@ -1,6 +1,6 @@ { "name": "common", - "version": "9.4.1", + "version": "9.5.0", "description": "", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/config/package.json b/config/package.json index 39b41e50b2..98df94632b 100644 --- a/config/package.json +++ b/config/package.json @@ -1,6 +1,6 @@ { "name": "common", - "version": "9.4.1", + "version": "9.5.0", "description": "", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/server/package.json b/server/package.json index 9f186c19c4..24ae39ab6b 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "@coralproject/talk", - "version": "9.4.1", + "version": "9.5.0", "author": "The Coral Project", "homepage": "https://coralproject.net/", "sideEffects": [