Skip to content

Conversation

@laxman-aqw
Copy link
Collaborator

@laxman-aqw laxman-aqw commented Oct 27, 2025

  • Added URL module setup.

  • Implemented features to add and edit URLs.

  • Added a new column original_url in the urls table to:

  • Store the original (hashed) URL.

  • Prevent creation of duplicate URLs.

  • Integrated guards to ensure authenticated access for URL CRUD operations.

  • removed console

  • added errorhandler method to handle error

  • updated auth to allow user login only after verification

  • set expiry time in createurl

  • updated authguard to check userid

@laxman-aqw laxman-aqw added the enhancement New feature or request label Oct 27, 2025
@laxman-aqw laxman-aqw self-assigned this Oct 27, 2025
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@laxman-aqw Changes to Auth seems to be out of place for this PR. Any reason for the changes here?

@@ -0,0 +1,29 @@
// import {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to delete the file itself

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

CREATE TABLE "urls" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
"user_id" uuid NOT NULL,
"encrypted_url" varchar (2048) NOT NULL,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need encrypted_url ? Can it be reconstructed using short_code if needed ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the short_code is just a random identifier so i think we cannot.

@@ -0,0 +1,9 @@
import { IsNotEmpty } from 'class-validator';

export class CreateUrlRequestData {
Copy link
Collaborator

@arjandhakal arjandhakal Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The request also needs the expiry time that the user can set

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

@Req() request: RequestWithUser,
) {
const userData = request.decodedData;
if (!userData) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be part of validation pipeline, instead of manual check

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines 8 to 11
family: string;
major: string;
minor: string;
patch: string;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of repeating this can't we make a seperate interface for this and use it ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines 29 to 43
const existingUser = await this.userRepository.findOne({
where: [
{ username: signUpUserDto.username },
{ email: signUpUserDto.email },
],
});

if (userByUsername) {
throw new BadRequestException('Username already taken');
if (existingUser) {
if (existingUser.username === signUpUserDto.username) {
throw new BadRequestException('Username already taken');
}

if (existingUser.email === signUpUserDto.email) {
throw new BadRequestException('Email already taken');
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User creation shouldn't be within user's module ?

async createUser(payload: SignupRequestData){
 // here should be sign up logic
}

Should be called in auth service as follows :

private readonly userService:userService


this.userService.createUser()

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines 25 to 27
const user = await this.userRepository.findOneByOrFail({
id: url.userId,
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than calling injection repostiory for user here, better create a findUserById method in user service and call user service from here

Comment on lines 1 to 5
export class GetUrlRequestData {
title: string;
shortCode: string;
expiresAt: Date;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does get ` method have request data ? Is payload allowed in get ? or is it response data ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated it to response

@Req() req: RequestWithUser,
) {
const { longCode } = await this.urlService.getLongUrl(shortCode, req);
return { url: longCode, statusCode: 302 };

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a decorator to set http status in nest js , better use that above the method call. this is not a good approach

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

@Column({ type: 'uuid', name: 'user_id' })
readonly userId: string;

@Column({ type: 'varchar', length: 2048, name: 'encrypted_url' })

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you are unsure regarding the length you can use text type

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noted!

Copy link

@pratham-outside pratham-outside left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments added . Focus on seperation of concerns

const urls = (await this.urlRepository.find({
where: { userId: userId },
select: ['title', 'shortCode', 'expiresAt'],
})) as GetUrlRequestData[];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the type name . Also can't it be urls:GetUrlRequestData[]=
Another best way might be

const urls: Pick<Url,'title'|'shortCode'|'expiresAt'> 

instead a creating a new type.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines 128 to 129
if (deletedUrl.affected === 0) {
throw new NotFoundException('URL not found');
Copy link

@pratham-outside pratham-outside Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have checked existence of url above and you are again checking if url is there or not here. Doesn't seem logical .

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

if (value === undefined || value === null) {
throw new BadRequestException(`Invalid value for field: ${field}`);
}
if (value === undefined || value === null) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if(!value)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Time stamp on file and timestamp on migration class name doesn't match ????

where: { expiresAt: LessThan(new Date()), expiryAlertedAt: IsNull() },
});
for (const url of expiredUrls) {
const user = await this.userRepository.findOneByOrFail({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findOneByOrFail throws different error in local and in production . So better use findOne and then check validation if(!user)...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Copy link

@pratham-outside pratham-outside left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Development

Successfully merging this pull request may close these issues.

4 participants