diff --git a/src/cognito/access-control.ts b/src/cognito/access-control.ts index 29bf5b5..9c218de 100644 --- a/src/cognito/access-control.ts +++ b/src/cognito/access-control.ts @@ -46,7 +46,12 @@ function getScopes(user: ClaimVerifyResult): Scopes[] | [] { function throwForbidden() { throw new GraphQLError('You are not authorized to perform this action', { - extensions: { code: 'FORBIDDEN' }, + extensions: { + code: 'FORBIDDEN', + http: { + status: 401, + }, + }, }); } diff --git a/src/cognito/cognito-client.ts b/src/cognito/cognito-client.ts index 7e89e53..a1fb9c9 100644 --- a/src/cognito/cognito-client.ts +++ b/src/cognito/cognito-client.ts @@ -86,7 +86,12 @@ interface Identity { const cognitoPoolId = process.env.COGNITO_POOL_ID || ''; if (!cognitoPoolId) { throw new GraphQLError('env var required for cognito pool', { - extensions: { code: 'FORBIDDEN' }, + extensions: { + code: 'FORBIDDEN', + http: { + status: 401, + }, + }, }); } const cognitoIssuer = `https://cognito-idp.eu-west-1.amazonaws.com/${cognitoPoolId}`; @@ -181,7 +186,12 @@ const verifyToken = async ( const verifyAuthentication = async (req: IncomingMessage) => { const notAuthorizedError = () => { throw new GraphQLError('You are not authorized', { - extensions: { code: 'FORBIDDEN' }, + extensions: { + code: 'FORBIDDEN', + http: { + status: 401, + }, + }, }); }; diff --git a/src/datasources/designer-api.ts b/src/datasources/designer-api.ts index c16294b..fde854e 100644 --- a/src/datasources/designer-api.ts +++ b/src/datasources/designer-api.ts @@ -10,7 +10,10 @@ export class DesignerAPI extends BaseSQLDataSource { } async getDesignerById(id: number): Promise { - ScopeAccess.validate(this.user).all([Scopes.DESIGNERS_READ]); + ScopeAccess.validate(this.user).some([ + Scopes.DESIGNERS_READ, + Scopes.DESIGNERS_PUBLIC_READ, + ]); return ( this.knex .select('*') diff --git a/src/datasources/product-api.ts b/src/datasources/product-api.ts index 67a1162..9a96141 100644 --- a/src/datasources/product-api.ts +++ b/src/datasources/product-api.ts @@ -220,7 +220,10 @@ export class ProductAPI extends BaseSQLDataSource { } async getProducts(input: ProductsFilterInput): Promise> { - ScopeAccess.validate(this.user).some([Scopes.PRODUCTS_READ]); + ScopeAccess.validate(this.user).some([ + Scopes.PRODUCTS_READ, + Scopes.PRODUCTS_PUBLIC_READ, + ]); const query = sql.products(input); return this.knex @@ -229,7 +232,10 @@ export class ProductAPI extends BaseSQLDataSource { } async getProduct(id: number): Promise> { - ScopeAccess.validate(this.user).some([Scopes.PRODUCTS_READ]); + ScopeAccess.validate(this.user).some([ + Scopes.PRODUCTS_READ, + Scopes.PRODUCTS_PUBLIC_READ, + ]); const query = sql.product(); const res = await this.knex.raw(query, [id]).then((data) => @@ -241,6 +247,25 @@ export class ProductAPI extends BaseSQLDataSource { return res.find(Boolean); } + async getListPrice( + printId: number, + marketId: number, + ): Promise> { + ScopeAccess.validate(this.user).some([ + Scopes.PRODUCTS_READ, + Scopes.PRODUCTS_PUBLIC_READ, + ]); + const query = sql.getProductListPrice(); + try { + const res = await this.knex.raw(query, [marketId, printId]); + return res.rows[0].listprice; + } catch (error) { + throw new GraphQLError('No listprice found', { + extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT }, + }); + } + } + async getProductByPath(path: string): Promise> { ScopeAccess.validate(this.user).all([Scopes.PRODUCTS_READ]); const query = sql.productByPath(); diff --git a/src/datasources/sql/products-sql.ts b/src/datasources/sql/products-sql.ts index 01a039c..851d5ff 100644 --- a/src/datasources/sql/products-sql.ts +++ b/src/datasources/sql/products-sql.ts @@ -199,3 +199,7 @@ export function searchByFieldValue(fieldid: number) { ` ); } + +export function getProductListPrice() { + return 'SELECT listprice FROM v_listprices WHERE market_id = ? AND printproduct_id = ?'; +} diff --git a/src/index.ts b/src/index.ts index 4845840..c1ac97c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,6 +46,9 @@ async function main() { }); app.post('/login', async (req, res) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', '*'); + res.setHeader('Access-Control-Allow-Credentials', 'true'); try { const response = await getClientAccessToken(req); res.status(200).send(response); @@ -57,7 +60,7 @@ async function main() { app.use( '/', - cors(), + cors('*'), json(), expressMiddleware(server, { context: async ({ req }) => { diff --git a/src/resolvers/products-resolver.ts b/src/resolvers/products-resolver.ts index 65ab170..85a0276 100644 --- a/src/resolvers/products-resolver.ts +++ b/src/resolvers/products-resolver.ts @@ -14,7 +14,7 @@ import { Keyword } from '../types/keyword-types'; import { MarketLocaleAPI } from '../datasources/market-locale-api'; import { InteriorAPI } from '../datasources/interior-api'; import { InteriorsLambdaAPI } from '../datasources/interiors-lambda-api'; -import { IdNumberResult } from '../types/types'; +import { IdNumberResult, MarketInput } from '../types/types'; import { moveS3File } from '../aws/s3'; import { DesignerAPI } from '../datasources/designer-api'; import { PrintProductDefaultsAPI } from '../datasources/printproduct-defaults-api'; @@ -55,6 +55,12 @@ const PrintProduct = { dataSources.printProductDefaultsApi )).getDefaults(id); }, + async listprice({ id }, input: MarketInput, { dataSources }) { + return (dataSources.productApi).getListPrice( + id, + input.marketId, + ); + }, }; async function getProductsResult( diff --git a/src/schema.graphql b/src/schema.graphql index d59d9d8..3144efa 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -341,6 +341,7 @@ type PrintProduct { updated: DateTime interiors: [Interior] defaults: PrintProductDefaults + listprice(marketId: Int!): Float! } enum InteriorType { diff --git a/src/types/types.ts b/src/types/types.ts index c12cff9..afc7f3c 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -45,3 +45,7 @@ export interface PaginationResult { export interface IdNumberResult { id: number; } + +export interface MarketInput { + marketId: number; +}