diff --git a/packages/apps/job-launcher/client/src/components/Jobs/Create/CreateJob.tsx b/packages/apps/job-launcher/client/src/components/Jobs/Create/CreateJob.tsx
index fedc78c4db..110b78efe2 100644
--- a/packages/apps/job-launcher/client/src/components/Jobs/Create/CreateJob.tsx
+++ b/packages/apps/job-launcher/client/src/components/Jobs/Create/CreateJob.tsx
@@ -8,7 +8,6 @@ import { useCreateJobPageUI } from '../../../providers/CreateJobPageUIProvider';
import { JobType, PayMethod } from '../../../types';
import { CvatJobRequestForm } from './CvatJobRequestForm';
import { FortuneJobRequestForm } from './FortuneJobRequestForm';
-import { HCaptchaJobRequestForm } from './HCaptchaJobRequestForm';
export const CreateJob = () => {
const { payMethod, jobRequest, updateJobRequest } = useCreateJobPageUI();
@@ -65,9 +64,6 @@ export const CreateJob = () => {
)}
{!IS_MAINNET && }
- {/* {!IS_MAINNET && (
-
- )} */}
{
{jobRequest.jobType === JobType.FORTUNE && }
{jobRequest.jobType === JobType.CVAT && }
- {jobRequest.jobType === JobType.HCAPTCHA && }
);
};
diff --git a/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx b/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx
index 4b8a106d13..f9fce014bb 100644
--- a/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx
+++ b/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx
@@ -218,13 +218,7 @@ export const CryptoPayForm = ({
}
// create job
- const {
- jobType,
- chainId,
- fortuneRequest,
- cvatRequest,
- hCaptchaRequest,
- } = jobRequest;
+ const { jobType, chainId, fortuneRequest, cvatRequest } = jobRequest;
if (jobType === JobType.FORTUNE && fortuneRequest) {
await jobService.createFortuneJob(
chainId,
@@ -241,8 +235,6 @@ export const CryptoPayForm = ({
Number(amount),
fundTokenSymbol,
);
- } else if (jobType === JobType.HCAPTCHA && hCaptchaRequest) {
- await jobService.createHCaptchaJob(chainId, hCaptchaRequest);
}
onFinish();
} catch (err) {
diff --git a/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx b/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx
index d2e2e5e164..82502c9b9b 100644
--- a/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx
+++ b/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx
@@ -28,11 +28,7 @@ import { TokenSelect } from '../../../components/TokenSelect';
import { CURRENCY } from '../../../constants/payment';
import { useCreateJobPageUI } from '../../../providers/CreateJobPageUIProvider';
import { useSnackbar } from '../../../providers/SnackProvider';
-import {
- createCvatJob,
- createFortuneJob,
- createHCaptchaJob,
-} from '../../../services/job';
+import { createCvatJob, createFortuneJob } from '../../../services/job';
import {
confirmFiatPayment,
createFiatPayment,
@@ -247,8 +243,7 @@ export const FiatPayForm = ({
}
// create job
- const { jobType, chainId, fortuneRequest, cvatRequest, hCaptchaRequest } =
- jobRequest;
+ const { jobType, chainId, fortuneRequest, cvatRequest } = jobRequest;
if (!chainId) return;
if (jobType === JobType.FORTUNE && fortuneRequest) {
@@ -267,8 +262,6 @@ export const FiatPayForm = ({
amount,
tokenSymbol,
);
- } else if (jobType === JobType.HCAPTCHA && hCaptchaRequest) {
- await createHCaptchaJob(chainId, hCaptchaRequest);
}
// Update balance and finish payment
diff --git a/packages/apps/job-launcher/client/src/components/Jobs/Create/HCaptchaJobRequestForm.tsx b/packages/apps/job-launcher/client/src/components/Jobs/Create/HCaptchaJobRequestForm.tsx
deleted file mode 100644
index f12750a53d..0000000000
--- a/packages/apps/job-launcher/client/src/components/Jobs/Create/HCaptchaJobRequestForm.tsx
+++ /dev/null
@@ -1,748 +0,0 @@
-import AddIcon from '@mui/icons-material/Add';
-import CloseIcon from '@mui/icons-material/Close';
-import CloudIcon from '@mui/icons-material/Cloud';
-import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
-import InfoIcon from '@mui/icons-material/Info';
-import {
- Autocomplete,
- Box,
- Button,
- Chip,
- FormControl,
- FormHelperText,
- Grid,
- IconButton,
- InputAdornment,
- InputLabel,
- MenuItem,
- Select,
- TextField,
- Tooltip,
-} from '@mui/material';
-import Typography from '@mui/material/Typography';
-import { DatePicker } from '@mui/x-date-pickers/DatePicker';
-import { useFormik } from 'formik';
-import { useEffect, useState } from 'react';
-import { useSearchParams } from 'react-router-dom';
-import {
- Accordion,
- AccordionDetails,
- AccordionSummary,
-} from '../../../components/Accordion';
-import { CollectionsFilledIcon } from '../../../components/Icons/CollectionsFilledIcon';
-import languages from '../../../data/languages.json';
-import locations from '../../../data/locations.json';
-import { useCreateJobPageUI } from '../../../providers/CreateJobPageUIProvider';
-import { getQualifications } from '../../../services/qualification';
-import { HCaptchaJobType, Qualification } from '../../../types';
-import { HCaptchaJobRequesteValidationSchema } from './schema';
-
-export const HCaptchaJobRequestForm = () => {
- const { jobRequest, updateJobRequest, goToPrevStep, goToNextStep } =
- useCreateJobPageUI();
- const [expanded, setExpanded] = useState(['panel1']);
- const [searchParams] = useSearchParams();
- const [qualificationsOptions, setQualificationsOptions] = useState<
- Qualification[]
- >([]);
-
- const initialValues = {
- dataUrl: '',
- accuracyTarget: 85,
- completionDate: null,
- minRequests: null,
- maxRequests: null,
- qualifications: [],
- // Advanced
- workerLanguage: null,
- workerLocation: null,
- targetBrowser: 'desktop',
- // Annotation
- type: HCaptchaJobType.COMPARISON,
- taskBidPrice: null,
- label: '',
- labelingPrompt: null,
- groundTruths: null,
- minWorkerConfidence: 85,
- images: [],
- };
-
- const handleChange =
- (panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
- if (newExpanded) {
- setExpanded([...expanded, panel]);
- } else {
- setExpanded(expanded.filter((item) => item !== panel));
- }
- };
-
- const handleNext = (data: any) => {
- const hCaptchaRequest: any = {
- dataUrl: data.dataUrl,
- accuracyTarget: Number(data.accuracyTarget) / 100,
- minRequests: Number(data.minRequests),
- maxRequests: Number(data.maxRequests),
-
- qualifications: (data.qualifications as Qualification[]).map(
- (qualification) => qualification.reference,
- ),
- advanced: {
- workerLanguage: data.workerLanguage,
- workerLocation: data.workerLocation,
- targetBrowser: data.targetBrowser,
- },
- annotations: {
- typeOfJob: data.type,
- taskBidPrice: Number(data.taskBidPrice),
- label: data.label ?? '',
- labelingPrompt: data.labelingPrompt,
- groundTruths: data.groundTruths,
- exampleImages: data.images,
- },
- };
- if (data.completionDate) {
- hCaptchaRequest['completionDate'] = data.completionDate;
- }
- updateJobRequest({
- ...jobRequest,
- hCaptchaRequest,
- });
- goToNextStep();
- };
-
- const {
- errors,
- touched,
- values,
- dirty,
- isValid,
- handleSubmit,
- handleBlur,
- setFieldValue,
- } = useFormik({
- initialValues,
- validationSchema: HCaptchaJobRequesteValidationSchema,
- onSubmit: handleNext,
- });
-
- useEffect(() => {
- const type = searchParams.get('type');
- if (
- type &&
- Object.values(HCaptchaJobType).includes(type as HCaptchaJobType)
- ) {
- setFieldValue('type', type);
- }
- const fetchData = async () => {
- if (jobRequest.chainId !== undefined) {
- try {
- setQualificationsOptions(await getQualifications(jobRequest.chainId));
- } catch (error) {
- // eslint-disable-next-line no-console
- console.error('Error fetching data:', error);
- }
- }
- };
-
- fetchData();
- }, [jobRequest.chainId]);
-
- return (
-
-
-
- );
-};
diff --git a/packages/apps/job-launcher/client/src/components/Jobs/Create/schema.ts b/packages/apps/job-launcher/client/src/components/Jobs/Create/schema.ts
index 827358218a..85884c5fba 100644
--- a/packages/apps/job-launcher/client/src/components/Jobs/Create/schema.ts
+++ b/packages/apps/job-launcher/client/src/components/Jobs/Create/schema.ts
@@ -62,30 +62,3 @@ export const FortuneJobRequestValidationSchema = Yup.object().shape({
.moreThan(0, 'FortunesRequested must be greater than 0'),
qualifications: Yup.array().of(Yup.object()),
});
-
-export const HCaptchaJobRequesteValidationSchema = Yup.object().shape({
- taskBidPrice: Yup.number()
- .required('Task Bid Price is required')
- .moreThan(0, 'Task Bid Price must be greater than 0'),
- minRequests: Yup.number()
- .required('Min Requests is required')
- .moreThan(0, 'Min Requests must be greater than 0'),
- maxRequests: Yup.number()
- .required('Max Requests is required')
- .moreThan(
- Yup.ref('minRequests'),
- 'Max Requests must be greater than min requests',
- ),
- dataUrl: Yup.string().required('Data URL is required').url('Invalid URL'),
- labelingPrompt: Yup.string().required('Labeling Prompt is required'),
- groundTruths: Yup.string()
- .required('Ground Truth URL is required')
- .url('Invalid URL'),
- accuracyTarget: Yup.number()
- .required('Accuracy target is required')
- .moreThan(0, 'Accuracy target must be greater than 0')
- .max(100, 'Accuracy target must be less than or equal to 100'),
- targetBrowser: Yup.string().required('Target Browser is required'),
- images: Yup.array().of(Yup.string().url('Invalid Image URL')),
- qualifications: Yup.array().of(Yup.object()),
-});
diff --git a/packages/apps/job-launcher/client/src/services/job.ts b/packages/apps/job-launcher/client/src/services/job.ts
index fae6ea60d4..ceb719f492 100644
--- a/packages/apps/job-launcher/client/src/services/job.ts
+++ b/packages/apps/job-launcher/client/src/services/job.ts
@@ -6,7 +6,6 @@ import {
CvatRequest,
JobStatus,
JobDetailsResponse,
- HCaptchaRequest,
FortuneFinalResult,
} from '../types';
import api from '../utils/api';
@@ -56,16 +55,6 @@ export const createCvatJob = async (
await api.post('/job/cvat', body);
};
-export const createHCaptchaJob = async (
- chainId: number,
- data: HCaptchaRequest,
-) => {
- await api.post('/job/hCaptcha', {
- chainId,
- ...data,
- });
-};
-
export const getJobList = async ({
chainId = ChainId.ALL,
status,
diff --git a/packages/apps/job-launcher/client/src/types/index.ts b/packages/apps/job-launcher/client/src/types/index.ts
index 6add95a163..0ca3d5a11b 100644
--- a/packages/apps/job-launcher/client/src/types/index.ts
+++ b/packages/apps/job-launcher/client/src/types/index.ts
@@ -98,14 +98,6 @@ export enum CvatJobType {
IMAGE_SKELETONS_FROM_BOXES = 'image_skeletons_from_boxes',
}
-export enum HCaptchaJobType {
- POLYGON = 'polygon',
- CATEGORIZATION = 'categorization',
- POINT = 'point',
- BOUNDING_BOX = 'bounding_box',
- COMPARISON = 'comparison',
-}
-
export type FortuneRequest = {
title: string;
fortunesRequested: number;
@@ -225,34 +217,11 @@ export type CvatRequest = {
accuracyTarget: number;
};
-export type HCaptchaRequest = {
- dataUrl: string;
- accuracyTarget: number;
- completionDate: Date;
- minRequests: number;
- maxRequests: number;
- qualifications?: string[];
- advanced: {
- workerLanguage: string;
- workerLocation: string;
- targetBrowser: string;
- };
- annotations: {
- typeOfJob: string;
- taskBidPrice: number;
- label: string;
- labelingPrompt: string;
- groundTruths: string;
- exampleImages: string[];
- };
-};
-
export type JobRequest = {
jobType: JobType;
chainId?: ChainId;
fortuneRequest?: FortuneRequest;
cvatRequest?: CvatRequest;
- hCaptchaRequest?: HCaptchaRequest;
};
export enum JobStatus {
diff --git a/packages/apps/job-launcher/server/src/modules/job/fixtures.ts b/packages/apps/job-launcher/server/src/modules/job/fixtures.ts
index f95f9fdc70..cf8f0ddf88 100644
--- a/packages/apps/job-launcher/server/src/modules/job/fixtures.ts
+++ b/packages/apps/job-launcher/server/src/modules/job/fixtures.ts
@@ -8,10 +8,9 @@ import {
CvatJobType,
EscrowFundToken,
FortuneJobType,
- JobCaptchaShapeType,
} from '../../common/enums/job';
import { PaymentCurrency } from '../../common/enums/payment';
-import { JobCaptchaDto, JobCvatDto, JobFortuneDto } from './job.dto';
+import { JobCvatDto, JobFortuneDto } from './job.dto';
import { JobEntity } from './job.entity';
import { JobStatus } from '../../common/enums/job';
@@ -67,36 +66,6 @@ export const createCvatJobDto = (overrides = {}): JobCvatDto => ({
...overrides,
});
-export const createCaptchaJobDto = (overrides = {}): JobCaptchaDto => ({
- chainId: ChainId.POLYGON_AMOY,
- data: {
- provider: getMockedProvider(),
- region: getMockedRegion(),
- bucketName: faker.lorem.word(),
- path: faker.system.filePath(),
- },
- accuracyTarget: faker.number.float({ min: 0.1, max: 1, fractionDigits: 4 }),
- minRequests: faker.number.int({ min: 1, max: 5 }),
- maxRequests: faker.number.int({ min: 6, max: 10 }),
- annotations: {
- typeOfJob: faker.helpers.arrayElement(Object.values(JobCaptchaShapeType)),
- labelingPrompt: faker.lorem.sentence(),
- groundTruths: faker.internet.url(),
- exampleImages: [faker.internet.url(), faker.internet.url()],
- taskBidPrice: faker.number.float({ min: 0.1, max: 10, fractionDigits: 6 }),
- label: faker.lorem.word(),
- },
- completionDate: faker.date.future(),
- paymentCurrency: faker.helpers.arrayElement(Object.values(PaymentCurrency)),
- paymentAmount: faker.number.int({ min: 1, max: 1000 }),
- escrowFundToken: faker.helpers.arrayElement(Object.values(EscrowFundToken)),
- exchangeOracle: faker.finance.ethereumAddress(),
- recordingOracle: faker.finance.ethereumAddress(),
- reputationOracle: faker.finance.ethereumAddress(),
- advanced: {},
- ...overrides,
-});
-
export const createJobEntity = (
overrides: Partial = {},
): JobEntity => {
diff --git a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts
index e5c3bb17c8..bc7ae37fb9 100644
--- a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts
+++ b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts
@@ -37,7 +37,6 @@ import {
JobFortuneDto,
JobIdDto,
JobListDto,
- // JobCaptchaDto,
JobQuickLaunchDto,
} from './job.dto';
import { JobService } from './job.service';
@@ -176,49 +175,6 @@ export class JobController {
);
}
- // @ApiOperation({
- // summary: 'Create a hCaptcha job',
- // description: 'Endpoint to create a new hCaptcha job.',
- // })
- // @ApiBody({ type: JobCaptchaDto })
- // @ApiResponse({
- // status: 201,
- // description: 'ID of the created hCaptcha job.',
- // type: Number,
- // })
- // @ApiResponse({
- // status: 400,
- // description: 'Bad Request. Invalid input parameters.',
- // })
- // @ApiResponse({
- // status: 401,
- // description: 'Unauthorized. Missing or invalid credentials.',
- // })
- // @ApiResponse({
- // status: 409,
- // description: 'Conflict. Conflict with the current state of the server.',
- // })
- // @Post('/hCaptcha')
- // public async createCaptchaJob(
- // @Body() data: JobCaptchaDto,
- // @Request() req: RequestWithUser,
- // ): Promise {
- // throw new ForbiddenError(
- // 'Hcaptcha jobs disabled temporally',
- // );
- // return await this.mutexManagerService.runExclusive(
- // `user${req.user.id}`,
- // MUTEX_TIMEOUT,
- // async () => {
- // return await this.jobService.createJob(
- // req.user,
- // JobRequestType.HCAPTCHA,
- // data,
- // );
- // },
- // );
- // }
-
@ApiOperation({
summary: 'Get a list of jobs',
description:
diff --git a/packages/apps/job-launcher/server/src/modules/job/job.dto.ts b/packages/apps/job-launcher/server/src/modules/job/job.dto.ts
index 32a58b0a85..729fcb3ccb 100644
--- a/packages/apps/job-launcher/server/src/modules/job/job.dto.ts
+++ b/packages/apps/job-launcher/server/src/modules/job/job.dto.ts
@@ -1,47 +1,39 @@
+import { ChainId } from '@human-protocol/sdk';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
+import { Transform, Type } from 'class-transformer';
import {
+ ArrayMinSize,
IsArray,
+ IsEthereumAddress,
+ IsIn,
+ IsNotEmpty,
IsNumber,
+ IsNumberString,
+ IsObject,
+ IsOptional,
IsPositive,
IsString,
IsUrl,
- IsDateString,
- IsOptional,
- IsObject,
- IsNumberString,
- IsIn,
- Min,
Max,
- IsNotEmpty,
- IsEthereumAddress,
+ Min,
ValidateNested,
- IsDefined,
- IsNotEmptyObject,
- ArrayMinSize,
} from 'class-validator';
-import { Type } from 'class-transformer';
-import { ChainId } from '@human-protocol/sdk';
+import { IsEnumCaseInsensitive } from '../../common/decorators';
import {
- JobCaptchaShapeType,
+ CvatJobType,
EscrowFundToken,
JobRequestType,
JobSortField,
JobStatus,
JobStatusFilter,
- WorkerBrowser,
- WorkerLanguage,
- Country,
- CvatJobType,
JobType,
} from '../../common/enums/job';
-import { Transform } from 'class-transformer';
+import { PaymentCurrency } from '../../common/enums/payment';
import { AWSRegions, StorageProviders } from '../../common/enums/storage';
import { PageOptionsDto } from '../../common/pagination/pagination.dto';
-import { IsEnumCaseInsensitive } from '../../common/decorators';
-import { PaymentCurrency } from '../../common/enums/payment';
+import { IsValidTokenDecimals } from '../../common/validators/token-decimals';
import { IsValidToken } from '../../common/validators/tokens';
import { Label, ManifestDetails } from '../manifest/manifest.dto';
-import { IsValidTokenDecimals } from '../../common/validators/token-decimals';
export class JobDto {
@ApiProperty({ enum: ChainId, required: false, name: 'chain_id' })
@@ -372,112 +364,4 @@ export class GetJobsDto extends PageOptionsDto {
status?: JobStatusFilter;
}
-export class JobCaptchaAdvancedDto {
- @ApiProperty({
- enum: WorkerLanguage,
- name: 'worker_language',
- })
- @IsEnumCaseInsensitive(WorkerLanguage)
- @IsOptional()
- workerLanguage?: WorkerLanguage;
-
- @ApiProperty({
- enum: Country,
- name: 'worker_location',
- })
- @IsEnumCaseInsensitive(Country)
- @IsOptional()
- workerLocation?: Country;
-
- @ApiProperty({
- enum: WorkerBrowser,
- name: 'target_browser',
- })
- @IsEnumCaseInsensitive(WorkerBrowser)
- @IsOptional()
- targetBrowser?: WorkerBrowser;
-}
-
-class JobCaptchaAnnotationsDto {
- @ApiProperty({
- enum: JobCaptchaShapeType,
- name: 'type_of_job',
- })
- @IsEnumCaseInsensitive(JobCaptchaShapeType)
- typeOfJob: JobCaptchaShapeType;
-
- @ApiProperty({ name: 'task_bid_price' })
- @IsNumber()
- @IsPositive()
- taskBidPrice: number;
-
- @ApiPropertyOptional()
- @IsOptional()
- @IsString()
- label?: string;
-
- @ApiProperty({ name: 'labeling_prompt' })
- @IsString()
- labelingPrompt: string;
-
- @ApiProperty({ name: 'ground_truths' })
- @IsString()
- groundTruths: string;
-
- @ApiProperty({ name: 'example_images' })
- @IsOptional()
- @IsArray()
- exampleImages?: string[];
-}
-
-export class JobCaptchaDto extends JobDto {
- @ApiProperty()
- @IsObject()
- @ValidateNested()
- @Type(() => StorageDataDto)
- data: StorageDataDto;
-
- @ApiProperty({ name: 'accuracy_target' })
- @IsNumber()
- @IsPositive()
- @Max(1)
- accuracyTarget: number;
-
- @ApiProperty({ name: 'completion_date' })
- @IsDateString()
- @IsOptional()
- completionDate: Date;
-
- @ApiProperty({ name: 'min_requests' })
- @IsNumber()
- @IsPositive()
- @Max(100)
- minRequests: number;
-
- @ApiProperty({ name: 'max_requests' })
- @IsNumber()
- @IsPositive()
- @Max(100)
- maxRequests: number;
-
- @ApiProperty()
- @IsDefined()
- @IsObject()
- @ValidateNested()
- @Type(() => JobCaptchaAdvancedDto)
- advanced: JobCaptchaAdvancedDto;
-
- @ApiProperty()
- @IsDefined()
- @IsNotEmptyObject()
- @IsObject()
- @ValidateNested()
- @Type(() => JobCaptchaAnnotationsDto)
- annotations: JobCaptchaAnnotationsDto;
-}
-
-export type CreateJob =
- | JobQuickLaunchDto
- | JobFortuneDto
- | JobCvatDto
- | JobCaptchaDto;
+export type CreateJob = JobQuickLaunchDto | JobFortuneDto | JobCvatDto;
diff --git a/packages/apps/job-launcher/server/src/modules/job/job.interface.ts b/packages/apps/job-launcher/server/src/modules/job/job.interface.ts
index 1946bf3a75..b4ad55106a 100644
--- a/packages/apps/job-launcher/server/src/modules/job/job.interface.ts
+++ b/packages/apps/job-launcher/server/src/modules/job/job.interface.ts
@@ -1,7 +1,6 @@
import { CvatJobType, JobRequestType } from '../../common/enums/job';
import {
CvatDataDto,
- JobCaptchaDto,
JobCvatDto,
JobFortuneDto,
StorageDataDto,
@@ -10,7 +9,7 @@ import { JobEntity } from './job.entity';
export interface RequestAction {
createManifest: (
- dto: JobFortuneDto | JobCvatDto | JobCaptchaDto,
+ dto: JobFortuneDto | JobCvatDto,
requestType: JobRequestType,
fundAmount: number,
decimals: number,
diff --git a/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts b/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts
index cdf7d3a25a..ef7015b8fb 100644
--- a/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts
+++ b/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts
@@ -42,7 +42,6 @@ import { getTokenDecimals } from '../../common/utils/tokens';
import {
createMockCvatManifest,
createMockFortuneManifest,
- createMockHcaptchaManifest,
} from '../manifest/fixtures';
import { ManifestService } from '../manifest/manifest.service';
import { PaymentRepository } from '../payment/payment.repository';
@@ -57,7 +56,6 @@ import { WebhookRepository } from '../webhook/webhook.repository';
import { WhitelistEntity } from '../whitelist/whitelist.entity';
import { WhitelistService } from '../whitelist/whitelist.service';
import {
- createCaptchaJobDto,
createCvatJobDto,
createFortuneJobDto,
createJobEntity,
@@ -573,92 +571,6 @@ describe('JobService', () => {
});
});
- describe('HCaptcha', () => {
- it('should create an HCaptcha job', async () => {
- const captchaJobDto = createCaptchaJobDto();
- const fundTokenDecimals = getTokenDecimals(
- captchaJobDto.chainId!,
- captchaJobDto.escrowFundToken,
- );
-
- const mockManifest = createMockHcaptchaManifest();
- mockManifestService.createManifest.mockResolvedValueOnce(mockManifest);
- const mockUrl = faker.internet.url();
- const mockHash = faker.string.uuid();
- mockManifestService.uploadManifest.mockResolvedValueOnce({
- url: mockUrl,
- hash: mockHash,
- });
- const jobEntityMock = createJobEntity();
- mockJobRepository.createUnique = jest
- .fn()
- .mockResolvedValueOnce(jobEntityMock);
- mockRateService.getRate
- .mockResolvedValueOnce(tokenToUsdRate)
- .mockResolvedValueOnce(usdToTokenRate);
-
- await jobService.createJob(
- userMock,
- HCaptchaJobType.HCAPTCHA,
- captchaJobDto,
- );
-
- expect(mockWeb3Service.validateChainId).toHaveBeenCalledWith(
- captchaJobDto.chainId,
- );
- expect(mockRoutingProtocolService.selectOracles).not.toHaveBeenCalled();
- expect(mockRoutingProtocolService.validateOracles).toHaveBeenCalledWith(
- captchaJobDto.chainId,
- HCaptchaJobType.HCAPTCHA,
- captchaJobDto.reputationOracle,
- captchaJobDto.exchangeOracle,
- captchaJobDto.recordingOracle,
- );
- expect(mockManifestService.createManifest).toHaveBeenCalledWith(
- captchaJobDto,
- HCaptchaJobType.HCAPTCHA,
- captchaJobDto.paymentAmount,
- fundTokenDecimals,
- );
- expect(mockManifestService.uploadManifest).toHaveBeenCalledWith(
- captchaJobDto.chainId,
- mockManifest,
- [
- captchaJobDto.exchangeOracle,
- captchaJobDto.reputationOracle,
- captchaJobDto.recordingOracle,
- ],
- );
- expect(mockPaymentService.createWithdrawalPayment).toHaveBeenCalledWith(
- userMock.id,
- expect.any(Number),
- captchaJobDto.paymentCurrency,
- tokenToUsdRate,
- );
- expect(mockJobRepository.updateOne).toHaveBeenCalledWith({
- chainId: captchaJobDto.chainId,
- userId: userMock.id,
- manifestUrl: mockUrl,
- manifestHash: mockHash,
- requestType: HCaptchaJobType.HCAPTCHA,
- fee: expect.any(Number),
- fundAmount: Number(
- mul(
- mul(captchaJobDto.paymentAmount, tokenToUsdRate),
- usdToTokenRate,
- ).toFixed(6),
- ),
- status: JobStatus.MODERATION_PASSED,
- waitUntil: expect.any(Date),
- token: captchaJobDto.escrowFundToken,
- exchangeOracle: captchaJobDto.exchangeOracle,
- recordingOracle: captchaJobDto.recordingOracle,
- reputationOracle: captchaJobDto.reputationOracle,
- payments: expect.any(Array),
- });
- });
- });
-
describe('JobQuickLaunchDto', () => {
it('should create a job with quick launch dto', async () => {
const jobQuickLaunchDto = new JobQuickLaunchDto();
diff --git a/packages/apps/job-launcher/server/src/modules/manifest/fixtures.ts b/packages/apps/job-launcher/server/src/modules/manifest/fixtures.ts
index dde47c00b4..ba2b12bb13 100644
--- a/packages/apps/job-launcher/server/src/modules/manifest/fixtures.ts
+++ b/packages/apps/job-launcher/server/src/modules/manifest/fixtures.ts
@@ -1,25 +1,14 @@
import { faker } from '@faker-js/faker';
import { ChainId } from '@human-protocol/sdk';
-import { AuthConfigService } from '../../common/config/auth-config.service';
import { CvatConfigService } from '../../common/config/cvat-config.service';
-import { Web3ConfigService } from '../../common/config/web3-config.service';
-import {
- CvatJobType,
- EscrowFundToken,
- JobCaptchaRequestType,
- JobCaptchaShapeType,
-} from '../../common/enums/job';
+import { CvatJobType, EscrowFundToken } from '../../common/enums/job';
import { PaymentCurrency } from '../../common/enums/payment';
-import { JobCaptchaDto, JobCvatDto } from '../job/job.dto';
+import { JobCvatDto } from '../job/job.dto';
import {
getMockedProvider,
getMockedRegion,
} from '../../../test/fixtures/storage';
-import {
- CvatManifestDto,
- FortuneManifestDto,
- HCaptchaManifestDto,
-} from './manifest.dto';
+import { CvatManifestDto, FortuneManifestDto } from './manifest.dto';
import { FortuneJobType } from '../../common/enums/job';
export const mockCvatConfigService: Omit = {
@@ -29,21 +18,6 @@ export const mockCvatConfigService: Omit = {
skeletonsJobSizeMultiplier: faker.number.int({ min: 1, max: 1000 }),
};
-export const mockAuthConfigService: Omit<
- Partial,
- 'configService'
-> = {
- hCaptchaSiteKey: faker.string.uuid(),
-};
-
-export const mockWeb3ConfigService: Omit<
- Partial,
- 'configService'
-> = {
- hCaptchaReputationOracleURI: faker.internet.url(),
- hCaptchaRecordingOracleURI: faker.internet.url(),
-};
-
export function createJobCvatDto(
overrides: Partial = {},
): JobCvatDto {
@@ -75,36 +49,6 @@ export function createJobCvatDto(
};
}
-export function createJobCaptchaDto(
- overrides: Partial = {},
-): JobCaptchaDto {
- return {
- data: {
- provider: getMockedProvider(),
- region: getMockedRegion(),
- bucketName: faker.lorem.word(),
- path: faker.system.filePath(),
- },
- accuracyTarget: faker.number.float({ min: 0.1, max: 1 }),
- minRequests: faker.number.int({ min: 1, max: 5 }),
- maxRequests: faker.number.int({ min: 6, max: 10 }),
- annotations: {
- typeOfJob: faker.helpers.arrayElement(Object.values(JobCaptchaShapeType)),
- labelingPrompt: faker.lorem.sentence(),
- groundTruths: faker.internet.url(),
- exampleImages: [faker.internet.url(), faker.internet.url()],
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- label: faker.lorem.word(),
- },
- completionDate: faker.date.future(),
- paymentCurrency: faker.helpers.arrayElement(Object.values(PaymentCurrency)),
- paymentAmount: faker.number.int({ min: 1, max: 1000 }),
- escrowFundToken: faker.helpers.arrayElement(Object.values(EscrowFundToken)),
- advanced: {},
- ...overrides,
- };
-}
-
export function createMockFortuneManifest(
overrides: Partial = {},
): FortuneManifestDto {
@@ -150,55 +94,3 @@ export function createMockCvatManifest(
...overrides,
};
}
-
-export function createMockHcaptchaManifest(
- overrides: Partial = {},
-): HCaptchaManifestDto {
- return {
- job_mode: faker.lorem.word(),
- request_type: faker.helpers.arrayElement(
- Object.values(JobCaptchaRequestType),
- ),
- request_config: {
- shape_type: faker.helpers.arrayElement(
- Object.values(JobCaptchaShapeType),
- ),
- min_shapes_per_image: faker.number.int({ min: 1, max: 5 }),
- max_shapes_per_image: faker.number.int({ min: 6, max: 10 }),
- min_points: faker.number.int({ min: 1, max: 5 }),
- max_points: faker.number.int({ min: 6, max: 10 }),
- minimum_selection_area_per_shape: faker.number.int({ min: 1, max: 100 }),
- multiple_choice_max_choices: faker.number.int({ min: 1, max: 5 }),
- multiple_choice_min_choices: faker.number.int({ min: 1, max: 5 }),
- answer_type: faker.lorem.word(),
- overlap_threshold: faker.number.float({ min: 0, max: 1 }),
- max_length: faker.number.int({ min: 1, max: 100 }),
- min_length: faker.number.int({ min: 1, max: 100 }),
- },
- requester_accuracy_target: faker.number.float({ min: 0.1, max: 1 }),
- requester_max_repeats: faker.number.int({ min: 1, max: 10 }),
- requester_min_repeats: faker.number.int({ min: 1, max: 10 }),
- requester_question_example: [faker.internet.url()],
- requester_question: { en: faker.lorem.sentence() },
- taskdata_uri: faker.internet.url(),
- job_total_tasks: faker.number.int({ min: 1, max: 1000 }),
- task_bid_price: faker.number.float({ min: 0.01, max: 10 }),
- groundtruth_uri: faker.internet.url(),
- public_results: faker.datatype.boolean(),
- oracle_stake: faker.number.int({ min: 1, max: 100 }),
- repo_uri: faker.internet.url(),
- ro_uri: faker.internet.url(),
- restricted_audience: {},
- requester_restricted_answer_set: {},
- taskdata: [
- {
- task_key: faker.string.uuid(),
- datapoint_uri: faker.internet.url(),
- datapoint_hash: faker.string.uuid(),
- datapoint_text: { en: faker.lorem.sentence() },
- },
- ],
- qualifications: [faker.lorem.word()],
- ...overrides,
- };
-}
diff --git a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts
index e06ba03ca1..2f9363f42e 100644
--- a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts
+++ b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts
@@ -7,51 +7,19 @@ import { faker } from '@faker-js/faker';
import { createMock } from '@golevelup/ts-jest';
import { Encryption } from '@human-protocol/sdk';
import { Test } from '@nestjs/testing';
-import { AuthConfigService } from '../../common/config/auth-config.service';
import { CvatConfigService } from '../../common/config/cvat-config.service';
import { PGPConfigService } from '../../common/config/pgp-config.service';
-import { Web3ConfigService } from '../../common/config/web3-config.service';
-import {
- HCAPTCHA_BOUNDING_BOX_MAX_POINTS,
- HCAPTCHA_BOUNDING_BOX_MIN_POINTS,
- HCAPTCHA_IMMO_MAX_LENGTH,
- HCAPTCHA_IMMO_MIN_LENGTH,
- HCAPTCHA_LANDMARK_MAX_POINTS,
- HCAPTCHA_LANDMARK_MIN_POINTS,
- HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- HCAPTCHA_MINIMUM_SELECTION_AREA_PER_SHAPE,
- HCAPTCHA_ORACLE_STAKE,
- HCAPTCHA_POLYGON_MAX_POINTS,
- HCAPTCHA_POLYGON_MIN_POINTS,
-} from '../../common/constants';
import { ErrorJob } from '../../common/constants/errors';
-import {
- CvatJobType,
- FortuneJobType,
- HCaptchaJobType,
- JobCaptchaMode,
- JobCaptchaRequestType,
- JobCaptchaShapeType,
-} from '../../common/enums/job';
+import { CvatJobType, FortuneJobType } from '../../common/enums/job';
import {
ConflictError,
ServerError,
ValidationError,
} from '../../common/errors';
-import {
- generateBucketUrl,
- listObjectsInBucket,
-} from '../../common/utils/storage';
+import { generateBucketUrl } from '../../common/utils/storage';
import { StorageService } from '../storage/storage.service';
import { Web3Service } from '../web3/web3.service';
-import {
- createJobCaptchaDto,
- createJobCvatDto,
- mockAuthConfigService,
- mockCvatConfigService,
- mockWeb3ConfigService,
-} from './fixtures';
+import { createJobCvatDto, mockCvatConfigService } from './fixtures';
import { FortuneManifestDto } from './manifest.dto';
import { ManifestService } from './manifest.service';
import {
@@ -72,19 +40,11 @@ describe('ManifestService', () => {
ManifestService,
{ provide: Web3Service, useValue: createMock() },
{ provide: StorageService, useValue: mockStorageService },
- {
- provide: AuthConfigService,
- useValue: mockAuthConfigService,
- },
{
provide: CvatConfigService,
useValue: mockCvatConfigService,
},
{ provide: PGPConfigService, useValue: { encrypt: false } },
- {
- provide: Web3ConfigService,
- useValue: mockWeb3ConfigService,
- },
{ provide: Encryption, useValue: createMock() },
],
}).compile();
@@ -297,422 +257,6 @@ describe('ManifestService', () => {
).rejects.toThrow(new ConflictError(ErrorJob.DataNotExist));
});
});
-
- describe('createHCaptchaManifest', () => {
- const requestType = HCaptchaJobType.HCAPTCHA;
- const tokenFundAmount = faker.number.int({ min: 1, max: 1000 });
- const tokenFundDecimals = faker.number.int({ min: 1, max: 18 });
-
- beforeEach(() => {
- const fileContent = JSON.stringify({
- [faker.internet.url()]: [true, true, true],
- });
- (listObjectsInBucket as jest.Mock).mockResolvedValueOnce([
- `${faker.word.sample()}.jpg`,
- `${faker.word.sample()}.jpg`,
- `${faker.word.sample()}.jpg`,
- ]);
- mockStorageService.uploadJsonLikeData.mockResolvedValueOnce({
- url: faker.internet.url(),
- hash: faker.string.uuid(),
- });
- mockStorageService.downloadJsonLikeData.mockResolvedValueOnce(
- fileContent,
- );
- });
-
- it('should create a valid HCaptcha manifest for COMPARISON job type', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.COMPARISON,
- labelingPrompt: faker.lorem.sentence(),
- groundTruths: faker.internet.url(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- exampleImages: [faker.internet.url(), faker.internet.url()],
- },
- });
-
- const result = await manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- );
-
- expect(result).toEqual({
- job_mode: JobCaptchaMode.BATCH,
- requester_accuracy_target: jobDto.accuracyTarget,
- request_config: {},
- restricted_audience: {
- sitekey: [expect.any(Object)],
- },
- requester_max_repeats: jobDto.maxRequests,
- requester_min_repeats: jobDto.minRequests,
- requester_question: { en: jobDto.annotations.labelingPrompt },
- job_total_tasks: 3,
- task_bid_price: jobDto.annotations.taskBidPrice,
- taskdata_uri: expect.any(String),
- public_results: true,
- oracle_stake: HCAPTCHA_ORACLE_STAKE,
- repo_uri: mockWeb3ConfigService.hCaptchaReputationOracleURI,
- ro_uri: mockWeb3ConfigService.hCaptchaRecordingOracleURI,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_BINARY,
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {},
- requester_question_example: jobDto.annotations.exampleImages,
- });
- });
-
- it('should create a valid HCaptcha manifest for CATEGORIZATION job type', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.CATEGORIZATION,
- labelingPrompt: faker.lorem.sentence(),
- groundTruths: faker.internet.url(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- },
- });
-
- const result = await manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- );
-
- expect(result).toEqual({
- job_mode: JobCaptchaMode.BATCH,
- requester_accuracy_target: jobDto.accuracyTarget,
- request_config: {},
- restricted_audience: {
- sitekey: [expect.any(Object)],
- },
- requester_max_repeats: jobDto.maxRequests,
- requester_min_repeats: jobDto.minRequests,
- requester_question: { en: jobDto.annotations.labelingPrompt },
- job_total_tasks: 3,
- task_bid_price: jobDto.annotations.taskBidPrice,
- taskdata_uri: expect.any(String),
- public_results: true,
- oracle_stake: HCAPTCHA_ORACLE_STAKE,
- repo_uri: mockWeb3ConfigService.hCaptchaReputationOracleURI,
- ro_uri: mockWeb3ConfigService.hCaptchaRecordingOracleURI,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_MULTIPLE_CHOICE,
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: expect.any(Object),
- });
- });
-
- it('should create a valid HCaptcha manifest for POLYGON job type', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.POLYGON,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- label: faker.lorem.word(),
- },
- });
-
- const result = await manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- );
-
- expect(result).toEqual({
- job_mode: JobCaptchaMode.BATCH,
- requester_accuracy_target: jobDto.accuracyTarget,
- request_config: {
- shape_type: JobCaptchaShapeType.POLYGON,
- min_shapes_per_image: HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- max_shapes_per_image: HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- min_points: HCAPTCHA_POLYGON_MIN_POINTS,
- max_points: HCAPTCHA_POLYGON_MAX_POINTS,
- minimum_selection_area_per_shape:
- HCAPTCHA_MINIMUM_SELECTION_AREA_PER_SHAPE,
- },
- restricted_audience: {
- sitekey: [expect.any(Object)],
- },
- requester_max_repeats: jobDto.maxRequests,
- requester_min_repeats: jobDto.minRequests,
- requester_question: { en: jobDto.annotations.labelingPrompt },
- requester_question_example: [],
- job_total_tasks: 3,
- task_bid_price: jobDto.annotations.taskBidPrice,
- taskdata_uri: expect.any(String),
- public_results: true,
- oracle_stake: HCAPTCHA_ORACLE_STAKE,
- repo_uri: mockWeb3ConfigService.hCaptchaReputationOracleURI,
- ro_uri: mockWeb3ConfigService.hCaptchaRecordingOracleURI,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT,
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- });
- });
-
- it('should throw ValidationError for invalid POLYGON job type without label', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.POLYGON,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- },
- });
-
- await expect(
- manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- ),
- ).rejects.toThrow(
- new ValidationError(ErrorJob.JobParamsValidationFailed),
- );
- });
-
- it('should create a valid HCaptcha manifest for POINT job type', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.POINT,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- label: faker.lorem.word(),
- },
- });
-
- const result = await manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- );
-
- expect(result).toEqual({
- job_mode: JobCaptchaMode.BATCH,
- requester_accuracy_target: jobDto.accuracyTarget,
- request_config: {
- shape_type: JobCaptchaShapeType.POINT,
- min_shapes_per_image: HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- max_shapes_per_image: HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- min_points: HCAPTCHA_LANDMARK_MIN_POINTS,
- max_points: HCAPTCHA_LANDMARK_MAX_POINTS,
- },
- restricted_audience: {
- sitekey: [expect.any(Object)],
- },
- requester_max_repeats: jobDto.maxRequests,
- requester_min_repeats: jobDto.minRequests,
- requester_question: { en: jobDto.annotations.labelingPrompt },
- requester_question_example: jobDto.annotations.exampleImages || [],
- job_total_tasks: 3,
- task_bid_price: jobDto.annotations.taskBidPrice,
- taskdata_uri: expect.any(String),
- public_results: true,
- oracle_stake: HCAPTCHA_ORACLE_STAKE,
- repo_uri: mockWeb3ConfigService.hCaptchaReputationOracleURI,
- ro_uri: mockWeb3ConfigService.hCaptchaRecordingOracleURI,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT,
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- });
- });
-
- it('should throw ValidationError for invalid POINT job type without label', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.POINT,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- },
- });
-
- await expect(
- manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- ),
- ).rejects.toThrow(
- new ValidationError(ErrorJob.JobParamsValidationFailed),
- );
- });
-
- it('should create a valid HCaptcha manifest for BOUNDING_BOX job type', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.BOUNDING_BOX,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- label: faker.lorem.word(),
- },
- });
-
- const result = await manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- );
-
- expect(result).toEqual({
- job_mode: JobCaptchaMode.BATCH,
- requester_accuracy_target: jobDto.accuracyTarget,
- request_config: {
- shape_type: JobCaptchaShapeType.BOUNDING_BOX,
- min_shapes_per_image: HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- max_shapes_per_image: HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- min_points: HCAPTCHA_BOUNDING_BOX_MIN_POINTS,
- max_points: HCAPTCHA_BOUNDING_BOX_MAX_POINTS,
- },
- restricted_audience: {
- sitekey: [expect.any(Object)],
- },
- requester_max_repeats: jobDto.maxRequests,
- requester_min_repeats: jobDto.minRequests,
- requester_question: { en: jobDto.annotations.labelingPrompt },
- requester_question_example: jobDto.annotations.exampleImages || [],
- job_total_tasks: 3,
- task_bid_price: jobDto.annotations.taskBidPrice,
- taskdata_uri: expect.any(String),
- public_results: true,
- oracle_stake: HCAPTCHA_ORACLE_STAKE,
- repo_uri: mockWeb3ConfigService.hCaptchaReputationOracleURI,
- ro_uri: mockWeb3ConfigService.hCaptchaRecordingOracleURI,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT,
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- });
- });
-
- it('should throw ValidationError for invalid BOUNDING_BOX job type without label', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.BOUNDING_BOX,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- },
- });
-
- await expect(
- manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- ),
- ).rejects.toThrow(
- new ValidationError(ErrorJob.JobParamsValidationFailed),
- );
- });
-
- it('should create a valid HCaptcha manifest for IMMO job type', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.IMMO,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- label: faker.lorem.word(),
- },
- });
-
- const result = await manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- );
-
- expect(result).toEqual({
- job_mode: JobCaptchaMode.BATCH,
- requester_accuracy_target: jobDto.accuracyTarget,
- request_config: {
- multiple_choice_max_choices: 1,
- multiple_choice_min_choices: 1,
- overlap_threshold: null,
- answer_type: 'str',
- max_length: HCAPTCHA_IMMO_MAX_LENGTH,
- min_length: HCAPTCHA_IMMO_MIN_LENGTH,
- },
- restricted_audience: {
- sitekey: [expect.any(Object)],
- },
- requester_max_repeats: jobDto.maxRequests,
- requester_min_repeats: jobDto.minRequests,
- requester_question: { en: jobDto.annotations.labelingPrompt },
- job_total_tasks: 3,
- task_bid_price: jobDto.annotations.taskBidPrice,
- taskdata: [],
- taskdata_uri: expect.any(String),
- public_results: true,
- oracle_stake: HCAPTCHA_ORACLE_STAKE,
- repo_uri: mockWeb3ConfigService.hCaptchaReputationOracleURI,
- ro_uri: mockWeb3ConfigService.hCaptchaRecordingOracleURI,
- request_type: JobCaptchaRequestType.TEXT_FREEE_NTRY,
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- });
- });
-
- it('should throw ValidationError for invalid IMMO job type without label', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: JobCaptchaShapeType.IMMO,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- },
- });
-
- await expect(
- manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- ),
- ).rejects.toThrow(
- new ValidationError(ErrorJob.JobParamsValidationFailed),
- );
- });
-
- it('should throw ValidationError for invalid job type', async () => {
- const jobDto = createJobCaptchaDto({
- annotations: {
- typeOfJob: 'INVALID_JOB_TYPE' as JobCaptchaShapeType,
- labelingPrompt: faker.lorem.sentence(),
- taskBidPrice: faker.number.float({ min: 0.1, max: 10 }),
- groundTruths: faker.internet.url(),
- },
- });
-
- await expect(
- manifestService.createManifest(
- jobDto,
- requestType,
- tokenFundAmount,
- tokenFundDecimals,
- ),
- ).rejects.toThrow(new ValidationError(ErrorJob.HCaptchaInvalidJobType));
- });
- });
});
describe('uploadManifest', () => {
diff --git a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts
index 6276568d13..93a47b8481 100644
--- a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts
+++ b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts
@@ -5,34 +5,13 @@ import {
} from '@nestjs/common';
import { validate } from 'class-validator';
import { ethers } from 'ethers';
-import { v4 as uuidv4 } from 'uuid';
-import { AuthConfigService } from '../../common/config/auth-config.service';
import { CvatConfigService } from '../../common/config/cvat-config.service';
import { PGPConfigService } from '../../common/config/pgp-config.service';
-import { Web3ConfigService } from '../../common/config/web3-config.service';
-import {
- HCAPTCHA_BOUNDING_BOX_MAX_POINTS,
- HCAPTCHA_BOUNDING_BOX_MIN_POINTS,
- HCAPTCHA_IMMO_MAX_LENGTH,
- HCAPTCHA_IMMO_MIN_LENGTH,
- HCAPTCHA_LANDMARK_MAX_POINTS,
- HCAPTCHA_LANDMARK_MIN_POINTS,
- HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- HCAPTCHA_MINIMUM_SELECTION_AREA_PER_SHAPE,
- HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- HCAPTCHA_NOT_PRESENTED_LABEL,
- HCAPTCHA_ORACLE_STAKE,
- HCAPTCHA_POLYGON_MAX_POINTS,
- HCAPTCHA_POLYGON_MIN_POINTS,
-} from '../../common/constants';
import { ErrorJob } from '../../common/constants/errors';
import {
CvatJobType,
FortuneJobType,
HCaptchaJobType,
- JobCaptchaMode,
- JobCaptchaRequestType,
- JobCaptchaShapeType,
JobRequestType,
} from '../../common/enums/job';
import { ConflictError, ValidationError } from '../../common/errors';
@@ -40,12 +19,7 @@ import {
generateBucketUrl,
listObjectsInBucket,
} from '../../common/utils/storage';
-import {
- CreateJob,
- JobCaptchaAdvancedDto,
- JobCaptchaDto,
- JobCvatDto,
-} from '../job/job.dto';
+import { CreateJob, JobCvatDto } from '../job/job.dto';
import {
CvatAnnotationData,
CvatCalculateJobBounty,
@@ -59,7 +33,6 @@ import {
FortuneManifestDto,
HCaptchaManifestDto,
ManifestDto,
- RestrictedAudience,
} from './manifest.dto';
@Injectable()
@@ -68,8 +41,6 @@ export class ManifestService {
constructor(
private readonly web3Service: Web3Service,
- private readonly authConfigService: AuthConfigService,
- private readonly web3ConfigService: Web3ConfigService,
private readonly cvatConfigService: CvatConfigService,
private readonly pgpConfigService: PGPConfigService,
private readonly storageService: StorageService,
@@ -83,9 +54,6 @@ export class ManifestService {
decimals: number,
): Promise {
switch (requestType) {
- case HCaptchaJobType.HCAPTCHA:
- return this.createHCaptchaManifest(dto as JobCaptchaDto);
-
case FortuneJobType.FORTUNE:
return {
...dto,
@@ -311,226 +279,6 @@ export class ManifestService {
};
}
- private async createHCaptchaManifest(
- jobDto: JobCaptchaDto,
- ): Promise {
- const jobType = jobDto.annotations.typeOfJob;
- const dataUrl = generateBucketUrl(jobDto.data, HCaptchaJobType.HCAPTCHA);
- const objectsInBucket = await listObjectsInBucket(dataUrl);
-
- const commonManifestProperties = {
- job_mode: JobCaptchaMode.BATCH,
- requester_accuracy_target: jobDto.accuracyTarget,
- request_config: {},
- restricted_audience: this.buildHCaptchaRestrictedAudience(
- jobDto.advanced,
- ),
- requester_max_repeats: jobDto.maxRequests,
- requester_min_repeats: jobDto.minRequests,
- requester_question: { en: jobDto.annotations.labelingPrompt },
- job_total_tasks: objectsInBucket.length,
- task_bid_price: jobDto.annotations.taskBidPrice,
- taskdata_uri: await this.generateAndUploadTaskData(
- dataUrl.href,
- objectsInBucket,
- ),
- public_results: true,
- oracle_stake: HCAPTCHA_ORACLE_STAKE,
- repo_uri: this.web3ConfigService.hCaptchaReputationOracleURI,
- ro_uri: this.web3ConfigService.hCaptchaRecordingOracleURI,
- ...(jobDto.qualifications && {
- qualifications: jobDto.qualifications,
- }),
- };
-
- let groundTruthsData;
- if (jobDto.annotations.groundTruths) {
- groundTruthsData = await this.storageService.downloadJsonLikeData(
- jobDto.annotations.groundTruths,
- );
- }
-
- switch (jobType) {
- case JobCaptchaShapeType.COMPARISON:
- return {
- ...commonManifestProperties,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_BINARY,
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {},
- requester_question_example: jobDto.annotations.exampleImages || [],
- };
-
- case JobCaptchaShapeType.CATEGORIZATION:
- return {
- ...commonManifestProperties,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_MULTIPLE_CHOICE,
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set:
- this.buildHCaptchaRestrictedAnswerSet(groundTruthsData),
- };
-
- case JobCaptchaShapeType.POLYGON:
- if (!jobDto.annotations.label) {
- throw new ValidationError(ErrorJob.JobParamsValidationFailed);
- }
-
- return {
- ...commonManifestProperties,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT,
- request_config: {
- shape_type: JobCaptchaShapeType.POLYGON,
- min_shapes_per_image: HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- max_shapes_per_image: HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- min_points: HCAPTCHA_POLYGON_MIN_POINTS,
- max_points: HCAPTCHA_POLYGON_MAX_POINTS,
- minimum_selection_area_per_shape:
- HCAPTCHA_MINIMUM_SELECTION_AREA_PER_SHAPE,
- },
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- requester_question_example: jobDto.annotations.exampleImages || [],
- };
-
- case JobCaptchaShapeType.POINT:
- if (!jobDto.annotations.label) {
- throw new ValidationError(ErrorJob.JobParamsValidationFailed);
- }
-
- return {
- ...commonManifestProperties,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT,
- request_config: {
- shape_type: jobType,
- min_shapes_per_image: HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- max_shapes_per_image: HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- min_points: HCAPTCHA_LANDMARK_MIN_POINTS,
- max_points: HCAPTCHA_LANDMARK_MAX_POINTS,
- },
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- requester_question_example: jobDto.annotations.exampleImages || [],
- };
-
- case JobCaptchaShapeType.BOUNDING_BOX:
- if (!jobDto.annotations.label) {
- throw new ValidationError(ErrorJob.JobParamsValidationFailed);
- }
-
- return {
- ...commonManifestProperties,
- request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT,
- request_config: {
- shape_type: jobType,
- min_shapes_per_image: HCAPTCHA_MIN_SHAPES_PER_IMAGE,
- max_shapes_per_image: HCAPTCHA_MAX_SHAPES_PER_IMAGE,
- min_points: HCAPTCHA_BOUNDING_BOX_MIN_POINTS,
- max_points: HCAPTCHA_BOUNDING_BOX_MAX_POINTS,
- },
- groundtruth_uri: jobDto.annotations.groundTruths,
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- requester_question_example: jobDto.annotations.exampleImages || [],
- };
-
- case JobCaptchaShapeType.IMMO:
- if (!jobDto.annotations.label) {
- throw new ValidationError(ErrorJob.JobParamsValidationFailed);
- }
-
- return {
- ...commonManifestProperties,
- request_type: JobCaptchaRequestType.TEXT_FREEE_NTRY,
- request_config: {
- multiple_choice_max_choices: 1,
- multiple_choice_min_choices: 1,
- overlap_threshold: null,
- answer_type: 'str',
- max_length: HCAPTCHA_IMMO_MAX_LENGTH,
- min_length: HCAPTCHA_IMMO_MIN_LENGTH,
- },
- requester_restricted_answer_set: {
- [jobDto.annotations.label!]: { en: jobDto.annotations.label },
- },
- taskdata: [],
- };
-
- default:
- throw new ValidationError(ErrorJob.HCaptchaInvalidJobType);
- }
- }
-
- private buildHCaptchaRestrictedAudience(advanced: JobCaptchaAdvancedDto) {
- const restrictedAudience: RestrictedAudience = {};
-
- restrictedAudience.sitekey = [
- {
- [this.authConfigService.hCaptchaSiteKey]: {
- score: 1,
- },
- },
- ];
-
- if (advanced.workerLanguage) {
- restrictedAudience.lang = [{ [advanced.workerLanguage]: { score: 1 } }];
- }
-
- if (advanced.workerLocation) {
- restrictedAudience.country = [
- { [advanced.workerLocation]: { score: 1 } },
- ];
- }
-
- if (advanced.targetBrowser) {
- restrictedAudience.browser = [{ [advanced.targetBrowser]: { score: 1 } }];
- }
-
- return restrictedAudience;
- }
-
- private buildHCaptchaRestrictedAnswerSet(groundTruthsData: any) {
- const maxElements = 3;
- const outputObject: any = {};
-
- let elementCount = 0;
-
- for (const key of Object.keys(groundTruthsData)) {
- if (elementCount >= maxElements) {
- break;
- }
-
- const value = groundTruthsData[key][0][0];
- outputObject[value] = { en: value, answer_example_uri: key };
- elementCount++;
- }
-
- // Default case
- outputObject['0'] = { en: HCAPTCHA_NOT_PRESENTED_LABEL };
-
- return outputObject;
- }
-
- private async generateAndUploadTaskData(
- dataUrl: string,
- objectNames: string[],
- ) {
- const data = objectNames.map((objectName) => {
- return {
- datapoint_uri: `${dataUrl}/${objectName}`,
- datapoint_hash: 'undefined-hash',
- task_key: uuidv4(),
- };
- });
-
- const { url } = await this.storageService.uploadJsonLikeData(data);
-
- return url;
- }
-
async uploadManifest(
chainId: ChainId,
data: any,