Skip to content

Commit

Permalink
Task 1
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldever committed Sep 19, 2023
1 parent f7e94a6 commit ff2cbe9
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 31 deletions.
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
This repository contains a full-stack TypeScript application consisting of a NestJS backend and an Angular frontend.

Prerequisites:
- Docker or a locally running MySQL installation
- NodeJS 16+ (tested with v18.13.0)
- Code Editor (VSCode is recommended)

- Docker or a locally running MySQL installation
- NodeJS 16+ (tested with v18.13.0)
- Code Editor (VSCode is recommended)

Getting started:
- Install the dependencies `npx yarn install`.
- If you don't have a local MySQL installation, start one in docker: `docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=conduit -e MYSQL_DATABASE=conduit -e MYSQL_USER=conduit -e MYSQL_PASSWORD=conduit mysql:8.1`
- Adjust the `apps/backend/mikro-orm.config.ts` with your MySQL credentials (they already match the ones from the docker command above).
- Start the app (both backend and frontend at once): `npm start`.
- After the backend successfully starts, in a new terminal `npm run seed` to seed the database with some initial data.
- You can now access the UI at http://localhost:4200 and login with `[email protected]` / `password`.
- You can also find the backend API spec at http://localhost:3000/docs.

- Install the dependencies `npx yarn install`.
- If you don't have a local MySQL installation, start one in docker: `docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=conduit -e MYSQL_DATABASE=conduit -e MYSQL_USER=conduit -e MYSQL_PASSWORD=conduit mysql:8.1`
- Adjust the `apps/backend/mikro-orm.config.ts` with your MySQL credentials (they already match the ones from the docker command above).
- Start the app (both backend and frontend at once): `npm start`.
- After the backend successfully starts, in a new terminal `npm run seed` to seed the database with some initial data.
- You can now access the UI at http://localhost:4200 and login with `[email protected]` / `password`.
- You can also find the backend API spec at http://localhost:3000/docs.
7 changes: 6 additions & 1 deletion apps/backend/src/article/article.entity.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {
ArrayType,
Collection,
DateTimeType,
Entity,
EntityDTO,
ManyToOne,
OneToMany,
Platform,
PrimaryKey,
Property,
wrap,
Expand All @@ -13,6 +15,7 @@ import slug from 'slug';

import { User } from '../user/user.entity';
import { Comment } from './comment.entity';
import { MySqlPlatform } from '@mikro-orm/mysql';

@Entity()
export class Article {
Expand All @@ -31,7 +34,9 @@ export class Article {
@Property()
body = '';

@Property({ type: 'date' })
@Property({ type: 'datetime', onUpdate(entity: Article) {
return entity.createdAt.toString().replace('T', ' ').replace('Z','')
}, })
createdAt = new Date();

@Property({ type: 'date', onUpdate: () => new Date() })
Expand Down
40 changes: 29 additions & 11 deletions apps/backend/src/article/article.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,24 +154,42 @@ export class ArticleService {
{ populate: ['followers', 'favorites', 'articles'] },
);
const article = new Article(user!, dto.title, dto.description, dto.body);
article.tagList.push(...dto.tagList);

// Parse tags
const tagNames = dto.tagList.split(',');
article.tagList.push(...tagNames.map((name: string) => name.trim()));

// Remove duplicates
article.tagList = [...new Set(article.tagList)];

user?.articles.add(article);
await this.em.flush();

user?.articles.add(article);
await this.em.flush();

return { article: article.toJSON(user!) };
}

async update(userId: number, slug: string, articleData: any): Promise<IArticleRO> {
const user = await this.userRepository.findOne(
{ id: userId },
{ populate: ['followers', 'favorites', 'articles'] },
);
const article = await this.articleRepository.findOne({ slug }, { populate: ['author'] });
wrap(article).assign(articleData);
await this.em.flush();
async update(userId: number, slug: string, articleData: CreateArticleDto): Promise<IArticleRO> {

return { article: article!.toJSON(user!) };
}
const user = await this.userRepository.findOne(
{ id: userId },
{ populate: ['followers', 'favorites', 'articles'] }
);

const article = await this.articleRepository.findOne({ slug }, { populate: ['author'] });

const tagList = articleData.tagList.split(',');
wrap(article).assign({
...articleData,
tagList
});

await this.em.flush();

return { article: article!.toJSON(user!) };
}

async delete(slug: string) {
return this.articleRepository.nativeDelete({ slug });
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/article/dto/create-article.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ export class CreateArticleDto {
readonly title: string;
readonly description: string;
readonly body: string;
readonly tagList: string[];
readonly tagList: string;
}
3 changes: 2 additions & 1 deletion apps/backend/src/tag/tag.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { TagController } from './tag.controller';
import { Tag } from './tag.entity';
import { TagService } from './tag.service';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { Article } from '../article/article.entity';

@Module({
controllers: [TagController],
exports: [],
imports: [MikroOrmModule.forFeature({ entities: [Tag] }), UserModule],
imports: [MikroOrmModule.forFeature({ entities: [Tag, Article] }), UserModule],
providers: [TagService],
})
export class TagModule {}
20 changes: 13 additions & 7 deletions apps/backend/src/tag/tag.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ import { EntityRepository } from '@mikro-orm/core';
import { InjectRepository } from '@mikro-orm/nestjs';
import { Tag } from './tag.entity';
import { ITagsRO } from './tag.interface';
import { Article } from '../article/article.entity';

@Injectable()
export class TagService {
constructor(
@InjectRepository(Tag)
private readonly tagRepository: EntityRepository<Tag>,
) {}
constructor(@InjectRepository(Article) private articleRepository: EntityRepository<Article>) {}

async findAll(): Promise<ITagsRO> {
const tags = await this.tagRepository.findAll();
return { tags: tags.map((tag) => tag.tag) };
async findAll() {

const articles = await this.articleRepository.findAll();

const tags = articles.reduce((acc: string[], article: Article) => {
return [...acc, ...article.tagList];
}, [] as string[]);

return {
tags: [...new Set(tags)]
}
}
}

0 comments on commit ff2cbe9

Please sign in to comment.