diff --git a/framework/eslint-config/package.json b/framework/eslint-config/package.json index 88129b77c..ca3dd682e 100644 --- a/framework/eslint-config/package.json +++ b/framework/eslint-config/package.json @@ -5,8 +5,8 @@ "main": "react.yaml", "dependencies": { "@stylistic/eslint-plugin": "^2.6.2", - "@typescript-eslint/eslint-plugin": "^8.0.1", - "@typescript-eslint/parser": "^8.0.1", + "@typescript-eslint/eslint-plugin": "^8.1.0", + "@typescript-eslint/parser": "^8.1.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-github": "^5.0.1", "eslint-plugin-import": "2.29.1", diff --git a/packages/center/index.ts b/packages/center/index.ts index 14d7c8f71..16d0974b0 100644 --- a/packages/center/index.ts +++ b/packages/center/index.ts @@ -86,7 +86,7 @@ class DataReportHandler extends Handler { this.ctx.emit('center/report', this, installId, old, payload); // TODO deliver messages this.response.body = { code: 0 }; - if (old.notification) this.response.body.notification = old?.notification; + if (old?.notification) this.response.body.notification = old?.notification; } } diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 389ca67ed..2ed2c75ab 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -12,11 +12,11 @@ }, "preferUnplugged": true, "dependencies": { - "@aws-sdk/client-s3": "3.627.0", - "@aws-sdk/lib-storage": "3.627.0", - "@aws-sdk/s3-presigned-post": "3.627.0", - "@aws-sdk/s3-request-presigner": "3.627.0", - "@graphql-tools/schema": "^10.0.4", + "@aws-sdk/client-s3": "3.631.0", + "@aws-sdk/lib-storage": "3.631.0", + "@aws-sdk/s3-presigned-post": "3.631.0", + "@aws-sdk/s3-request-presigner": "3.631.0", + "@graphql-tools/schema": "^10.0.5", "@hydrooj/framework": "workspace:^", "@hydrooj/utils": "workspace:^", "@simplewebauthn/server": "9.0.3", diff --git a/packages/hydrooj/src/model/document.ts b/packages/hydrooj/src/model/document.ts index 75210398f..f41bb83dc 100644 --- a/packages/hydrooj/src/model/document.ts +++ b/packages/hydrooj/src/model/document.ts @@ -302,12 +302,18 @@ export function getMultiStatusWithoutDomain( } export async function setStatus( - domainId: string, docType: K, docId: DocStatusType[K]['docId'], uid: number, args: UpdateFilter['$set'], + domainId: string, docType: K, docId: DocStatusType[K]['docId'], uid: number, + args: UpdateFilter['$set'], returnDocument: 'before' | 'after' = 'after', ): Promise { const res = await collStatus.findOneAndUpdate( { domainId, docType, docId, uid }, - { $set: args }, - { upsert: true, returnDocument: 'after' }, + { $set: args, $inc: { counter: 1 } }, + { + upsert: true, + returnDocument, + // if fetching document before update we want to ensure data was read from primary + ...(returnDocument === 'before' ? { readConcern: { level: 'majority' }, readPreference: 'primary' } : {}), + }, ); return res.value; } @@ -321,41 +327,32 @@ export async function setMultiStatus( ); } +export async function setStatusIfNotCondition( + domainId: string, docType: T, docId: DocStatusType[T]['docId'], uid: number, + filter: Filter, args: Partial = {}, + returnDocument: 'before' | 'after' = 'after', +): Promise { + try { + const res = await collStatus.findOneAndUpdate( + { domainId, docType, docId, uid, $nor: [filter] }, + { $set: args }, + { upsert: true, returnDocument }, + ); + return res.value; + } catch (e) { + return false; + } +} + export async function setIfNotStatus( domainId: string, docType: T, docId: DocStatusType[T]['docId'], uid: number, key: K, value: DocStatusType[T][K], ifNot: DocStatusType[T][K], args: Partial, + returnDocument: 'before' | 'after' = 'after', ): Promise { - const current: Partial = await collStatus.findOne({ domainId, docType, docId, uid }) || {}; - if (typeof key === 'string' && key.includes('.')) { - const acc = key.split('.'); - let c = current; - for (const i of acc) { - if (!(i in c)) break; - c = c[i]; - if (c === null || c === undefined) break; - } - if (c === ifNot) return null; - } else if (current[key] === ifNot) return null; - const res = await collStatus.findOneAndUpdate( - { domainId, docType, docId, uid }, - { $set: { [key]: value, ...args } }, - { upsert: true, returnDocument: 'after' }, + return await setStatusIfNotCondition( + domainId, docType, docId, uid, { [key]: ifNot } as any, + { [key]: value, ...args }, returnDocument, ); - return res.value; -} - -export async function setStatusIfNotCondition( - domainId: string, docType: T, docId: DocStatusType[T]['docId'], uid: number, - filter: Filter, args: Partial, -): Promise { - const match = await collStatus.findOne({ domainId, docType, docId, uid, ...filter }); - if (match) return null; - const res = await collStatus.findOneAndUpdate( - { domainId, docType, docId, uid }, - { $set: args }, - { upsert: true, returnDocument: 'after' }, - ); - return res.value; } export async function cappedIncStatus( diff --git a/packages/hydrooj/src/model/solution.ts b/packages/hydrooj/src/model/solution.ts index 9d666a76a..53f1b04e8 100644 --- a/packages/hydrooj/src/model/solution.ts +++ b/packages/hydrooj/src/model/solution.ts @@ -70,12 +70,18 @@ class SolutionModel { } static async vote(domainId: string, psid: ObjectId, uid: number, value: number) { - let pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid); - await document.setStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid, { vote: value }); - if (pssdoc) value += -pssdoc.vote; - const psdoc = await document.inc(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'vote', value); - pssdoc = await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid); - return [psdoc, pssdoc]; + const before = await document.setStatus( + domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid, + { vote: value }, 'before', + ); + let inc = value; + if (before?.vote) inc -= before.vote; + return [ + inc + ? await document.inc(domainId, document.TYPE_PROBLEM_SOLUTION, psid, 'vote', inc) + : await document.get(domainId, document.TYPE_PROBLEM_SOLUTION, psid), + await document.getStatus(domainId, document.TYPE_PROBLEM_SOLUTION, psid, uid), + ]; } static async getListStatus(domainId: string, psids: ObjectId[], uid: number) { diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 0505b781f..70ef19a76 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -25,8 +25,8 @@ "@fontsource/source-code-pro": "^5.0.18", "@fontsource/ubuntu-mono": "^5.0.20", "@hydrooj/utils": "workspace:^", - "@sentry/browser": "^8.25.0", - "@sentry/webpack-plugin": "^2.22.0", + "@sentry/browser": "^8.26.0", + "@sentry/webpack-plugin": "^2.22.2", "@simplewebauthn/browser": "9.0.1", "@svgr/webpack": "^8.1.0", "@types/gulp-if": "^0.0.34", @@ -76,7 +76,7 @@ "jquery.easing": "^1.4.1", "jquery.transit": "^0.9.12", "matchmedia-polyfill": "^0.3.2", - "md-editor-rt": "^4.18.0", + "md-editor-rt": "^4.18.1", "mini-css-extract-plugin": "^2.9.0", "moment": "^2.30.1", "monaco-editor": "0.50.0", @@ -141,7 +141,7 @@ "lodash": "^4.17.21", "markdown-it": "^14.1.0", "markdown-it-anchor": "^9.0.1", - "markdown-it-attrs": "^4.1.6", + "markdown-it-attrs": "^4.2.0", "markdown-it-footnote": "^4.0.0", "markdown-it-imsize": "^2.0.1", "markdown-it-mark": "^4.0.0",