Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
a894ddd
[HUMAN App] fix: invalid sorting by `reward_amount` (#3201)
dnechay Mar 20, 2025
0a3f515
[Job Launcher] Abuse system integration (#3193)
flopez7 Mar 21, 2025
239a7a8
chore(deps-dev): bump @nestjs/schematics from 10.2.3 to 11.0.2 (#3142)
dependabot[bot] Mar 21, 2025
ab3415e
chore(deps): bump vitest from 1.6.1 to 3.0.9 (#3197)
dependabot[bot] Mar 21, 2025
18e1b00
remove comments (#3212)
portuu3 Mar 21, 2025
143d5d9
fix: remove external link from HCaptchaJobRequestForm (#3214)
portuu3 Mar 24, 2025
56ff5a5
[CVAT] Oracle updates (#3219)
zhiltsov-max Mar 24, 2025
8bc1fef
[HUMAN App] refactor: filter component logic (#3187)
mpblocky Mar 24, 2025
c9ae4e0
chore(deps): bump stripe from 17.6.0 to 17.7.0 (#3222)
dependabot[bot] Mar 25, 2025
cd97e8b
[CVAT] Oracle fixes (#3224)
zhiltsov-max Mar 25, 2025
5f09795
fix: jl docker env vars (#3227)
dnechay Mar 25, 2025
ff3614a
[Job Launcher Client] Allow adding biliing details without tax ID (#3…
flopez7 Mar 25, 2025
fdfd835
chore(deps-dev): bump @graphprotocol/graph-ts from 0.37.0 to 0.38.0 (…
dependabot[bot] Mar 25, 2025
5d4ccad
fix: reco compose pgp public key (#3228)
dnechay Mar 25, 2025
4312262
[Reputation Oracle] Refactor `Auth` module (#3205)
Dzeranov Mar 27, 2025
835daca
[HUMAN App] refactor: layout components (#3220)
mpblocky Mar 27, 2025
8c2a6f5
deps: bump vite (#3235)
dnechay Mar 27, 2025
d8fefd8
feat: support multiple event types in webhook status query (#3234)
flopez7 Mar 27, 2025
8195f04
fix: vite package resolutions (#3237)
dnechay Mar 28, 2025
511a1ff
[Reputation Oracle] fix: handle key not found kv store errors (#3238)
dnechay Mar 28, 2025
7173c26
[Reputation Oracle] Forbid login if user is in `inactive` status (#3240)
Dzeranov Mar 28, 2025
c5f2693
Extend task creation status checks (#3242)
zhiltsov-max Mar 28, 2025
7b3ad28
Optimize roi preparation and uploading (#3243)
zhiltsov-max Mar 28, 2025
4e27e03
[HUMAN App] fix: bg color; oracle discovery redirects (#3231)
mpblocky Mar 31, 2025
34ae83a
feat: add support for additional mainnet chain IDs (#3245)
flopez7 Mar 31, 2025
24060b2
[Job Launcher] [Client] Infinite spinner when create job fails (#3230)
KirillKirill Mar 31, 2025
3565c27
[Fortune Exchange Oracle] Abuse system (#3202)
flopez7 Apr 1, 2025
45f7576
chore(deps-dev): bump vite from 6.2.3 to 6.2.4 (#3247)
dependabot[bot] Apr 1, 2025
e8156b5
chore(deps): bump @mui/icons-material from 6.4.6 to 7.0.1 (#3248)
dependabot[bot] Apr 1, 2025
981cbd6
[Subgraph] Remove LegacyEscrow references and update entities (#3232)
flopez7 Apr 1, 2025
7c17a23
feat: add retry logic for crypto payment and top-up forms; enhance Wa…
flopez7 Apr 1, 2025
6953efe
[CVAT] Move annotation downloading after successful validation (#3253)
zhiltsov-max Apr 1, 2025
b5b172d
Fix invalid status check (#3257)
zhiltsov-max Apr 1, 2025
fe20481
Fix date check in cron job service (#3259)
flopez7 Apr 2, 2025
ef50fc6
feat: add support for Audino jobs (#3258)
dnechay Apr 2, 2025
9b99c7c
[Job Launcher] fix: add missing OracleType for audino (#3260)
dnechay Apr 2, 2025
99ab64e
add partial status as valid status for completion (#3263)
portuu3 Apr 4, 2025
b13faf3
[HUMAN App] fix: table header props ref warning (#3239)
mpblocky Apr 4, 2025
3c6ed95
[HUMAN App] fix: wallet connection control (#3266)
mpblocky Apr 7, 2025
5dc44af
chore: bump vite to address dep review (#3271)
dnechay Apr 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/apps/dashboard/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@human-protocol/sdk": "*",
"@mui/icons-material": "^6.4.6",
"@mui/icons-material": "^7.0.1",
"@mui/material": "^5.15.18",
"@mui/styled-engine-sc": "6.4.0",
"@mui/x-data-grid": "^7.23.2",
Expand Down Expand Up @@ -53,7 +53,7 @@
"sass": "^1.85.0",
"stylelint-prettier": "^5.0.0",
"typescript": "^5.6.3",
"vite": "^6.2.0",
"vite": "^6.2.4",
"vite-plugin-svgr": "^4.2.0"
}
}
2 changes: 1 addition & 1 deletion packages/apps/dashboard/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
"devDependencies": {
"@nestjs/cli": "^10.3.2",
"@nestjs/schematics": "^10.1.3",
"@nestjs/schematics": "^11.0.2",
"@nestjs/testing": "^10.4.6",
"@types/express": "^4.17.13",
"@types/jest": "29.5.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/apps/faucet/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"license": "MIT",
"dependencies": {
"@human-protocol/sdk": "*",
"@mui/icons-material": "^6.4.6",
"@mui/icons-material": "^7.0.1",
"@mui/material": "^5.16.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand All @@ -22,7 +22,7 @@
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-react": "^7.34.3",
"eslint-plugin-react-hooks": "^5.1.0",
"vite": "^6.2.0",
"vite": "^6.2.4",
"vite-plugin-node-polyfills": "^0.22.0"
},
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/apps/fortune/exchange-oracle/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.11",
"typescript": "^5.6.3",
"vite": "^6.2.0"
"vite": "^6.2.4"
},
"lint-staged": {
"*.{ts,tsx}": [
Expand Down
2 changes: 1 addition & 1 deletion packages/apps/fortune/exchange-oracle/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"devDependencies": {
"@golevelup/ts-jest": "^0.6.1",
"@nestjs/cli": "^10.3.2",
"@nestjs/schematics": "^10.1.3",
"@nestjs/schematics": "^11.0.2",
"@nestjs/testing": "^10.4.6",
"@types/express": "^4.17.13",
"@types/jest": "29.5.12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export enum ErrorAssignment {
export enum ErrorJob {
AlreadyExists = 'Job already exists',
InvalidAddress = 'Invalid address',
InvalidStatus = 'Invalid job status',
NotAssigned = 'User is not assigned to the job',
SolutionAlreadySubmitted = 'User has already submitted a solution',
JobCompleted = 'This job has already been completed',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export enum JobStatus {
ACTIVE = 'active',
PAUSED = 'paused',
COMPLETED = 'completed',
CANCELED = 'canceled',
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export enum EventType {
ESCROW_FAILED = 'escrow_failed',
SUBMISSION_REJECTED = 'submission_rejected',
SUBMISSION_IN_REVIEW = 'submission_in_review',
ABUSE_DETECTED = 'abuse_detected',
ABUSE_DISMISSED = 'abuse_dismissed',
}

export enum WebhookStatus {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class HandleAbuse1743412274647 implements MigrationInterface {
name = 'HandleAbuse1743412274647';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TYPE "hmt"."webhooks_event_type_enum"
RENAME TO "webhooks_event_type_enum_old"
`);
await queryRunner.query(`
CREATE TYPE "hmt"."webhooks_event_type_enum" AS ENUM(
'escrow_created',
'escrow_completed',
'escrow_canceled',
'escrow_failed',
'submission_rejected',
'submission_in_review',
'abuse_detected',
'abuse_dismissed'
)
`);
await queryRunner.query(`
ALTER TABLE "hmt"."webhooks"
ALTER COLUMN "event_type" TYPE "hmt"."webhooks_event_type_enum" USING "event_type"::"text"::"hmt"."webhooks_event_type_enum"
`);
await queryRunner.query(`
DROP TYPE "hmt"."webhooks_event_type_enum_old"
`);
await queryRunner.query(`
ALTER TYPE "hmt"."jobs_status_enum"
RENAME TO "jobs_status_enum_old"
`);
await queryRunner.query(`
CREATE TYPE "hmt"."jobs_status_enum" AS ENUM('active', 'paused', 'completed', 'canceled')
`);
await queryRunner.query(`
ALTER TABLE "hmt"."jobs"
ALTER COLUMN "status" TYPE "hmt"."jobs_status_enum" USING "status"::"text"::"hmt"."jobs_status_enum"
`);
await queryRunner.query(`
DROP TYPE "hmt"."jobs_status_enum_old"
`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TYPE "hmt"."jobs_status_enum_old" AS ENUM('active', 'completed', 'canceled')
`);
await queryRunner.query(`
ALTER TABLE "hmt"."jobs"
ALTER COLUMN "status" TYPE "hmt"."jobs_status_enum_old" USING "status"::"text"::"hmt"."jobs_status_enum_old"
`);
await queryRunner.query(`
DROP TYPE "hmt"."jobs_status_enum"
`);
await queryRunner.query(`
ALTER TYPE "hmt"."jobs_status_enum_old"
RENAME TO "jobs_status_enum"
`);
await queryRunner.query(`
CREATE TYPE "hmt"."webhooks_event_type_enum_old" AS ENUM(
'escrow_created',
'escrow_completed',
'escrow_canceled',
'escrow_failed',
'submission_rejected',
'submission_in_review'
)
`);
await queryRunner.query(`
ALTER TABLE "hmt"."webhooks"
ALTER COLUMN "event_type" TYPE "hmt"."webhooks_event_type_enum_old" USING "event_type"::"text"::"hmt"."webhooks_event_type_enum_old"
`);
await queryRunner.query(`
DROP TYPE "hmt"."webhooks_event_type_enum"
`);
await queryRunner.query(`
ALTER TYPE "hmt"."webhooks_event_type_enum_old"
RENAME TO "webhooks_event_type_enum"
`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
MOCK_MANIFEST_URL,
MOCK_PRIVATE_KEY,
} from '../../../test/constants';
import { AssignmentStatus, JobType } from '../../common/enums/job';
import { AssignmentStatus, JobStatus, JobType } from '../../common/enums/job';
import { AssignmentRepository } from '../assignment/assignment.repository';
import { AssignmentService } from '../assignment/assignment.service';
import { ManifestDto } from '../job/job.dto';
Expand All @@ -18,7 +18,7 @@ import { Escrow__factory } from '@human-protocol/core/typechain-types';
import { AssignmentSortField } from '../../common/enums/job';
import { SortDirection } from '../../common/enums/collection';
import { AssignmentEntity } from './assignment.entity';
import { ErrorAssignment } from '../../common/constant/errors';
import { ErrorAssignment, ErrorJob } from '../../common/constant/errors';
import { BadRequestException } from '@nestjs/common';
import { ServerConfigService } from '../../common/config/server-config.service';

Expand Down Expand Up @@ -117,6 +117,7 @@ describe('AssignmentService', () => {
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
jest
.spyOn(assignmentRepository, 'findOneByJobIdAndWorker')
Expand All @@ -140,6 +141,7 @@ describe('AssignmentService', () => {
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
},
workerAddress: workerAddress,
status: AssignmentStatus.ACTIVE,
Expand All @@ -160,6 +162,7 @@ describe('AssignmentService', () => {
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
jest
.spyOn(assignmentRepository, 'findOneByJobIdAndWorker')
Expand Down Expand Up @@ -194,6 +197,7 @@ describe('AssignmentService', () => {
assignmentService.createAssignment(createAssignmentDto, {
address: workerAddress,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any),
).rejects.toThrow('Job not found');
});
Expand All @@ -207,6 +211,7 @@ describe('AssignmentService', () => {
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: differentReputationNetwork,
status: JobStatus.ACTIVE,
} as any);

await expect(
Expand All @@ -217,13 +222,32 @@ describe('AssignmentService', () => {
).rejects.toThrow('Requested job is not in your reputation network');
});

it('should fail if job is not active', async () => {
jest
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.PAUSED,
} as any);

await expect(
assignmentService.createAssignment(createAssignmentDto, {
address: workerAddress,
reputationNetwork: reputationNetwork,
} as any),
).rejects.toThrow(ErrorJob.InvalidStatus);
});

it('should fail if user already assigned', async () => {
jest
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
jest
.spyOn(assignmentRepository, 'findOneByJobIdAndWorker')
Expand All @@ -244,6 +268,7 @@ describe('AssignmentService', () => {
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
jest
.spyOn(assignmentRepository, 'findOneByJobIdAndWorker')
Expand All @@ -255,6 +280,7 @@ describe('AssignmentService', () => {
assignmentService.createAssignment(createAssignmentDto, {
address: workerAddress,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any),
).rejects.toThrow('Fully assigned job');
});
Expand All @@ -267,6 +293,7 @@ describe('AssignmentService', () => {
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
jest
.spyOn(assignmentRepository, 'findOneByJobIdAndWorker')
Expand All @@ -291,6 +318,7 @@ describe('AssignmentService', () => {
id: 1,
manifestUrl: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
jest
.spyOn(assignmentRepository, 'findOneByJobIdAndWorker')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { AssignmentStatus, JobType } from '../../common/enums/job';
import { AssignmentStatus, JobStatus, JobType } from '../../common/enums/job';
import { JwtUser } from '../../common/types/jwt';
import { JobRepository } from '../job/job.repository';
import {
Expand All @@ -13,7 +13,7 @@ import { PageDto } from '../../common/pagination/pagination.dto';
import { JobService } from '../job/job.service';
import { Escrow__factory } from '@human-protocol/core/typechain-types';
import { Web3Service } from '../web3/web3.service';
import { ErrorAssignment } from '../../common/constant/errors';
import { ErrorAssignment, ErrorJob } from '../../common/constant/errors';
import { ServerConfigService } from '../../common/config/server-config.service';

@Injectable()
Expand All @@ -40,6 +40,9 @@ export class AssignmentService {
if (!jobEntity) {
this.logger.log(ErrorAssignment.JobNotFound, AssignmentService.name);
throw new BadRequestException(ErrorAssignment.JobNotFound);
} else if (jobEntity.status !== JobStatus.ACTIVE) {
this.logger.log(ErrorJob.InvalidStatus, AssignmentService.name);
throw new BadRequestException(ErrorJob.InvalidStatus);
} else if (jobEntity.reputationNetwork !== jwtUser.reputationNetwork) {
this.logger.log(
ErrorAssignment.ReputationNetworkMismatch,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ describe('JobService', () => {
job: {
escrowAddress,
chainId,
status: JobStatus.ACTIVE,
},
} as AssignmentEntity;

Expand Down Expand Up @@ -666,4 +667,54 @@ describe('JobService', () => {
).rejects.toThrow(`Solution not found in Escrow: ${escrowAddress}`);
});
});

describe('pauseJob', () => {
const webhook: WebhookDto = {
chainId,
escrowAddress,
eventType: EventType.ABUSE_DETECTED,
};

it('should create a new job in the database', async () => {
jest
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
chainId: chainId,
escrowAddress: escrowAddress,
status: JobStatus.ACTIVE,
} as JobEntity);
const result = await jobService.pauseJob(webhook);

expect(result).toEqual(undefined);
expect(jobRepository.updateOne).toHaveBeenCalledWith({
chainId: chainId,
escrowAddress: escrowAddress,
status: JobStatus.PAUSED,
});
});

it('should fail if job not exists', async () => {
jest
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue(null);

await expect(jobService.pauseJob(webhook)).rejects.toThrow(
ErrorJob.NotFound,
);
});

it('should fail if job is not in Active status', async () => {
jest
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
chainId: chainId,
escrowAddress: escrowAddress,
status: JobStatus.CANCELED,
} as JobEntity);

await expect(jobService.pauseJob(webhook)).rejects.toThrow(
ErrorJob.InvalidStatus,
);
});
});
});
Loading