Skip to content

Commit

Permalink
Post creation and getting all posts work well
Browse files Browse the repository at this point in the history
  • Loading branch information
devbenho committed Jun 20, 2024
1 parent 37e6270 commit 658835e
Show file tree
Hide file tree
Showing 20 changed files with 331 additions and 133 deletions.
Binary file modified server/db.sqlite3
Binary file not shown.
25 changes: 13 additions & 12 deletions server/src/application/post/create/create-post.request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { UseCaseRequest } from '@application/shared';
import { Post, User } from '@domain/entities';
import { POST_STATUS } from '@domain/entities/posts/post-status.enum';
import { TriggeredBy } from '@domain/shared/entities/triggered-by';
import { UploadedFiles } from '@domain/shared/models';
import { InvalidParameterException } from '@domain/shared/exceptions';
Expand All @@ -9,23 +7,24 @@ class CreatePostRequest extends UseCaseRequest {
readonly title: string;
readonly content: string;
readonly authorId: string;
readonly author: User;
// readonly author: User;
readonly attachments: UploadedFiles[];
readonly status: POST_STATUS;
readonly status: string;

// Constructor Section
constructor(
triggeredBy: TriggeredBy,
title: string,
content: string,
author: User,
authorId: string,
// author: User,
attachments: UploadedFiles[],
status: POST_STATUS = POST_STATUS.DRAFT,
status: string = 'draft',
) {
super(triggeredBy);
this.title = title;
this.content = content;
this.author = author;
// this.author = author;
this.authorId = authorId;
this.attachments = attachments;
this.status = status;
}
Expand All @@ -34,23 +33,25 @@ class CreatePostRequest extends UseCaseRequest {
triggeredBy: TriggeredBy,
title: string,
content: string,
author: User,
authorId: string,
// author: User,
attachments: UploadedFiles[],
status: POST_STATUS = POST_STATUS.DRAFT,
status: string = 'draft',
): CreatePostRequest {
return new CreatePostRequest(
triggeredBy,
title,
content,
author,
authorId,
// author,
attachments,
status,
);
}

// Validate here using EnsureClass
protected validatePayload(): void {
if (!this.title || !this.content || !this.triggeredBy.who || !this.author) {
if (!this.title || !this.content || !this.triggeredBy.who || !this.authorId || !this.attachments || !this.status) {
throw new InvalidParameterException('Invalid request');
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import { BaseUseCase, UseCase } from '@application/shared';
import { inject, injectable } from 'inversify';
import { TYPES } from '@infrastructure/shared/ioc/types';
import { PostRepository } from '@domain/entities/posts/post.repository';
import { PostDetailsResponseDto } from '@contracts/dtos/posts/post-details.response';
import { log } from 'console';
import { CreatePostRequest } from './create-post.request';
import { Post } from '@domain/entities';
import { Logger } from '@domain/shared';

@UseCase()
class CreatePostUseCase extends BaseUseCase<
CreatePostRequest,
PostDetailsResponseDto
> {
private readonly _postRepository: PostRepository;

constructor(
@inject(TYPES.IPostRepository) private _postRepository: PostRepository,
postRepository: PostRepository,
) {
super();
this._postRepository = postRepository;
}


public async performOperation(
request: CreatePostRequest,
): Promise<PostDetailsResponseDto> {
Expand All @@ -26,19 +28,17 @@ class CreatePostUseCase extends BaseUseCase<
request.title,
request.content,
request.authorId,
request.author,
null,
[],
[],
request.status,
new Date(),
null,
null,
);

Logger.info('CreatePostUseCase.performOperation', post);
const createdPost = await this._postRepository.createPost(post);

log('created post is', createdPost);

Logger.info('Done', createdPost);
if (createdPost) {
return PostDetailsResponseDto.fromEntity(createdPost);
}
Expand Down
2 changes: 1 addition & 1 deletion server/src/application/post/create/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './create-post.usecase';
export * from './create-post.use-case';
export * from './create-post.request';
25 changes: 15 additions & 10 deletions server/src/application/post/find-all/find-all-post.usecase.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,38 @@
import { BaseUseCase } from '@application/shared';
import { BaseUseCase, UseCase } from '@application/shared';
import { FindAllPostRequest } from './find-all-post.request';
import { PostResponseDto } from '@contracts/dtos/posts';
import { TYPES } from '@infrastructure/shared/ioc/types';
import { PostRepository } from '@domain/entities/posts/post.repository';
import { inject } from 'inversify';
import { log } from 'console';
import { Logger } from '@domain/shared';

@UseCase()
class FindAllPostUseCase extends BaseUseCase<
FindAllPostRequest,
PostResponseDto[]
> {
constructor(
@inject(TYPES.IPostRepository)
private readonly _postRepository: PostRepository,
) {
private readonly _postRepository: PostRepository;

constructor(postRepository: PostRepository) {
super();
this._postRepository = postRepository;
}

public async performOperation(
request: FindAllPostRequest,
): Promise<PostResponseDto[]> {
Logger.info('FindAllPostUseCase.performOperation');
const { pageSize, pageNumber } = request;
const posts = await this._postRepository.findAll(pageSize, pageNumber);
log('posts from use-case', posts);
const posts = await this._postRepository.findAll(
pageSize || 10,
pageNumber || 1,
);

Logger.info('posts from usecase', posts);
const postDtos = await Promise.all(
posts.map(async post => {
return await PostResponseDto.fromEntity(post);
}),
);
Logger.info('postsDtos from usecase', postDtos);

return postDtos;
}
Expand Down
4 changes: 3 additions & 1 deletion server/src/contracts/dtos/posts/post-details.response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ export class PostDetailsResponseDto {
public id: string,
public title: string,
public content: string,
public authorId: string,
public author: UserResponseDto,
public createdAt: Date,
public lastModifiedAt: Nullable<Date>,
) {}
) { }

public static fromEntity(entity: Post): PostDetailsResponseDto {
return new PostDetailsResponseDto(
entity.id ?? '',
entity.title,
entity.content,
entity.authorId ?? '',
UserResponseDto.fromEntity(entity.author ?? ({} as any)),
entity.createdAt,
entity.updatedAt,
Expand Down
6 changes: 5 additions & 1 deletion server/src/contracts/dtos/posts/post.response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@ export class PostResponseDto {
public id: Nullable<string>,
public title: string,
public content: string,
public authorId: string,
public author: UserResponseDto,
public comments: CommentResponseDto[],
public status: string,
public createdAt: Date,
public lastModifiedAt: Nullable<Date>,
) {}
) { }

public static async fromEntity(entity: Post): Promise<PostResponseDto> {
return new PostResponseDto(
entity.id,
entity.title,
entity.content,
entity.authorId,
UserResponseDto.fromEntity(entity.author as any),
entity.comments ? entity.comments.map(CommentResponseDto.fromEntity) : [],
entity.status,
entity.createdAt,
entity.updatedAt,
);
Expand Down
30 changes: 29 additions & 1 deletion server/src/domain/entities/posts/post-status.enum.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
import { InvalidParameterException } from "@domain/shared/exceptions";
import { EnumValueObject } from "@domain/shared/value-object/enum-value-object";

enum POST_STATUS {
DRAFT = 'draft',
PUBLISHED = 'published',
}

export { POST_STATUS };
class PostStatus extends EnumValueObject<POST_STATUS> {
protected throwErrorForInvalidValue(value: POST_STATUS): void {
throw new InvalidParameterException(`The status ${value} is invalid`);
}
constructor(value: POST_STATUS) {
super(value, Object.values(POST_STATUS));
}

public static fromValue(value: string): PostStatus {
switch (value) {
case POST_STATUS.DRAFT: {
return new PostStatus(POST_STATUS.DRAFT);
}
case POST_STATUS.PUBLISHED: {
return new PostStatus(POST_STATUS.PUBLISHED);
}
default: {
throw new Error(`The status ${value} is invalid`);
}
}
}
}



export { PostStatus };
5 changes: 2 additions & 3 deletions server/src/domain/entities/posts/post.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { AuditableBaseEntity } from '@domain/shared/auditable.entity';
import { Nullable } from '@domain/shared/types';
import { POST_STATUS } from '@domain/entities/posts/post-status.enum';
import { User, Comment, LikePost } from '..';

class Post extends AuditableBaseEntity {
Expand All @@ -12,7 +11,7 @@ class Post extends AuditableBaseEntity {
public author: Nullable<User>,
public likes: LikePost[],
public comments: Comment[],
public status: POST_STATUS = POST_STATUS.DRAFT,
public status: string = 'draft',
public createdAt: Date,
public updatedAt: Nullable<Date>,
public deletedAt: Nullable<Date>,
Expand All @@ -28,7 +27,7 @@ class Post extends AuditableBaseEntity {
author: Nullable<User>,
likes: LikePost[],
comments: Comment[],
status: POST_STATUS,
status: string,
createdAt: Date,
updatedAt: Nullable<Date>,
deletedAt: Nullable<Date>,
Expand Down
13 changes: 9 additions & 4 deletions server/src/infrastructure/posts/post.mapper.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { PostPersistence } from '@infrastructure/posts';
import { POST_STATUS } from '@domain/entities/posts/post-status.enum';
import { Post } from '@domain/entities';
import { UserMapper, UserPersistence } from '@infrastructure/users';
import { CommentMapper, CommentPersistence } from '@infrastructure/comments';
import {
LikePostMapper,
LikePostPersistence,
} from '@infrastructure/like-posts';
import { Logger } from '@domain/shared';

class PostMapper {
public static toDomain(
Expand All @@ -28,7 +28,11 @@ class PostMapper {
CommentMapper.toDomain(comment),
);
const postStatus =
POST_STATUS[persistence.status.toUpperCase() as keyof typeof POST_STATUS];
persistence.status === 'draft'
? 'draft'
: persistence.status === 'published'
? 'published'
: 'archived';

return Post.create(
persistence.id,
Expand All @@ -46,6 +50,7 @@ class PostMapper {
}

public static toPersistence(domainPost: Post): PostPersistence {
Logger.info('PostMapper.toPersistence', domainPost);
const postPersistence = new PostPersistence();

if (domainPost.id) {
Expand All @@ -56,7 +61,7 @@ class PostMapper {
postPersistence.content = domainPost.content;
postPersistence.authorId = domainPost.authorId;

postPersistence.status = domainPost.status.toLowerCase(); //TODO: Refactor this
postPersistence.status = domainPost.status.toString(); //TODO: Refactor this
postPersistence.createdAt = domainPost.createdAt;
postPersistence.deletedAt = domainPost.deletedAt;

Expand All @@ -74,7 +79,7 @@ class PostMapper {
postPersistence.comments = Promise.all(
domainPost.comments.map(CommentMapper.toPersistence),
);

Logger.info('PostMapper.toPersistence done', postPersistence);
return postPersistence;
}
}
Expand Down
2 changes: 2 additions & 0 deletions server/src/infrastructure/posts/post.persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CommentPersistence } from '@infrastructure/comments/';
import { UserPersistence } from '@infrastructure/users';
import { LikePostPersistence } from '@infrastructure/like-posts/';
import { Nullable } from '@domain/shared/types';
import { Default } from '@tsed/schema';

@Entity()
class PostPersistence {
Expand Down Expand Up @@ -53,6 +54,7 @@ class PostPersistence {

// add status column enum ['draft', 'published', 'deleted']
@Column()
@Default('draft')
status: string;
}

Expand Down
6 changes: 6 additions & 0 deletions server/src/infrastructure/posts/post.repository.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PostPersistence } from './post.persistence';
import { PostMapper } from './post.mapper';
import { appDataSource } from '@infrastructure/shared/persistence/data-source';
import { RepositoryDec } from '@infrastructure/shared/persistence/repository.decorator';
import { Logger } from '@domain/shared';

@RepositoryDec({ type: PostRepository })
export class PostRepositoryImp implements PostRepository {
Expand All @@ -18,7 +19,9 @@ export class PostRepositoryImp implements PostRepository {
}

async createPost(post: Post): Promise<Post> {
Logger.info('PostRepositoryImp.createPost', post);
const postPersistence = PostMapper.toPersistence(post);
Logger.info('PostRepositoryImp.createPost', postPersistence);
const createdPost = await this._repository.save(postPersistence);

return PostMapper.toDomain(createdPost, {
Expand Down Expand Up @@ -53,7 +56,10 @@ export class PostRepositoryImp implements PostRepository {
}

async findAll(limit: number, page: number): Promise<Post[]> {
Logger.info('PostRepositoryImp.findAll');
const [posts, count] = await this._repository.findAndCount();

Logger.info('posts from repo', posts);
const postPromises = posts.map(async post =>
PostMapper.toDomain(post, {
author: await post.author,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const GlobalConfig = Object.freeze({

JWT_SECRET: getEnvironmentString('JWT_SECRET', 'jwtSecretPassphrase'),

JWT_EXPIRATION: getEnvironmentNumber('JWT_EXPIRATION', 1),
JWT_EXPIRATION: getEnvironmentNumber('JWT_EXPIRATION', 2),

JWT_REFRESH_EXPIRATION: getEnvironmentNumber('JWT_REFRESH_EXPIRATION', 6),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class AuthController {
const authenticatedUser = await this._loginUseCase.execute(
AuthRequest.create(triggeredBy, username, password),
);

return UserSuccessfullyAuthenticatedApiResponse.create(
authenticatedUser.userDetails.id as string,
username,
Expand Down
Loading

0 comments on commit 658835e

Please sign in to comment.