Skip to content

Commit

Permalink
Merge pull request #1752 from Giveth/feat/issue-1519
Browse files Browse the repository at this point in the history
feat: add endpoint to delete draft project
  • Loading branch information
Reshzera authored Aug 12, 2024
2 parents 34a615d + d0a7ccd commit bbdb457
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 2 deletions.
110 changes: 108 additions & 2 deletions src/repositories/projectRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,33 @@ import {
findProjectsByIdArray,
findProjectsBySlugArray,
projectsWithoutUpdateAfterTimeFrame,
removeProjectAndRelatedEntities,
updateProjectWithVerificationForm,
verifyMultipleProjects,
verifyProject,
} from './projectRepository';
import {
createDonationData,
createProjectData,
generateRandomEtheriumAddress,
saveAnchorContractDirectlyToDb,
saveDonationDirectlyToDb,
saveProjectDirectlyToDb,
saveUserDirectlyToDb,
} from '../../test/testUtils';
import { createProjectVerificationForm } from './projectVerificationRepository';
import { PROJECT_VERIFICATION_STATUSES } from '../entities/projectVerificationForm';
import {
PROJECT_VERIFICATION_STATUSES,
ProjectVerificationForm,
} from '../entities/projectVerificationForm';
import { NETWORK_IDS } from '../provider';
import { setPowerRound } from './powerRoundRepository';
import { refreshProjectPowerView } from './projectPowerViewRepository';
import {
insertSinglePowerBoosting,
takePowerBoostingSnapshot,
} from './powerBoostingRepository';
import { Project } from '../entities/project';
import { Project, ProjectUpdate } from '../entities/project';
import { User } from '../entities/user';
import { PowerBalanceSnapshot } from '../entities/powerBalanceSnapshot';
import { PowerBoostingSnapshot } from '../entities/powerBoostingSnapshot';
Expand All @@ -37,6 +44,15 @@ import { getHtmlTextSummary } from '../utils/utils';
import { generateRandomString } from '../utils/utils';
import { addOrUpdatePowerSnapshotBalances } from './powerBalanceSnapshotRepository';
import { findPowerSnapshots } from './powerSnapshotRepository';
import { AnchorContractAddress } from '../entities/anchorContractAddress';
import { Donation } from '../entities/donation';
import { FeaturedUpdate } from '../entities/featuredUpdate';
import { ProjectAddress } from '../entities/projectAddress';
import { ProjectSocialMedia } from '../entities/projectSocialMedia';
import { ProjectStatusHistory } from '../entities/projectStatusHistory';
import { Reaction } from '../entities/reaction';
import { SocialProfile } from '../entities/socialProfile';
import { ProjectSocialMediaType } from '../types/projectSocialMediaType';

describe(
'findProjectByWalletAddress test cases',
Expand Down Expand Up @@ -71,6 +87,11 @@ describe(
findProjectsBySlugArrayTestCases,
);

describe(
'removeProjectAndRelatedEntities test cases',
removeProjectAndRelatedEntitiesTestCase,
);

function projectsWithoutUpdateAfterTimeFrameTestCases() {
it('should return projects created a long time ago', async () => {
const superExpiredProject = await saveProjectDirectlyToDb({
Expand Down Expand Up @@ -498,3 +519,88 @@ function updateDescriptionSummaryTestCases() {
);
});
}

function removeProjectAndRelatedEntitiesTestCase() {
it('should remove project and related entities', async () => {
const user = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const projectData = createProjectData();
projectData.adminUserId = user.id;
//It creates a project, projectUpdate, and ProjectAddress
const project = await saveProjectDirectlyToDb(projectData);

await Promise.all([
saveDonationDirectlyToDb(
{
...createDonationData(),
},
user.id,
project.id,
),
saveAnchorContractDirectlyToDb({
creatorId: user.id,
projectId: project.id,
}),
Reaction.create({
projectId: project.id,
userId: user.id,
reaction: '',
}).save(),
ProjectSocialMedia.create({
projectId: project.id,
type: ProjectSocialMediaType.FACEBOOK,
link: 'https://facebook.com',
}).save(),
ProjectStatusHistory.create({
projectId: project.id,
createdAt: new Date(),
}).save(),
ProjectVerificationForm.create({ projectId: project.id }).save(),
FeaturedUpdate.create({ projectId: project.id }).save(),
SocialProfile.create({ projectId: project.id }).save(),
]);

const relatedEntitiesBefore = await Promise.all([
Donation.findOne({ where: { projectId: project.id } }),
Reaction.findOne({ where: { projectId: project.id } }),
ProjectAddress.findOne({ where: { projectId: project.id } }),
ProjectSocialMedia.findOne({ where: { projectId: project.id } }),
AnchorContractAddress.findOne({ where: { projectId: project.id } }),
ProjectStatusHistory.findOne({ where: { projectId: project.id } }),
ProjectVerificationForm.findOne({
where: { projectId: project.id },
}),
FeaturedUpdate.findOne({ where: { projectId: project.id } }),
SocialProfile.findOne({ where: { projectId: project.id } }),
ProjectUpdate.findOne({ where: { projectId: project.id } }),
]);

relatedEntitiesBefore.forEach(entity => {
assert.isNotNull(entity);
});

await removeProjectAndRelatedEntities(project.id);

const relatedEntities = await Promise.all([
Donation.findOne({ where: { projectId: project.id } }),
Reaction.findOne({ where: { projectId: project.id } }),
ProjectAddress.findOne({ where: { projectId: project.id } }),
ProjectSocialMedia.findOne({ where: { projectId: project.id } }),
AnchorContractAddress.findOne({ where: { projectId: project.id } }),
ProjectStatusHistory.findOne({ where: { projectId: project.id } }),
ProjectVerificationForm.findOne({
where: { projectId: project.id },
}),
FeaturedUpdate.findOne({ where: { projectId: project.id } }),
SocialProfile.findOne({ where: { projectId: project.id } }),
ProjectUpdate.findOne({ where: { projectId: project.id } }),
]);

const fetchedProject = await Project.findOne({ where: { id: project.id } });

assert.isNull(fetchedProject);

relatedEntities.forEach(entity => {
assert.isNull(entity);
});
});
}
68 changes: 68 additions & 0 deletions src/repositories/projectRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { UpdateResult } from 'typeorm';
import {
FilterField,
Project,
ProjectUpdate,
ProjStatus,
ReviewStatus,
RevokeSteps,
Expand All @@ -14,6 +15,13 @@ import { publicSelectionFields } from '../entities/user';
import { ResourcesTotalPerMonthAndYear } from '../resolvers/donationResolver';
import { OrderDirection, ProjectResolver } from '../resolvers/projectResolver';
import { getAppropriateNetworkId } from '../services/chains';
import { AnchorContractAddress } from '../entities/anchorContractAddress';
import { Donation } from '../entities/donation';
import { FeaturedUpdate } from '../entities/featuredUpdate';
import { ProjectSocialMedia } from '../entities/projectSocialMedia';
import { ProjectStatusHistory } from '../entities/projectStatusHistory';
import { Reaction } from '../entities/reaction';
import { SocialProfile } from '../entities/socialProfile';

export const findProjectById = (projectId: number): Promise<Project | null> => {
// return Project.findOne({ id: projectId });
Expand Down Expand Up @@ -533,3 +541,63 @@ export const findProjectsBySlugArray = async (
});
return projects;
};

export const removeProjectAndRelatedEntities = async (
projectId: number,
): Promise<void> => {
// Delete related entities
await Donation.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await Reaction.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await ProjectAddress.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await ProjectSocialMedia.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await AnchorContractAddress.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await ProjectStatusHistory.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await ProjectVerificationForm.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await FeaturedUpdate.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await SocialProfile.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await ProjectUpdate.createQueryBuilder()
.delete()
.where('projectId = :projectId', { projectId })
.execute();

await Project.createQueryBuilder()
.delete()
.where('id = :id', { id: projectId })
.execute();
};
113 changes: 113 additions & 0 deletions src/resolvers/projectResolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
addRecipientAddressToProjectQuery,
createProjectQuery,
deactivateProjectQuery,
deleteDraftProjectQuery,
deleteProjectUpdateQuery,
editProjectUpdateQuery,
fetchFeaturedProjects,
Expand Down Expand Up @@ -174,6 +175,8 @@ describe(

describe('projectsPerDate() test cases --->', projectsPerDateTestCases);

describe('deleteDraftProject test cases --->', deleteDraftProjectTestCases);

function projectsPerDateTestCases() {
it('should projects created in a time range', async () => {
await saveProjectDirectlyToDb({
Expand Down Expand Up @@ -5668,3 +5671,113 @@ function deleteProjectUpdateTestCases() {
);
});
}

function deleteDraftProjectTestCases() {
it('should delete draft project successfully ', async () => {
const user = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const accessToken = await generateTestAccessToken(user.id);
const project = await saveProjectDirectlyToDb({
...createProjectData(),
adminUserId: user.id,
statusId: ProjStatus.drafted,
});

const result = await axios.post(
graphqlUrl,
{
query: deleteDraftProjectQuery,
variables: {
projectId: project.id,
},
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
);
assert.equal(result.data.data.deleteDraftProject, true);
});
it('should can not delete draft project because of ownerShip ', async () => {
const user = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const user1 = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const project = await saveProjectDirectlyToDb({
...createProjectData(),
adminUserId: user.id,
statusId: ProjStatus.drafted,
});
const accessTokenUser1 = await generateTestAccessToken(user1.id);

// Add projectUpdate with accessToken user1
const result = await axios.post(
graphqlUrl,
{
query: deleteDraftProjectQuery,
variables: {
projectId: project.id,
},
},
{
headers: {
Authorization: `Bearer ${accessTokenUser1}`,
},
},
);
assert.equal(
result.data.errors[0].message,
errorMessages.YOU_ARE_NOT_THE_OWNER_OF_PROJECT,
);
});
it('should can not delete draft project because of not found project ', async () => {
const user = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const accessToken = await generateTestAccessToken(user.id);
const projectCount = await Project.count();
const result = await axios.post(
graphqlUrl,
{
query: deleteDraftProjectQuery,
variables: {
projectId: Number(projectCount + 10),
},
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
);
assert.equal(
result.data.errors[0].message,
errorMessages.PROJECT_NOT_FOUND,
);
});

it('should can not delete draft project because status ', async () => {
const user = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const accessToken = await generateTestAccessToken(user.id);
const project = await saveProjectDirectlyToDb({
...createProjectData(),
adminUserId: user.id,
statusId: ProjStatus.active,
});

const result = await axios.post(
graphqlUrl,
{
query: deleteDraftProjectQuery,
variables: {
projectId: project.id,
},
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
);
assert.equal(
result.data.errors[0].message,
errorMessages.ONLY_DRAFTED_PROJECTS_CAN_BE_DELETED,
);
});
}
Loading

0 comments on commit bbdb457

Please sign in to comment.