diff --git a/migration/1724231548035-ProjectIcon.ts b/migration/1724231548035-ProjectIcon.ts new file mode 100644 index 000000000..cdb96223f --- /dev/null +++ b/migration/1724231548035-ProjectIcon.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class ProjectIcon1724231548035 implements MigrationInterface { + name = 'ProjectIcon1724231548035'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "project" ADD "icon" character varying`, + ); + await queryRunner.query( + `ALTER TABLE "project_update" ADD "icon" character varying`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "project_update" DROP COLUMN "icon"`); + await queryRunner.query(`ALTER TABLE "project" DROP COLUMN "icon"`); + } +} diff --git a/src/entities/project.ts b/src/entities/project.ts index 31a211a17..946b01ed7 100644 --- a/src/entities/project.ts +++ b/src/entities/project.ts @@ -446,6 +446,10 @@ export class Project extends BaseEntity { @Field(_type => [Campaign], { nullable: true }) campaigns: Campaign[]; + @Field({ nullable: true }) + @Column({ nullable: true }) + icon?: string; + // only projects with status active can be listed automatically static pendingReviewSince(maximumDaysForListing: number) { const maxDaysForListing = moment() @@ -675,6 +679,10 @@ export class ProjectUpdate extends BaseEntity { @Column('text', { nullable: true }) managingFundDescription: string; + @Field({ nullable: true }) + @Column({ nullable: true }) + icon?: string; + @Field(_type => FeaturedUpdate, { nullable: true }) @OneToOne( _type => FeaturedUpdate, diff --git a/src/resolvers/projectResolver.test.ts b/src/resolvers/projectResolver.test.ts index 0ecfe1c2b..0fbff8417 100644 --- a/src/resolvers/projectResolver.test.ts +++ b/src/resolvers/projectResolver.test.ts @@ -53,7 +53,7 @@ function createProjectTestCases() { description: 'Test Project Description', categories: [], image: 'https://example.com/test-project.jpg', - teaser: 'https://example.com/test-project-teaser.jpg', + teaser: 'Test Project Text Teaser', impactLocation: 'Test Impact Location', isDraft: false, teamMembers, @@ -82,4 +82,42 @@ function createProjectTestCases() { await getAbcLauncherAdapter().getProjectAbcLaunchData(projectAddress); expect(project.abc).to.deep.equal(expectedAbc); }); + + it('should create project with icon successfully', async () => { + assert.isOk(user); + assert.isOk(accessToken); + + const projectAddress = generateRandomEtheriumAddress(); + const createProjectInput: CreateProjectInput = { + title: 'Test Project with Icon', + adminUserId: user.id, + description: 'A project to test icon field', + categories: [], + image: 'https://example.com/test-project.jpg', + teaser: 'Test Project Teaser', + impactLocation: 'Test Location', + isDraft: false, + address: projectAddress, + icon: 'https://example.com/test-icon.jpg', + }; + + const result = await axios.post( + graphqlUrl, + { + query: createProjectQuery, + variables: { + project: createProjectInput, + }, + }, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }, + ); + + const project = result.data.data.createProject; + assert.isOk(project); + expect(project.icon).to.equal(createProjectInput.icon); + }); } diff --git a/src/resolvers/projectResolver.ts b/src/resolvers/projectResolver.ts index a7291f01a..746431858 100644 --- a/src/resolvers/projectResolver.ts +++ b/src/resolvers/projectResolver.ts @@ -1115,6 +1115,10 @@ export class ProjectResolver { // project.listed = null; // project.reviewStatus = ReviewStatus.NotReviewed; + // if (newProjectData.icon !== undefined) { + // project.icon = newProjectData.icon; + // } + // await project.save(); // await project.reload(); @@ -1299,44 +1303,44 @@ export class ProjectResolver { const qualityScore = getQualityScore(description, Boolean(image), 0); - if (!projectInput.categories) { - throw new Error( - i18n.__( - translationErrorMessagesKeys.CATEGORIES_MUST_BE_FROM_THE_FRONTEND_SUBSELECTION, - ), - ); - } + // if (!projectInput.categories) { + // throw new Error( + // i18n.__( + // translationErrorMessagesKeys.CATEGORIES_MUST_BE_FROM_THE_FRONTEND_SUBSELECTION, + // ), + // ); + // } // We do not create categories only use existing ones - const categories = await Promise.all( - projectInput.categories - ? projectInput.categories.map(async category => { - const [c] = await this.categoryRepository.find({ - where: { - name: category, - isActive: true, - canUseOnFrontend: true, - }, - }); - if (!c) { - throw new Error( - i18n.__( - translationErrorMessagesKeys.CATEGORIES_MUST_BE_FROM_THE_FRONTEND_SUBSELECTION, - ), - ); - } - return c; - }) - : [], - ); + // const categories = await Promise.all( + // projectInput.categories + // ? projectInput.categories.map(async category => { + // const [c] = await this.categoryRepository.find({ + // where: { + // name: category, + // isActive: true, + // canUseOnFrontend: true, + // }, + // }); + // if (!c) { + // throw new Error( + // i18n.__( + // translationErrorMessagesKeys.CATEGORIES_MUST_BE_FROM_THE_FRONTEND_SUBSELECTION, + // ), + // ); + // } + // return c; + // }) + // : [], + // ); - if (categories.length > 5) { - throw new Error( - i18n.__( - translationErrorMessagesKeys.CATEGORIES_LENGTH_SHOULD_NOT_BE_MORE_THAN_FIVE, - ), - ); - } + // if (categories.length > 5) { + // throw new Error( + // i18n.__( + // translationErrorMessagesKeys.CATEGORIES_LENGTH_SHOULD_NOT_BE_MORE_THAN_FIVE, + // ), + // ); + // } const abcLauncherAdapter = getAbcLauncherAdapter(); const abc = await abcLauncherAdapter.getProjectAbcLaunchData( @@ -1391,7 +1395,7 @@ export class ProjectResolver { const project = Project.create({ ...projectInput, abc, - categories: categories as Category[], + categories: [], organization: organization as Organization, image, creationDate: now, diff --git a/src/resolvers/types/project-input.ts b/src/resolvers/types/project-input.ts index 473234f51..a6808207f 100644 --- a/src/resolvers/types/project-input.ts +++ b/src/resolvers/types/project-input.ts @@ -80,6 +80,10 @@ export class ProjectInput { @Field(() => [ProjectTeamMemberInput], { nullable: true }) teamMembers?: ProjectTeamMemberInput[]; + + @Field({ nullable: true }) + @MaxLength(IMAGE_LINK_MAX_SIZE) + icon?: string; } @InputType() diff --git a/test/graphqlQueries.ts b/test/graphqlQueries.ts index 9cd78c158..714fb51f7 100644 --- a/test/graphqlQueries.ts +++ b/test/graphqlQueries.ts @@ -98,6 +98,7 @@ export const createProjectQuery = ` listed reviewStatus verified + icon organization { id name