diff --git a/docker-compose.yml b/docker-compose.yml index adc818c00a3217f6b289be7ef67cf93747a9a47a..6c7ead9599e89777d27cae37032fb9b2a8b227fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,5 +42,29 @@ services: ME_CONFIG_BASICAUTH_PASSWORD: ${ME_CONFIG_BASICAUTH_PASSWORD} ME_CONFIG_MONGODB_SERVER: database-ram + ghost: + image: ghost:latest + restart: always + ports: + - ${GHOST_PORT}:2368 + environment: + # see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables + database__client: mysql + database__connection__host: ghost-db + database__connection__user: root + database__connection__password: ${GHOST_DB_PASSWORD} + database__connection__database: ghost + # this url value is just an example, and is likely wrong for your environment! + url: http://localhost:${GHOST_PORT} + + ghost-db: + image: mysql:5.7 + restart: always + environment: + MYSQL_ROOT_PASSWORD: ${GHOST_DB_PASSWORD} + volumes: + - db-ghost + volumes: db-ram: + db-ghost: diff --git a/src/app.module.ts b/src/app.module.ts index e4f71d3eadc6821b7e65fb69825aaada5ee3b856..e0aa57e2278e56f027bcfe0d0db969e5936708c8 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -10,6 +10,7 @@ import { UsersModule } from './users/users.module'; import { MailerModule } from './mailer/mailer.module'; import { TclModule } from './tcl/tcl.module'; import { AdminModule } from './admin/admin.module'; +import { PostsModule } from './posts/posts.module'; @Module({ imports: [ ConfigurationModule, @@ -24,6 +25,7 @@ import { AdminModule } from './admin/admin.module'; MailerModule, TclModule, AdminModule, + PostsModule, ], controllers: [AppController], }) diff --git a/src/main.ts b/src/main.ts index ed8e487ca1cfc569b967338942d322c5c1f7f31c..d4287f5015f44ad7e5e76f6ab93023cd41caf1d7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,7 +6,12 @@ import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe()); - const options = new DocumentBuilder().setTitle('RAM').setDescription('RAM API description').setVersion('1.0').build(); + const options = new DocumentBuilder() + .setTitle('RAM') + .setDescription('RAM API description') + .setVersion('1.0') + .addBearerAuth({ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' }, 'JWT') + .build(); const document = SwaggerModule.createDocument(app, options); SwaggerModule.setup('api', app, document); await app.listen(3000); diff --git a/src/posts/posts.controller.spec.ts b/src/posts/posts.controller.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..7784335f5040742d323ac81d6e04f2940f8e9088 --- /dev/null +++ b/src/posts/posts.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PostsController } from './posts.controller'; + +describe('PostsController', () => { + let controller: PostsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [PostsController], + }).compile(); + + controller = module.get<PostsController>(PostsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/posts/posts.controller.ts b/src/posts/posts.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5c9478a2cde8a29629759fab5fbf5513c07acc0 --- /dev/null +++ b/src/posts/posts.controller.ts @@ -0,0 +1,35 @@ +import { Controller, Get, HttpService, Query } from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { ApiBearerAuth, ApiQuery } from '@nestjs/swagger'; +import { Post } from './schemas/post.schema'; + +@Controller('posts') +export class PostsController { + constructor(private readonly httpService: HttpService) {} + + @Get() + @ApiQuery({ name: 'include', type: String, required: false }) + @ApiQuery({ name: 'fields', type: String, required: false }) + @ApiQuery({ name: 'formats', type: String, required: false }) + @ApiQuery({ name: 'filter', type: String, required: false }) + @ApiQuery({ name: 'limit', type: String, required: false }) + @ApiQuery({ name: 'page', type: String, required: false }) + @ApiQuery({ name: 'order', type: String, required: false }) + public async findAll(@Query() query): Promise<Observable<{ posts: Post[] }>> { + return this.httpService + .get(`${process.env.GHOST_HOST_AND_PORT}/ghost/api/v3/content/posts`, { + params: { + key: process.env.GHOST_CONTENT_API_KEY, + include: query.include ? query.include : null, + fields: query.fields ? query.fields : null, + formats: query.formats ? query.formats : null, + filter: query.filter ? query.filter : null, + limit: query.limit ? query.limit : null, + order: query.order ? query.order : null, + page: query.page ? query.page : null, + }, + }) + .pipe(map((response) => response.data)); + } +} diff --git a/src/posts/posts.module.ts b/src/posts/posts.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..de11cb04f87397833dacfd9550c8947acfc9c591 --- /dev/null +++ b/src/posts/posts.module.ts @@ -0,0 +1,8 @@ +import { HttpModule, Module } from '@nestjs/common'; +import { PostsController } from './posts.controller'; + +@Module({ + imports: [HttpModule], + controllers: [PostsController], +}) +export class PostsModule {} diff --git a/src/posts/schemas/post.schema.ts b/src/posts/schemas/post.schema.ts new file mode 100644 index 0000000000000000000000000000000000000000..1711ec1f208295ec71881e4b480f21cd264f2fee --- /dev/null +++ b/src/posts/schemas/post.schema.ts @@ -0,0 +1,29 @@ +export class Post { + id: string; + uuid: string; + title: string; + slug: string; + html: string; + comment_id: string; + feature_image: null; + featured: false; + visibility: string; + email_recipient_filter: string; + created_at: string; + updated_at: string; + published_at: string; + url: string; + excerpt: string; + reading_time: string; + access: boolean; + send_email_when_published: boolean; + og_image: string; + og_title: string; + og_description: string; + twitter_image: string; + twitter_title: string; + twitter_description: string; + meta_title: string; + meta_description: string; + email_subject: string; +} diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 9c8c2c31b19ad0fec488cc11fd3ec1e53976d93a..43fb564f56211d4f7fd7b0952d9237f8308d3bb4 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Get, Param, Post, Query, Request, UseGuards } from '@nestjs/common'; -import { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger'; +import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { PasswordChangeDto } from './dto/change-password.dto'; import { EmailChangeDto } from './dto/change-email.dto'; @@ -13,6 +13,7 @@ export class UsersController { constructor(private usersService: UsersService) {} @UseGuards(JwtAuthGuard) + @ApiBearerAuth('JWT') @ApiOperation({ description: 'Get user profile' }) @ApiResponse({ status: 200, description: 'Return user profil' }) @ApiResponse({ status: 401, description: 'User does not have sufficient rights' }) diff --git a/template.env b/template.env index 4f50e814d2837bacddfefdb2c80e0a1bfcb05176..fa2c9d0ae8b15dad61e8e27bf04059602c8c597c 100644 --- a/template.env +++ b/template.env @@ -14,3 +14,5 @@ SALT=<Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue> MAIL_URL=<API url> MAIL_TOKEN=<API token> APTIC_TOKEN=<APTIC API TOKEN> +GHOST_PORT=<ghost port> +GHOST_DB_PASSWORD=<ghost db password>