Skip to content

Commit

Permalink
feat(profiles): implement profile use cases
Browse files Browse the repository at this point in the history
  • Loading branch information
havrydotdev committed Oct 18, 2023
1 parent 99c86d5 commit ffe1417
Show file tree
Hide file tree
Showing 23 changed files with 177 additions and 37 deletions.
Binary file modified dev.sqlite
Binary file not shown.
1 change: 1 addition & 0 deletions src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './app.update';
export * from './register.wizard';
50 changes: 35 additions & 15 deletions src/controllers/register.wizard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Ctx, Message, On, Wizard, WizardStep } from 'nestjs-telegraf';
import { Game } from 'src/core';
import { Game, User } from 'src/core';
import { REGISTER_WIZARD_ID } from 'src/core/constants';
import { Language } from 'src/core/enums';
import { GameUseCases } from 'src/use-cases/game';
import { ReplyUseCases } from 'src/use-cases/reply';
import { UserUseCases } from 'src/use-cases/user';
Expand All @@ -18,6 +19,7 @@ export class RegisterWizard {
private readonly gameUseCases: GameUseCases,
) {
this.gameUseCases.findAll().then((games: Game[]) => {
console.log(games);
this.games = games;
});
}
Expand Down Expand Up @@ -75,7 +77,7 @@ export class RegisterWizard {

ctx.wizard.next();

await this.replyUseCases.sendGames(ctx);
await this.replyUseCases.sendGames(ctx, this.games);
}

@On('text')
Expand All @@ -87,6 +89,8 @@ export class RegisterWizard {
if (msg.text === '✅') {
ctx.wizard.next();

await this.replyUseCases.sendPicture(ctx);

return;
}

Expand All @@ -97,18 +101,30 @@ export class RegisterWizard {
return;
}

if (ctx.wizard.state['games']?.includes(game.id)) {
await this.replyUseCases.invalidGame(ctx);

return;
}

if (!ctx.wizard.state['games']) {
ctx.wizard.state['games'] = [];
}

ctx.wizard.state['games'].push(game.id);

await this.replyUseCases.sendPicture(ctx);
await this.replyUseCases.gameAdded(ctx);
}

@On('photo')
@On('message')
@WizardStep(6)
async onPhoto(
@Ctx()
ctx: Context & WizardContext,
@Message() msg: MessageType.PhotoMessage,
) {
if (msg.photo.length === 0) {
}
const imageId = msg.photo.pop().file_id;

ctx.wizard.state['photo'] = imageId;
Expand All @@ -119,18 +135,22 @@ export class RegisterWizard {
@WizardStep(7)
async onDone(
@Ctx()
ctx: Context &
WizardContext & {
wizard: {
state: {
name: string;
location: string;
age: number;
games: number[];
};
ctx: WizardContext & {
session: {
user?: User;
lang: Language;
};
} & {
wizard: {
state: {
name: string;
location: string;
age: number;
games: number[];
};
},
};
},
) {
console.log(ctx.wizard.state);
await ctx.scene.leave();
}
}
6 changes: 3 additions & 3 deletions src/core/abstracts/profile.abstract.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Profile } from '../entities';

abstract class IProfileService {
abstract createProfile(profile: Profile): Promise<void>;
abstract createProfile(profile: Profile): Promise<Profile>;

abstract updateProfile(profileId: number, profile: Profile): Promise<void>;
abstract updateProfile(profileId: number, profile: Profile): Promise<Profile>;

abstract deleteProfile(profileId: number): Promise<void>;

abstract findByUser(userId: number): Promise<Profile>;

abstract findRecommended(user: Profile, skip: number): Promise<void>;
abstract findRecommended(user: Profile, skip: number): Promise<Profile>;
}

export { IProfileService };
4 changes: 3 additions & 1 deletion src/core/dtos/profile.dto.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { autoImplement } from '../utils';

class CreateProfileDto {
userId: number;

Expand All @@ -12,6 +14,6 @@ class CreateProfileDto {
games: number[];
}

class UpdateProfileDto implements Partial<CreateProfileDto> {}
class UpdateProfileDto extends autoImplement<Partial<CreateProfileDto>>() {}

export { CreateProfileDto, UpdateProfileDto };
4 changes: 3 additions & 1 deletion src/core/dtos/user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { autoImplement } from '../utils';

class CreateUserDto {
chatId: number;
userId: number;
}

class UpdateUserDto implements Partial<CreateUserDto> {}
class UpdateUserDto extends autoImplement<Partial<CreateUserDto>>() {}

export { CreateUserDto, UpdateUserDto };
2 changes: 1 addition & 1 deletion src/core/entities/game.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Game extends IEntity {
@Column()
title: string;

@ManyToMany(() => Profile, (profile) => profile.game)
@ManyToMany(() => Profile, (profile) => profile.games)
profiles: Profile[];
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/entities/profile.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Profile extends IEntity {
user: User;

@ManyToMany(() => Game, (game) => game.profiles)
game: Game[];
games: Game[];
}

export { Profile };
1 change: 1 addition & 0 deletions src/core/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './partial';
5 changes: 5 additions & 0 deletions src/core/utils/partial.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function autoImplement<T>(): new () => T {
return class {} as any;
}

export { autoImplement };
6 changes: 5 additions & 1 deletion src/frameworks/game/typeorm/typeorm-game.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export class TypeOrmGameService implements IGameService {
) {}

async findAll(): Promise<Game[]> {
return this.gameRepo.find();
return this.gameRepo.find({
order: {
created_at: 'DESC',
},
});
}
}
17 changes: 11 additions & 6 deletions src/frameworks/profile/typeorm/typeorm-profile.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,29 @@ export class TypeOrmProfileService implements IProfileService {
});
}

async createProfile(profile: Profile): Promise<void> {
await this.profileRepo.insert(profile);
async createProfile(profile: Profile): Promise<Profile> {
return this.profileRepo.save(profile);
}

async updateProfile(profileId: number, profile: Profile): Promise<void> {
await this.profileRepo.update(profileId, profile);
async updateProfile(profileId: number, profile: Profile): Promise<Profile> {
return await this.profileRepo.save({
id: profileId,
...profile,
});
}

async deleteProfile(profileId: number): Promise<void> {
await this.profileRepo.delete(profileId);
}

// TODO
async findRecommended(user: Profile, skip: number): Promise<void> {
await this.profileRepo.find({
async findRecommended(user: Profile, skip: number): Promise<Profile> {
const result = await this.profileRepo.find({
skip,
take: 1,
order: {},
});

return result[0];
}
}
1 change: 1 addition & 0 deletions src/generated/i18n.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type I18nTranslations = {
"send_location": string;
"send_games": string;
"invalid_game": string;
"game_added": string;
};
};
export type I18nPath = Path<I18nTranslations>;
3 changes: 2 additions & 1 deletion src/i18n/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"send_picture": "Send photo for your profile",
"send_location": "Send city you live in",
"send_games": "Send games you play",
"invalid_game": "Please, enter valid game"
"invalid_game": "Please, enter valid game",
"game_added": "Game added"
}
3 changes: 2 additions & 1 deletion src/i18n/ru/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"send_picture": "пішовнахуйпішовнахуйпішовнахуй",
"send_location": "пішовнахуйпішовнахуйпішовнахуй",
"send_games": "пішовнахуйпішовнахуйпішовнахуй",
"invalid_game": "пішовнахуйпішовнахуйпішовнахуй"
"invalid_game": "пішовнахуйпішовнахуйпішовнахуй",
"game_added": "пішовнахуйпішовнахуйпішовнахуй"
}
3 changes: 2 additions & 1 deletion src/i18n/ua/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"send_picture": "Тепер, надішли мені фото для твого профілю",
"send_location": "Введи назву населенного пункту, в якому ти живеш",
"send_games": "Майже готово! Тепер, обери ігри, в які ти граєш",
"invalid_game": "Ця гра не існує або не підтримується"
"invalid_game": "Ця гра не існує або не підтримується",
"game_added": "Гра додана"
}
2 changes: 1 addition & 1 deletion src/services/database/database.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
host: config.get<string>('DB_HOST'),
password: config.get<string>('DB_PASSWORD'),
synchronize: config.get<string>('DB_SYNCHRONIZE') === 'true',
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
entities: [__dirname + '../../../core/entities/*{.js,.ts}'],
};
},
inject: [ConfigService],
Expand Down
8 changes: 8 additions & 0 deletions src/services/profile/profile.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { TypeOrmProfileModule } from 'src/frameworks/profile/typeorm';

@Module({
imports: [TypeOrmProfileModule],
exports: [TypeOrmProfileModule],
})
export class ProfileModule {}
2 changes: 1 addition & 1 deletion src/use-cases/game/game.use-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ export class GameUseCases {
constructor(private readonly gameService: IGameService) {}

async findAll() {
return await this.gameService.findAll();
return this.gameService.findAll();
}
}
25 changes: 25 additions & 0 deletions src/use-cases/profile/profile-factory.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Injectable } from '@nestjs/common';
import { CreateProfileDto, Profile, UpdateProfileDto } from 'src/core';

@Injectable()
export class ProfileFactoryService {
create(dto: CreateProfileDto): Profile {
return Profile.create({
...dto,
user: {
id: dto.userId,
},
games: dto.games.map((gameId) => ({ id: gameId })),
});
}

update(dto: UpdateProfileDto): Profile {
return Profile.create({
...dto,
user: {
id: dto.userId,
},
games: dto.games.map((gameId) => ({ id: gameId })),
});
}
}
11 changes: 11 additions & 0 deletions src/use-cases/profile/profile.use-case.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { ProfileModule } from 'src/services/profile/profile.module';
import { ProfileUseCases } from './profile.use-case';
import { ProfileFactoryService } from './profile-factory.service';

@Module({
imports: [ProfileModule],
providers: [ProfileUseCases, ProfileFactoryService],
exports: [ProfileUseCases],
})
export class ProfileUseCasesModule {}
37 changes: 37 additions & 0 deletions src/use-cases/profile/profile.use-case.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Injectable } from '@nestjs/common';
import { CreateProfileDto, IProfileService } from 'src/core';
import { ProfileFactoryService } from './profile-factory.service';

@Injectable()
export class ProfileUseCases {
constructor(
private readonly profileService: IProfileService,
private readonly profileFactory: ProfileFactoryService,
) {}

async findByUser(userId: number) {
return this.profileService.findByUser(userId);
}

async createProfile(dto: CreateProfileDto) {
const profile = this.profileFactory.create(dto);

return this.profileService.createProfile(profile);
}

async updateProfile(profileId: number, dto: CreateProfileDto) {
const profile = this.profileFactory.update(dto);

return this.profileService.updateProfile(profileId, profile);
}

async deleteProfile(profileId: number) {
return this.profileService.deleteProfile(profileId);
}

async findRecommended(userId: number, skip: number) {
const profile = await this.profileService.findByUser(userId);

return this.profileService.findRecommended(profile, skip);
}
}
21 changes: 18 additions & 3 deletions src/use-cases/reply/reply.use-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Context } from 'telegraf';
import { IReplyService } from 'src/core/abstracts/reply.abstract.service';
import { Markup } from 'telegraf';
import { ReplyKeyboardMarkup } from 'telegraf/typings/core/types/typegram';
import { Game } from 'src/core';

@Injectable()
export class ReplyUseCases {
Expand Down Expand Up @@ -90,14 +91,28 @@ export class ReplyUseCases {
}

async sendPicture(ctx: Context) {
await this.replyService.reply(ctx, 'messages.send_picture');
await this.replyService.reply(ctx, 'messages.send_picture', {
reply_markup: Markup.removeKeyboard().reply_markup,
});
}

async sendGames(ctx: Context) {
await this.replyService.reply(ctx, 'messages.send_games');
async sendGames(ctx: Context, games: Game[]) {
const reply_markup = Markup.keyboard(
games.map((game) => Markup.button.callback(game.title, game.title)),
).reply_markup;

reply_markup.resize_keyboard = true;

await this.replyService.reply(ctx, 'messages.send_games', {
reply_markup,
});
}

async invalidGame(ctx: Context) {
await this.replyService.reply(ctx, 'messages.invalid_game');
}

async gameAdded(ctx: Context) {
await this.replyService.reply(ctx, 'messages.game_added');
}
}

0 comments on commit ffe1417

Please sign in to comment.