diff --git a/frontend/social-login.html b/frontend/social-login.html deleted file mode 100644 index bf5ad51..0000000 --- a/frontend/social-login.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - 소셜로그인 - - - 구글로그인 - - diff --git a/src/apis/auth/auth.service.ts b/src/apis/auth/auth.service.ts index 6ea8075..731efd7 100644 --- a/src/apis/auth/auth.service.ts +++ b/src/apis/auth/auth.service.ts @@ -112,41 +112,42 @@ export class AuthService { ); // 개발 환경 - res.setHeader('set-Cookie', `refreshToken=${refreshToken}; path=/;`); + // res.setHeader('set-Cookie', `refreshToken=${refreshToken}; path=/;`); // 배포 환경 ============== 배포 하기 전까지 잠시 주석 ============= - // const originList = [ - // 'http://localhost:3000', - // 'http://groomeong.store', // 프론트 도메인 주소?? - // 'https://groomeong.store', // 프론트 도메인 주소?? - // // ssl 된 주소 https:// ..... - // ]; - // const origin = req.headers.origin; - // if (originList.includes(origin)) { - // // 리소스에 엑세스하기 위해 코드 요청을 허용하도록 브라우저에 알리는 응답 - // res.setHeader('Access-Control-Allow-Origin', origin); - // } - - // // 프런트엔드 js 코드에 대한 응답을 노출할지 여부를 브라우저에 알려준다. - // res.setHeader('Access-Control-Allow-Credentials', 'true'); - // // 리소스에 엑세스할 때 허용되는 하나 이상의 메서드를 지정해준다. - // res.setHeader( - // 'Access-Control-Allow-Methods', // - // 'GET, HEAD, OPTIONS, POST, PUT', - // ); - // // 실제 요청 중에 사용할 수 있는 HTTP 헤더를 나타내는 실행 전 요청에 대한 응답. - // // X-Custom-Header => 서버에 대한 cors 요청에 의해 지원 - // // Upgrade-Insecure-Requests => 여러 헤더에 대한 지원을 지정 - // res.setHeader( - // 'Access-Control-Allow-Headers', // - // 'Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers', - // ); - - // res.setHeader( - // 'Set-Cookie', - // `refreshToken=${refreshToken}; path=/; domain=www.groomeong.shop ; Secure; httpOnly; SameSite=None;`, - // ); + const originList = [ + 'http://localhost:3000', + 'http://groomeong.store', // 프론트 도메인 주소?? + 'https://groomeong.store', // 프론트 도메인 주소?? + 'https://www.groomeong.shop/graphql', + // ssl 된 주소 https:// ..... + ]; + const origin = req.headers.origin; + if (originList.includes(origin)) { + // 리소스에 엑세스하기 위해 코드 요청을 허용하도록 브라우저에 알리는 응답 + res.setHeader('Access-Control-Allow-Origin', origin); + } + + // 프런트엔드 js 코드에 대한 응답을 노출할지 여부를 브라우저에 알려준다. + res.setHeader('Access-Control-Allow-Credentials', 'true'); + // 리소스에 엑세스할 때 허용되는 하나 이상의 메서드를 지정해준다. + res.setHeader( + 'Access-Control-Allow-Methods', // + 'GET, HEAD, OPTIONS, POST, PUT', + ); + // 실제 요청 중에 사용할 수 있는 HTTP 헤더를 나타내는 실행 전 요청에 대한 응답. + // X-Custom-Header => 서버에 대한 cors 요청에 의해 지원 + // Upgrade-Insecure-Requests => 여러 헤더에 대한 지원을 지정 + res.setHeader( + 'Access-Control-Allow-Headers', // + 'Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers', + ); + + res.setHeader( + 'Set-Cookie', + `refreshToken=${refreshToken}; path=/; domain=www.groomeong.shop ; Secure; httpOnly; SameSite=None;`, + ); } async loginOAuth({ req, res }: ILoginService): Promise { @@ -160,8 +161,8 @@ export class AuthService { // 3. 로그인 브라우저 전송 this.setRefreshToken({ user, res, req }); - console.log(user, req, res, '@@@@@@@@@@@@'); - res.redirect('http://localhost:3000/'); + + res.redirect('https://groomeong.store/home/'); // 페이지 수정 꼭 하기! 배포될때!!🚗🚗🚗🚗🚗🚗🚗🚗🚗🚗🚗🚗 프론트 메인 페이지 } } diff --git a/src/apis/auth/strategies/jwt-social-google.strategy.ts b/src/apis/auth/strategies/jwt-social-google.strategy.ts index b2d88bf..8dacf65 100644 --- a/src/apis/auth/strategies/jwt-social-google.strategy.ts +++ b/src/apis/auth/strategies/jwt-social-google.strategy.ts @@ -6,7 +6,7 @@ export class JwtGoogleStrategy extends PassportStrategy(Strategy, 'google') { super({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, - callbackURL: 'http://localhost:3000/login/google', + callbackURL: 'https://groomeong.store/login/google', scope: ['email', 'profile'], }); } diff --git a/src/apis/auth/strategies/jwt-social-kakao.strategy.ts b/src/apis/auth/strategies/jwt-social-kakao.strategy.ts index 3048773..0b7401e 100644 --- a/src/apis/auth/strategies/jwt-social-kakao.strategy.ts +++ b/src/apis/auth/strategies/jwt-social-kakao.strategy.ts @@ -6,7 +6,7 @@ export class JwtKakaoStrategy extends PassportStrategy(Strategy, 'KaKao') { super({ clientID: process.env.KAKAO_CLIENT_ID, clientSecret: process.env.KAKAO_CLIENT_SECRET, - callbackURL: 'http://localhost:3000/login/kakao', + callbackURL: 'https://groomeong.store/login/kakao', scope: ['account_email', 'profile_nickname'], }); } diff --git a/src/apis/reservations/entities/reservation.entity.ts b/src/apis/reservations/entities/reservation.entity.ts index 4a6f6bd..c720728 100644 --- a/src/apis/reservations/entities/reservation.entity.ts +++ b/src/apis/reservations/entities/reservation.entity.ts @@ -51,9 +51,9 @@ export class Reservation { // 예약 생성일자 @CreateDateColumn() - createAt?: Date; + createdAt?: Date; // 예약 취소일자 @DeleteDateColumn({ nullable: true }) - deleteAt: Date; + deletedAt: Date; } diff --git a/src/apis/shops/__test__/shops.resolver.spec.ts b/src/apis/shops/__test__/shops.resolver.spec.ts new file mode 100644 index 0000000..49a8a80 --- /dev/null +++ b/src/apis/shops/__test__/shops.resolver.spec.ts @@ -0,0 +1,118 @@ +import { ElasticsearchService } from '@nestjs/elasticsearch'; +import { Test, TestingModule } from '@nestjs/testing'; + +import * as supertest from 'supertest'; +import { ShopsResolver } from '../shops.resolver'; +import { ShopsService } from '../shops.service'; + +describe('ShopsResolver', () => { + let resolver: ShopsResolver; + let service: ShopsService; + let elasticsearchService: ElasticsearchService; + let app; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + ShopsResolver, + { + provide: ShopsService, + useValue: { + sortByAvgStar: jest.fn(), + findAll: jest.fn(), + findById: jest.fn(), + create: jest.fn(), + update: jest.fn(), + }, + }, + { + provide: ElasticsearchService, + useValue: { + search: jest.fn(), + }, + }, + ], + }).compile(); + + resolver = module.get(ShopsResolver); + service = module.get(ShopsService); + elasticsearchService = + module.get(ElasticsearchService); + + app = module.createNestApplication(); + await app.init(); + }); + + describe('autocompleteShops', () => { + it('should return an array of AutocompleteShopsOutput', async () => { + const result = [{ name: 'shop1' }, { name: 'shop2' }]; + (elasticsearchService.search as jest.Mock).mockReturnValueOnce({ + body: { + hits: { + hits: result, + }, + }, + }); + (service.sortByAvgStar as jest.Mock).mockReturnValueOnce(result); + + const response = await supertest(app.getHttpServer()) + .post('/graphql') + .send({ + query: ` + query { + autocompleteShops(search: "test") { + name + } + } + `, + }) + .expect(200); + + expect(response.body.data.autocompleteShops).toEqual(result); + }); + }); + + describe('fetchShops', () => { + it('should return an array of Shop', async () => { + const result = [{ name: 'shop1' }, { name: 'shop2' }]; + (service.findAll as jest.Mock).mockReturnValueOnce(result); + + const response = await supertest(app.getHttpServer()) + .post('/graphql') + .send({ + query: ` + query { + fetchShops(page: 1, count: 10) { + name + } + } + `, + }) + .expect(200); + + expect(response.body.data.fetchShops).toEqual(result); + }); + }); + + describe('fetchShop', () => { + it('should return a Shop', async () => { + const result = { name: 'shop1' }; + (service.findById as jest.Mock).mockReturnValueOnce(result); + + const response = await supertest(app.getHttpServer()) + .post('/graphql') + .send({ + query: ` + query { + fetchShop(shopId: "test") { + name + } + } + `, + }) + .expect(200); + + expect(response.body.data.fetchShop).toEqual(result); + }); + }); +}); diff --git a/src/apis/shops/__test__/shops.resolver.ts b/src/apis/shops/__test__/shops.resolver.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/apis/shops/dto/return-shop.output.ts b/src/apis/shops/dto/return-shop.output.ts index b0a0188..09858a2 100644 --- a/src/apis/shops/dto/return-shop.output.ts +++ b/src/apis/shops/dto/return-shop.output.ts @@ -1,5 +1,4 @@ import { Field, Int, ObjectType } from '@nestjs/graphql'; -import { isNullableType } from 'graphql'; import { Shop } from '../entities/shop.entity'; @ObjectType() diff --git a/src/apis/users/__test__/users.service.spec.ts b/src/apis/users/__test__/users.service.spec.ts index 6423855..5107c6e 100644 --- a/src/apis/users/__test__/users.service.spec.ts +++ b/src/apis/users/__test__/users.service.spec.ts @@ -138,7 +138,7 @@ describe('UsersService', () => { const myData = { name: '철수', email: 'bbb@bbb.com', - hasedPassword: '1234', + password: '1234', phone: '01012341234', }; diff --git a/src/apis/users/entities/user.entity.ts b/src/apis/users/entities/user.entity.ts index 34a276f..a15de0d 100644 --- a/src/apis/users/entities/user.entity.ts +++ b/src/apis/users/entities/user.entity.ts @@ -42,13 +42,13 @@ export class User { image: string; @CreateDateColumn({ nullable: true }) - createAt: Date; + createdAt: Date; @DeleteDateColumn({ nullable: true }) - deleteAt: Date; + deletedAt: Date; @UpdateDateColumn({ nullable: true }) - updateAt: Date; + updatedAt: Date; // Dog @OneToMany(() => Dog, (dogs) => dogs.user)