Skip to content

Commit

Permalink
Merge pull request #1292 from hngprojects/feat/unsubscribe-newsletter
Browse files Browse the repository at this point in the history
feat: unsubscribe newsletter
  • Loading branch information
TheCodeGhinux authored Feb 28, 2025
2 parents 010a3c0 + f8b88f5 commit 9ee304e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail } from 'class-validator';

export class UnsubscribeNewsletterDto {
@ApiProperty({ description: 'Email of the user to unsubscribe' })
@IsEmail()
email: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ export class NewsletterSubscription extends AbstractBaseEntity {

@DeleteDateColumn()
deletedAt: Date;

@Column({ default: false })
isUnsubscribed: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { skipAuth } from '@shared/helpers/skipAuth';
import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { NewsletterSubscriptionResponseDto } from './dto/newsletter-subscription.response.dto';
import { SuperAdminGuard } from '@guards/super-admin.guard';
import { UnsubscribeNewsletterDto } from './dto/unsubscribe-newsletter.dto';

@ApiTags('Newsletter Subscription')
@Controller('newsletter-subscription')
Expand Down Expand Up @@ -115,4 +116,14 @@ export class NewsletterSubscriptionController {
restore(@Param('id') id: string) {
return this.newsletterSubscriptionService.restore(id);
}

@Post('unsubscribe')
@skipAuth()
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Unsubscribe from the newsletter' })
@ApiResponse({ status: 200, description: 'User has been unsubscribed successfully.' })
@ApiResponse({ status: 404, description: 'Email not found' })
unsubscribe(@Body() unsubscribeDto: UnsubscribeNewsletterDto) {
return this.newsletterSubscriptionService.unsubscribe(unsubscribeDto.email);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,17 @@ export class NewsletterSubscriptionService {
email: newsletterSubscription.email,
};
}

async unsubscribe(email: string) {
const subscription = await this.newsletterSubscriptionRepository.findOne({ where: { email } });

if (!subscription) {
throw new NotFoundException(`Email ${email} not found in the subscription list`);
}

subscription.isUnsubscribed = true;
await this.newsletterSubscriptionRepository.save(subscription);

return { message: `Email ${email} has been unsubscribed successfully` };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,47 @@ describe('NewsletterService', () => {
await expect(service.restore(id)).rejects.toThrow(NotFoundException);
});
});

describe('unsubscribe', () => {
it('should successfully unsubscribe a user', async () => {
const email = '[email protected]';
const mockSubscription = { id: '1', email, isUnsubscribed: false } as NewsletterSubscription;

// Mock `findOne` to return a subscribed user
jest.spyOn(repository, 'findOne').mockResolvedValue(mockSubscription);
// Mock `save` to return updated object
jest.spyOn(repository, 'save').mockImplementation(
async sub =>
({
...sub,
isUnsubscribed: true,
email: sub.email,
deletedAt: sub.deletedAt || new Date(),
id: sub.id,
created_at: sub.created_at || new Date(),
updated_at: new Date(),
}) as NewsletterSubscription
);

const result = await service.unsubscribe(email);
expect(result).toEqual({ message: `Email ${email} has been unsubscribed successfully` });

// Ensure `isUnsubscribed` was updated
expect(repository.save).toHaveBeenCalledWith(expect.objectContaining({ isUnsubscribed: true }));
});

it('should throw NotFoundException if email is not found', async () => {
const email = '[email protected]';

// Mock `findOne` to return null
jest.spyOn(repository, 'findOne').mockResolvedValue(null);

// Expecting an error
await expect(service.unsubscribe(email)).rejects.toThrow(
new NotFoundException(`Email ${email} not found in the subscription list`)
);

expect(repository.findOne).toHaveBeenCalledWith({ where: { email } });
});
});
});

0 comments on commit 9ee304e

Please sign in to comment.