Merge branch 'master' into 2369-rework-stock-product-handling
This commit is contained in:
Generated
+4993
-6713
File diff suppressed because it is too large
Load Diff
+26
-26
@@ -17,46 +17,46 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.49.0",
|
"@aws-sdk/client-s3": "^3.95.0",
|
||||||
"@aws-sdk/client-sqs": "^3.49.0",
|
"@aws-sdk/client-sqs": "^3.95.0",
|
||||||
"@aws-sdk/client-translate": "^3.49.0",
|
"@aws-sdk/client-translate": "^3.95.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.49.0",
|
"@aws-sdk/s3-request-presigner": "^3.95.0",
|
||||||
"@newrelic/apollo-server-plugin": "^1.2.0",
|
"@newrelic/apollo-server-plugin": "^1.3.0",
|
||||||
"apollo-datasource": "^3.3.1",
|
"apollo-datasource": "^3.3.1",
|
||||||
"apollo-datasource-rest": "^3.5.1",
|
"apollo-datasource-rest": "^3.5.3",
|
||||||
"apollo-server": "^3.6.2",
|
"apollo-server": "^3.7.0",
|
||||||
"async-redis": "^2.0.0",
|
"async-redis": "^2.0.0",
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.27.2",
|
||||||
"datasource-sql": "^1.6.0",
|
"datasource-sql": "^1.6.0",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.1",
|
||||||
"graphql": "^16.3.0",
|
"graphql": "^16.5.0",
|
||||||
"graphql-scalars": "^1.14.1",
|
"graphql-scalars": "^1.17.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"jwk-to-pem": "^2.0.5",
|
"jwk-to-pem": "^2.0.5",
|
||||||
"knex": "^1.0.2",
|
"knex": "^2.0.0",
|
||||||
"knex-stringcase": "^1.4.6",
|
"knex-stringcase": "^1.4.6",
|
||||||
"newrelic": "^8.7.1",
|
"newrelic": "^8.11.1",
|
||||||
"nodemon": "^2.0.15",
|
"nodemon": "^2.0.16",
|
||||||
"pg": "^8.7.3",
|
"pg": "^8.7.3",
|
||||||
"pg-hstore": "^2.3.4",
|
"pg-hstore": "^2.3.4",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.6.2",
|
||||||
"slug": "^5.2.0",
|
"slug": "^5.3.0",
|
||||||
"stringcase": "^4.3.1",
|
"stringcase": "^4.3.1",
|
||||||
"ts-node": "^10.4.0",
|
"ts-node": "^10.7.0",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.6.4",
|
||||||
"util": "^0.12.4",
|
"util": "^0.12.4",
|
||||||
"validator": "^13.7.0"
|
"validator": "^13.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^27.4.0",
|
"@types/jest": "^27.5.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.2",
|
"@typescript-eslint/eslint-plugin": "^5.25.0",
|
||||||
"@typescript-eslint/parser": "^5.10.2",
|
"@typescript-eslint/parser": "^5.25.0",
|
||||||
"eslint": "^8.8.0",
|
"eslint": "^8.15.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"isomorphic-fetch": "^3.0.0",
|
"isomorphic-fetch": "^3.0.0",
|
||||||
"jest": "^27.5.0",
|
"jest": "^28.1.0",
|
||||||
"testcontainers": "^8.2.0",
|
"testcontainers": "^8.10.1",
|
||||||
"ts-jest": "^27.1.3"
|
"ts-jest": "^28.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { SQLDataSource } from 'datasource-sql';
|
import { SQLDataSource } from 'datasource-sql';
|
||||||
import { Keyword, KeywordType } from '../types/keyword-types';
|
import { Keyword, KeywordType } from '../types/keyword-types';
|
||||||
|
import { TextsAPI } from './texts-api';
|
||||||
|
|
||||||
const MINUTE = 60;
|
const MINUTE = 60;
|
||||||
|
|
||||||
export class KeywordAPI extends SQLDataSource {
|
export class KeywordAPI extends SQLDataSource {
|
||||||
constructor(config) {
|
textsApi: TextsAPI;
|
||||||
|
constructor(config, textsApi) {
|
||||||
super(config);
|
super(config);
|
||||||
|
this.textsApi = textsApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
getType(data: any) {
|
getType(data: any) {
|
||||||
@@ -98,18 +101,8 @@ ORDER BY keywords.value
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await this.textsApi.translateKeyword(keywordId, name);
|
||||||
|
|
||||||
return keywordId;
|
return keywordId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
category keywords:
|
|
||||||
SELECT category_keyword.category_id, keywords.value
|
|
||||||
FROM category_keyword
|
|
||||||
JOIN keywords ON category_keyword.keyword_id = keywords.id;
|
|
||||||
|
|
||||||
texts:
|
|
||||||
FROM categorydata cd
|
|
||||||
JOIN categorydatakeys cdk ON cd.datakey_id = cdk.id
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -194,6 +194,18 @@ export class ProductAPI extends BaseSQLDataSource {
|
|||||||
return res.find(Boolean);
|
return res.find(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getProductByPath(path: string): Promise<Maybe<Product>> {
|
||||||
|
const query = sql.productByPath(path);
|
||||||
|
|
||||||
|
const res = await this.knex.raw(query).then((data) =>
|
||||||
|
data.rows.map((row) => {
|
||||||
|
const prod = this.createProductFromRow(row);
|
||||||
|
return prod;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return res.find(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
async getDesignerProducts(designerId: number): Promise<Array<Product>> {
|
async getDesignerProducts(designerId: number): Promise<Array<Product>> {
|
||||||
const query = sql.designerProducts();
|
const query = sql.designerProducts();
|
||||||
|
|
||||||
@@ -381,7 +393,7 @@ export class ProductAPI extends BaseSQLDataSource {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @function addProduct
|
* @function addProduct
|
||||||
* @description Adds a new product to system, will use batchname and name to
|
* @description Adds a new product to system, will use name to
|
||||||
* set a unique path, artNo is the productId with e infront.
|
* set a unique path, artNo is the productId with e infront.
|
||||||
*/
|
*/
|
||||||
async addProduct(
|
async addProduct(
|
||||||
@@ -390,8 +402,7 @@ export class ProductAPI extends BaseSQLDataSource {
|
|||||||
designerId: number,
|
designerId: number,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const fixedBatch = !!batch ? batch : '';
|
const fixedBatch = !!batch ? batch : '';
|
||||||
const path = batch ? fixedBatch + ' ' + name : name;
|
const productPath = slug(name);
|
||||||
const productPath = slug(path);
|
|
||||||
const safePath = await this.getUniqueProductPath(productPath, null);
|
const safePath = await this.getUniqueProductPath(productPath, null);
|
||||||
|
|
||||||
const idres = await this.knex
|
const idres = await this.knex
|
||||||
|
|||||||
@@ -119,6 +119,15 @@ export function product(id: number) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function productByPath(path: string) {
|
||||||
|
return (
|
||||||
|
baseQuery +
|
||||||
|
/* sql */ `
|
||||||
|
WHERE products.path = '${path}'
|
||||||
|
`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function categoryProducts(categoryId: number) {
|
export function categoryProducts(categoryId: number) {
|
||||||
return (
|
return (
|
||||||
baseQuery +
|
baseQuery +
|
||||||
|
|||||||
@@ -14,6 +14,31 @@ export class TextsAPI extends SQLDataSource {
|
|||||||
this.marketLocaleApi = marketLocaleApi;
|
this.marketLocaleApi = marketLocaleApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async translateKeyword(keywordId: number, keyword: string): Promise<void> {
|
||||||
|
const locales = await this.marketLocaleApi.getLocales();
|
||||||
|
for (let i = 0; i < locales.length; i++) {
|
||||||
|
let langCode = this.getLanguageCode(locales[i]);
|
||||||
|
// If we have a fallback locale we skip translating
|
||||||
|
if (locales[i].fallbackId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const input: TranslateInput = {
|
||||||
|
text: keyword,
|
||||||
|
targetLanguageCode: langCode,
|
||||||
|
sourceLanguageCode: 'en',
|
||||||
|
};
|
||||||
|
const translated = await translateText(input);
|
||||||
|
|
||||||
|
const res = await this.knex('keywords_i18n')
|
||||||
|
.insert({
|
||||||
|
value: translated,
|
||||||
|
keyword_id: keywordId,
|
||||||
|
locale_id: locales[i].id,
|
||||||
|
})
|
||||||
|
.returning('*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async translateProductName(
|
async translateProductName(
|
||||||
name: string,
|
name: string,
|
||||||
oldPath: string,
|
oldPath: string,
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ const imageServerApi = new ImageServerApi();
|
|||||||
const interiorsLambdaApi = new InteriorsLambdaAPI();
|
const interiorsLambdaApi = new InteriorsLambdaAPI();
|
||||||
const interiorApi = new InteriorAPI(knexConfig, imageServerApi);
|
const interiorApi = new InteriorAPI(knexConfig, imageServerApi);
|
||||||
const printProductDefaultsApi = new PrintProductDefaultsAPI(knexConfig);
|
const printProductDefaultsApi = new PrintProductDefaultsAPI(knexConfig);
|
||||||
const keywordApi = new KeywordAPI(knexConfig);
|
const keywordApi = new KeywordAPI(knexConfig, textsApi);
|
||||||
const orderApi = new OrderAPI(knexConfig);
|
const orderApi = new OrderAPI(knexConfig);
|
||||||
const productApi = new ProductAPI(
|
const productApi = new ProductAPI(
|
||||||
knexConfig,
|
knexConfig,
|
||||||
|
|||||||
@@ -121,6 +121,14 @@ async function getProduct(_, { id }, { dataSources, auth }): Promise<Product> {
|
|||||||
return (<ProductAPI>dataSources.productApi).getProduct(id);
|
return (<ProductAPI>dataSources.productApi).getProduct(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getProductByPath(
|
||||||
|
_,
|
||||||
|
{ path },
|
||||||
|
{ dataSources },
|
||||||
|
): Promise<Product> {
|
||||||
|
return (<ProductAPI>dataSources.productApi).getProductByPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
export const productTypeDefs = {
|
export const productTypeDefs = {
|
||||||
ProductBlacklist,
|
ProductBlacklist,
|
||||||
Product,
|
Product,
|
||||||
@@ -130,6 +138,7 @@ export const productTypeDefs = {
|
|||||||
export const productQueryTypeDefs = {
|
export const productQueryTypeDefs = {
|
||||||
products: getProductsResult,
|
products: getProductsResult,
|
||||||
product: getProduct,
|
product: getProduct,
|
||||||
|
productByPath: getProductByPath,
|
||||||
productsSearch: getProductsSearchResult,
|
productsSearch: getProductsSearchResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type Query {
|
|||||||
filter: ProductsFilterInput
|
filter: ProductsFilterInput
|
||||||
): ProductsResult
|
): ProductsResult
|
||||||
product(id: Int!): Product
|
product(id: Int!): Product
|
||||||
|
productByPath(path: String!): Product
|
||||||
productsSearch(q: String!): ProductsSearchResult
|
productsSearch(q: String!): ProductsSearchResult
|
||||||
categories: [Category]
|
categories: [Category]
|
||||||
category(id: Int!): Category
|
category(id: Int!): Category
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
const {
|
||||||
|
TranslateClient,
|
||||||
|
TranslateTextCommand,
|
||||||
|
} = require('@aws-sdk/client-translate');
|
||||||
|
|
||||||
|
const db = require('knex')({
|
||||||
|
client: 'pg',
|
||||||
|
connection: 'postgresql://fondberg:@docker.for.mac.localhost/photowall',
|
||||||
|
searchPath: ['public'],
|
||||||
|
});
|
||||||
|
|
||||||
|
async function translateText(input) {
|
||||||
|
const translateClient = new TranslateClient({
|
||||||
|
region: 'eu-west-1',
|
||||||
|
});
|
||||||
|
|
||||||
|
const translateTextCommand = new TranslateTextCommand({
|
||||||
|
SourceLanguageCode: input.sourceLanguageCode ?? 'auto',
|
||||||
|
TargetLanguageCode: input.targetLanguageCode,
|
||||||
|
Text: input.text,
|
||||||
|
});
|
||||||
|
|
||||||
|
return translateClient
|
||||||
|
.send(translateTextCommand)
|
||||||
|
.then((resp) => resp.TranslatedText);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLanguageCode(locale) {
|
||||||
|
let langCode = locale.value.substr(0, 2);
|
||||||
|
return langCode == 'nn' ? 'no' : langCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function translate(locales, keyword) {
|
||||||
|
for (let i = 0; i < locales.length; i++) {
|
||||||
|
const langCode = getLanguageCode(locales[i]);
|
||||||
|
const input = {
|
||||||
|
text: keyword.value,
|
||||||
|
targetLanguageCode: langCode,
|
||||||
|
};
|
||||||
|
const translated = await translateText(input);
|
||||||
|
console.log(keyword.value + ' : ' + translated);
|
||||||
|
const res = await db('keywords_i18n')
|
||||||
|
.insert({
|
||||||
|
value: translated,
|
||||||
|
keyword_id: keyword.id,
|
||||||
|
locale_id: locales[i].id,
|
||||||
|
})
|
||||||
|
.returning('*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const locales = await db.select().table('locales').whereNull('fallback_id');
|
||||||
|
const keywords = await db.select().table('keywords');
|
||||||
|
for (let i = 0; i < keywords.length; i++) {
|
||||||
|
await translate(locales, keywords[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user