From 6000259b5fadeb8588726399e120cbe0d770e5f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20V=C3=A1clavek?= <49518842+david-vaclavek@users.noreply.github.com> Date: Thu, 9 May 2024 17:31:13 +0200 Subject: [PATCH] LOC-1096 - Fix Analytics User Identification Within Integrations (#51) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚧 refactor: use `api-client` and `generic-connector-client` * ♻️ refactor: use `generic-connector-client` for analytics * ♻️ refactor: upload process * ♻️ refactor: download proces (`api-client`) * 🐛 fix: (`deprecate-event-entry-in-localazy-hook`) `client-api` result * ⚰️ code: remove dead code * 🐛 fix: (`supported-custom-field-plugins`) add reference to server side * ⬆️ deps(upgrade): `api-client` and `generic-connector-client` * ✨ feat(Analytics): send plugin version in request --------- Co-authored-by: david-vaclavek --- admin/src/config/index.js | 2 - admin/src/index.js | 2 +- .../@common/services/plugin.service.js | 16 +++ .../services/product-analytics-service.js | 65 +++++++----- .../login/components/LoginButton/index.js | 14 +-- admin/src/plugins/analytics-service.js | 14 --- admin/src/plugins/generic-connector-client.js | 9 ++ .../createPluginConnectorAxiosInstance.js | 45 --------- package-lock.json | 80 +++++++++++---- package.json | 4 +- server/controllers/index.js | 2 - .../controllers/localazy-auth-controller.js | 46 +++------ server/controllers/my-controller.js | 10 -- server/controllers/strapi-controller.js | 8 ++ .../deprecate-event-entry-in-localazy-hook.js | 28 +++--- .../upload-event-entry-to-localazy-hook.js | 17 ++-- .../models/supported-custom-field-plugins.js | 1 + server/routes/strapi.js | 8 ++ server/services/index.js | 4 - server/services/localazy-auth-service.js | 38 ------- server/services/localazy-download-service.js | 54 ---------- server/services/localazy-pubapi-service.js | 14 +-- .../localazy-transfer-download-service.js | 16 ++- .../localazy-transfer-upload-service.js | 20 ++-- server/services/localazy-upload-service.js | 98 +++++-------------- server/services/strapi-service.js | 3 + ...-api.js => localazy-api-client-factory.js} | 8 +- ...calazy-generic-connector-client-factory.js | 15 +++ 28 files changed, 268 insertions(+), 373 deletions(-) create mode 100644 admin/src/modules/@common/services/plugin.service.js delete mode 100644 admin/src/plugins/analytics-service.js create mode 100644 admin/src/plugins/generic-connector-client.js delete mode 100644 admin/src/utils/createPluginConnectorAxiosInstance.js delete mode 100644 server/controllers/my-controller.js delete mode 100644 server/services/localazy-auth-service.js delete mode 100644 server/services/localazy-download-service.js rename server/utils/{get-localazy-api.js => localazy-api-client-factory.js} (69%) create mode 100644 server/utils/localazy-generic-connector-client-factory.js diff --git a/admin/src/config/index.js b/admin/src/config/index.js index fd40927..650d390 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -14,8 +14,6 @@ if (process.env.STRAPI_ADMIN_LOCALAZY_ENV === "development") { config = development; } -console.log(config); - export default { ...config, }; diff --git a/admin/src/index.js b/admin/src/index.js index 360f880..07a9407 100644 --- a/admin/src/index.js +++ b/admin/src/index.js @@ -59,7 +59,7 @@ export default { return component; } catch (e) { - console.log(e); + console.error(e); } return null; diff --git a/admin/src/modules/@common/services/plugin.service.js b/admin/src/modules/@common/services/plugin.service.js new file mode 100644 index 0000000..2be1154 --- /dev/null +++ b/admin/src/modules/@common/services/plugin.service.js @@ -0,0 +1,16 @@ +/* eslint-disable no-useless-catch */ +import createAxiosInstance from "../../../utils/createAxiosInstance"; + +const axiosInstance = createAxiosInstance(); + +export default class PluginService { + static async getPluginVersion() { + try { + const result = await axiosInstance.get("/strapi/version"); + + return result.data; + } catch (e) { + throw e; + } + } +} diff --git a/admin/src/modules/@common/services/product-analytics-service.js b/admin/src/modules/@common/services/product-analytics-service.js index 0791a95..772d6f8 100644 --- a/admin/src/modules/@common/services/product-analytics-service.js +++ b/admin/src/modules/@common/services/product-analytics-service.js @@ -1,13 +1,18 @@ -import AnalyticsService from "../../../plugins/analytics-service"; +import GenericConnectorClient from "../../../plugins/generic-connector-client"; +import PluginService from "./plugin.service"; export default class ProductAnalyticsService { static async trackAppConnected(userId, project, params = {}) { try { - const data = this.buildData(userId, "Strapi Connected", project, params); - await AnalyticsService.trackEvent(data.event, { - ...data.data, - userId, - category: "Project", + const data = await this.buildData("Strapi Connected", project, params); + await GenericConnectorClient.analytics.track({ + event: data.event, + data: { + ...data.data, + userId, + orgId: project.orgId, + category: "Project", + } }); } catch (e) { console.warn(e); @@ -16,11 +21,15 @@ export default class ProductAnalyticsService { static async trackAppDisconnected(userId, project, params = {}) { try { - const data = this.buildData(userId, "Strapi Disconnected", project, params); - await AnalyticsService.trackEvent(data.event, { - ...data.data, - userId, - category: "Project", + const data = await this.buildData("Strapi Disconnected", project, params); + await GenericConnectorClient.analytics.track({ + event: data.event, + data: { + ...data.data, + userId, + orgId: project.orgId, + category: "Project", + } }); } catch (e) { console.warn(e); @@ -29,11 +38,15 @@ export default class ProductAnalyticsService { static async trackUploadToLocalazy(userId, project, params = {}) { try { - const data = this.buildData(userId, "Strapi Upload", project, params); - await AnalyticsService.trackEvent(data.event, { - ...data.data, - userId, - category: "Project", + const data = await this.buildData("Strapi Upload", project, params); + await GenericConnectorClient.analytics.track({ + event: data.event, + data: { + ...data.data, + userId, + orgId: project.orgId, + category: "Project", + } }); } catch (e) { console.warn(e); @@ -42,24 +55,30 @@ export default class ProductAnalyticsService { static async trackDownloadToStrapi(userId, project, params = {}) { try { - const data = this.buildData(userId, "Strapi Download", project, params); - await AnalyticsService.trackEvent(data.event, { - ...data.data, - userId, - category: "Project", + const data = await this.buildData("Strapi Download", project, params); + await GenericConnectorClient.analytics.track({ + event: data.event, + data: { + ...data.data, + userId, + orgId: project.orgId, + category: "Project", + } }); } catch (e) { console.warn(e); } } - static buildData(userId, event, project, params) { + static async buildData(event, project, params) { + const { version } = await PluginService.getPluginVersion(); + return { event, data: { - "User Id": userId, "Project Id": project.id, "Project Name": project.name, + version, ...params, }, }; diff --git a/admin/src/modules/login/components/LoginButton/index.js b/admin/src/modules/login/components/LoginButton/index.js index 1317826..66392dd 100644 --- a/admin/src/modules/login/components/LoginButton/index.js +++ b/admin/src/modules/login/components/LoginButton/index.js @@ -8,6 +8,7 @@ import React, { useState } from "react"; import PropTypes from "prop-types"; import { Button } from "@strapi/design-system/Button"; import { useTranslation } from "react-i18next"; +import { getOAuthAuthorizationUrl } from "@localazy/generic-connector-client"; import LocalazyLoginService from "../../services/localazy-login-service"; import { getStrapiDefaultLocale } from "../../../@common/utils/get-default-locale"; import { isoStrapiToLocalazy } from "../../../@common/utils/iso-locales-utils"; @@ -23,13 +24,12 @@ function LoginButton(props) { const strapiDefaultLocale = await getStrapiDefaultLocale(); const localazyFormatLocaleCode = isoStrapiToLocalazy(strapiDefaultLocale.code); const keys = await LocalazyLoginService.generateKeys(); - const params = new URLSearchParams({ - client_id: config.LOCALAZY_OAUTH_APP_CLIENT_ID, - custom_id: keys.writeKey, - allow_create: "true", - create_locale: localazyFormatLocaleCode, - }); - const url = `${config.LOCALAZY_OAUTH_URL}?${params.toString()}`; + const url = getOAuthAuthorizationUrl({ + clientId: config.LOCALAZY_OAUTH_APP_CLIENT_ID, + customId: keys.writeKey, + allowCreate: true, + createLocale: localazyFormatLocaleCode, + }, config.LOCALAZY_OAUTH_URL); window.open(url); const pollResult = await LocalazyLoginService.continuousPoll(keys.readKey); diff --git a/admin/src/plugins/analytics-service.js b/admin/src/plugins/analytics-service.js deleted file mode 100644 index 7d3b0c4..0000000 --- a/admin/src/plugins/analytics-service.js +++ /dev/null @@ -1,14 +0,0 @@ -import createPluginConnectorAxiosInstance from "../utils/createPluginConnectorAxiosInstance"; - -const ANALYTICS_PATH = "/analytics"; -const axiosInstance = createPluginConnectorAxiosInstance(); -export default class AnalyticsService { - static async trackEvent(event, data) { - const result = await axiosInstance.post(`${ANALYTICS_PATH}/track`, { - event, - ...data, - }); - - return result.data; - } -} diff --git a/admin/src/plugins/generic-connector-client.js b/admin/src/plugins/generic-connector-client.js new file mode 100644 index 0000000..4386df7 --- /dev/null +++ b/admin/src/plugins/generic-connector-client.js @@ -0,0 +1,9 @@ +import { GenericConnectorClient, Services } from "@localazy/generic-connector-client"; +import config from "../config"; + +const client = new GenericConnectorClient({ + pluginId: Services.STRAPI, + genericConnectorUrl: config.LOCALAZY_PLUGIN_CONNECTOR_API_URL, +}); + +export default client; diff --git a/admin/src/utils/createPluginConnectorAxiosInstance.js b/admin/src/utils/createPluginConnectorAxiosInstance.js deleted file mode 100644 index 185af80..0000000 --- a/admin/src/utils/createPluginConnectorAxiosInstance.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * axios with plugin connector config. - */ - -import axios from "axios"; -import config from "../config"; - -const BASE_PLUGIN_PATH = config.LOCALAZY_PLUGIN_CONNECTOR_API_URL; - -const createPluginConnectorAxiosInstance = (baseUrl = null) => { - if (baseUrl === null) { - baseUrl = `${BASE_PLUGIN_PATH}`; - } - - const instance = axios.create({ - baseURL: baseUrl, - }); - - instance.interceptors.request.use( - async (config) => { - config.headers = { - Accept: "application/json", - "Content-Type": "application/json", - // Strapi plugin id in terms of plugin connector - "X-Localazy-Plugin-Id": 1, - }; - - return config; - }, - (error) => { - Promise.reject(error); - } - ); - - instance.interceptors.response.use( - (response) => response, - (error) => { - throw error; - } - ); - - return instance; -}; - -export default createPluginConnectorAxiosInstance; diff --git a/package-lock.json b/package-lock.json index 01329c7..882c3c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,9 @@ "license": "MIT", "dependencies": { "@david-vaclavek/deep-keys": "^0.5.0", - "@localazy/ts-api": "^1.0.13", + "@localazy/api-client": "^2.1.5", + "@localazy/generic-connector-client": "^0.2.3", + "@localazy/ts-api": "^1.1.0", "chalk": "^5.3.0", "fs-extra": "^11.1.1", "i18next": "^22.4.9", @@ -3880,10 +3882,33 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@localazy/api-client": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@localazy/api-client/-/api-client-2.1.5.tgz", + "integrity": "sha512-bYIyHEOgO3ldS3tl224tQyIffDUhMm9tAg3XBYoNwaQM0LkqUJiQBCRu/QFCnXsrOS9ieG/F6yhPL4Na3CU09A==", + "dependencies": { + "@localazy/languages": "^0.1.6", + "lodash-es": "^4.17.21" + } + }, + "node_modules/@localazy/generic-connector-client": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@localazy/generic-connector-client/-/generic-connector-client-0.2.3.tgz", + "integrity": "sha512-o0CL0ils+rwQurWRlrV5BRnesERC4XO3HwFDtJFES6ZzZHtUZplpAvi+yhUfaxSfbnJHC49tc3TMSTGSNfoZBw==", + "dependencies": { + "@localazy/languages": "^0.1.6", + "lodash-es": "^4.17.21" + } + }, + "node_modules/@localazy/languages": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@localazy/languages/-/languages-0.1.9.tgz", + "integrity": "sha512-XgCOu1aQI9P0zmq9wIU+mpJJbkaHnajuItrs4CXr/6EyGaZe3Of9uIk76p8iYCd5RXYeqZPd513MgEl8C1m1HQ==" + }, "node_modules/@localazy/ts-api": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@localazy/ts-api/-/ts-api-1.0.13.tgz", - "integrity": "sha512-WmWkoRfTtyrtBHyzhnk7nVLW/YQb6ePBAKAUobwQaCmxLAHUOSx8MGyg7I6VYJLofE1EQzg8crJgZhtvKeSF6g==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@localazy/ts-api/-/ts-api-1.1.0.tgz", + "integrity": "sha512-0iLFWRxmKPkuruASye4A6CQoYMDGLqQmPLS76zKhPywwNTc89oIlaWrkl63c2EP70NzHxKu6BnpmJAjqFSeXrg==" }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", @@ -13989,9 +14014,9 @@ "peer": true }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -19046,8 +19071,7 @@ "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "peer": true + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -29984,10 +30008,33 @@ "@lezer/common": "^1.0.0" } }, + "@localazy/api-client": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@localazy/api-client/-/api-client-2.1.5.tgz", + "integrity": "sha512-bYIyHEOgO3ldS3tl224tQyIffDUhMm9tAg3XBYoNwaQM0LkqUJiQBCRu/QFCnXsrOS9ieG/F6yhPL4Na3CU09A==", + "requires": { + "@localazy/languages": "^0.1.6", + "lodash-es": "^4.17.21" + } + }, + "@localazy/generic-connector-client": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@localazy/generic-connector-client/-/generic-connector-client-0.2.3.tgz", + "integrity": "sha512-o0CL0ils+rwQurWRlrV5BRnesERC4XO3HwFDtJFES6ZzZHtUZplpAvi+yhUfaxSfbnJHC49tc3TMSTGSNfoZBw==", + "requires": { + "@localazy/languages": "^0.1.6", + "lodash-es": "^4.17.21" + } + }, + "@localazy/languages": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@localazy/languages/-/languages-0.1.9.tgz", + "integrity": "sha512-XgCOu1aQI9P0zmq9wIU+mpJJbkaHnajuItrs4CXr/6EyGaZe3Of9uIk76p8iYCd5RXYeqZPd513MgEl8C1m1HQ==" + }, "@localazy/ts-api": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@localazy/ts-api/-/ts-api-1.0.13.tgz", - "integrity": "sha512-WmWkoRfTtyrtBHyzhnk7nVLW/YQb6ePBAKAUobwQaCmxLAHUOSx8MGyg7I6VYJLofE1EQzg8crJgZhtvKeSF6g==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@localazy/ts-api/-/ts-api-1.1.0.tgz", + "integrity": "sha512-0iLFWRxmKPkuruASye4A6CQoYMDGLqQmPLS76zKhPywwNTc89oIlaWrkl63c2EP70NzHxKu6BnpmJAjqFSeXrg==" }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", @@ -37448,9 +37495,9 @@ "peer": true }, "follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "peer": true }, "for-each": { @@ -41173,8 +41220,7 @@ "lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "peer": true + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "lodash.debounce": { "version": "4.0.8", diff --git a/package.json b/package.json index dcfe651..3bcbad3 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,9 @@ }, "dependencies": { "@david-vaclavek/deep-keys": "^0.5.0", - "@localazy/ts-api": "^1.0.13", + "@localazy/api-client": "^2.1.5", + "@localazy/generic-connector-client": "^0.2.3", + "@localazy/ts-api": "^1.1.0", "chalk": "^5.3.0", "fs-extra": "^11.1.1", "i18next": "^22.4.9", diff --git a/server/controllers/index.js b/server/controllers/index.js index 3158198..9eb5d0e 100644 --- a/server/controllers/index.js +++ b/server/controllers/index.js @@ -1,6 +1,5 @@ "use strict"; -const myController = require("./my-controller"); const localazyUserController = require("./localazy-user-controller"); const localazyAuthController = require("./localazy-auth-controller"); const strapiController = require("./strapi-controller"); @@ -9,7 +8,6 @@ const localazyTransferController = require("./localazy-transfer-controller"); const localazyProjectController = require("./localazy-project-controller"); module.exports = { - myController, localazyUserController, localazyAuthController, strapiController, diff --git a/server/controllers/localazy-auth-controller.js b/server/controllers/localazy-auth-controller.js index c719e6e..fd411e0 100644 --- a/server/controllers/localazy-auth-controller.js +++ b/server/controllers/localazy-auth-controller.js @@ -1,46 +1,22 @@ "use strict"; +const localazyGenericConnectorClientFactory = require("../utils/localazy-generic-connector-client-factory"); + module.exports = { async generateKeys(ctx) { - ctx.body = await strapi - .plugin("localazy") - .service("localazyAuthService") - .generateKeys(); + const GenericConnectorApi = await localazyGenericConnectorClientFactory(); + ctx.body = await GenericConnectorApi.public.keys(); }, async continuousPoll(ctx) { - const POLLING_LIMIT = 60; - const INTERVAL_PERIOD = 2000; // ms - const localazyAuthService = strapi - .plugin("localazy") - .service("localazyAuthService"); - - let counter = 1; + // init continuous poll const { readKey } = ctx.query; - let result = await localazyAuthService.completeLogin(readKey); - - let data = { - success: false, - }; - if (!result.completed) { - data = await new Promise((resolve, reject) => { - const pollInterval = setInterval(async () => { - result = await localazyAuthService.completeLogin(readKey); - - if (result.completed) { - clearInterval(pollInterval); - resolve(result.data); - } - - counter += 1; - if (counter >= POLLING_LIMIT) { - clearInterval(pollInterval); - reject(new Error("Sign in attempts timed out.")); - } - }, INTERVAL_PERIOD); - }); - } + const GenericConnectorApi = await localazyGenericConnectorClientFactory(); + const pollResult = await GenericConnectorApi.oauth.continuousPoll({ + readKey, + }); + const pollResultData = pollResult.data; - ctx.body = data; + ctx.body = pollResultData; }, }; diff --git a/server/controllers/my-controller.js b/server/controllers/my-controller.js deleted file mode 100644 index d25538a..0000000 --- a/server/controllers/my-controller.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; - -module.exports = { - index(ctx) { - ctx.body = strapi - .plugin("localazy") - .service("myService") - .getWelcomeMessage(); - }, -}; diff --git a/server/controllers/strapi-controller.js b/server/controllers/strapi-controller.js index d14965d..335132c 100644 --- a/server/controllers/strapi-controller.js +++ b/server/controllers/strapi-controller.js @@ -16,4 +16,12 @@ module.exports = { async postLifecycleLocalazyWebhooks(ctx) { strapi.log("done"); }, + async getPluginVersion(ctx) { + ctx.body = { + version: await strapi + .plugin("localazy") + .service("strapiService") + .getPluginVersion() + } + } }; diff --git a/server/lifecycles/deprecate-event-entry-in-localazy-hook.js b/server/lifecycles/deprecate-event-entry-in-localazy-hook.js index 777abfa..2bfc1bb 100644 --- a/server/lifecycles/deprecate-event-entry-in-localazy-hook.js +++ b/server/lifecycles/deprecate-event-entry-in-localazy-hook.js @@ -2,7 +2,7 @@ const getPickedFlattenKeysForHookEntry = require('../utils/get-picked-flatten-keys-for-hook-entry'); const config = require("../config").default; -const getLocalazyApi = require("../utils/get-localazy-api"); +const localazyApiClientFactory = require("../utils/localazy-api-client-factory"); const delay = require("../utils/delay"); module.exports = async (event) => { @@ -20,9 +20,6 @@ module.exports = async (event) => { const LocalazyPubApiService = strapi .plugin("localazy") .service("localazyPubApiService"); - const LocalazyDownloadService = strapi - .plugin("localazy") - .service("localazyDownloadService"); const user = await LocalazyUserService.getUser(); @@ -37,24 +34,31 @@ module.exports = async (event) => { return; } - const projectKeys = await LocalazyDownloadService.download({ - projectId: user.project.id, - fileId: strapiFile.id, + const LocalazyApi = await localazyApiClientFactory(); + const projectKeys = await LocalazyApi.files.listKeys({ + project: user.project.id, + file: strapiFile.id, lang: eventEntryLocale, }); + if(!projectKeys) { + strapi.log.error(`Keys not found for file ${strapiFile.id}`); + return { + success: false, + }; + } + const pickedFlattenKeys = Object.keys(pickedFlatten); - const filteredProjectKeysIds = projectKeys.data + const filteredProjectKeysIds = projectKeys .filter((key) => pickedFlattenKeys.includes(key.key[0])) .map((key) => key.id); - const LocalazyApi = await getLocalazyApi(); // call in a loop in a sequence, to avoid hitting PubAPI limits for (const filteredProjectKeysId of filteredProjectKeysIds) { try { - await LocalazyApi.updateKey({ - projectId: user.project.id, - keyId: filteredProjectKeysId, + await LocalazyApi.keys.update({ + project: user.project.id, + key: filteredProjectKeysId, deprecated: 0, }); await delay(); diff --git a/server/lifecycles/upload-event-entry-to-localazy-hook.js b/server/lifecycles/upload-event-entry-to-localazy-hook.js index 7adbeff..3820352 100644 --- a/server/lifecycles/upload-event-entry-to-localazy-hook.js +++ b/server/lifecycles/upload-event-entry-to-localazy-hook.js @@ -17,15 +17,20 @@ module.exports = async (event) => { .plugin("localazy") .service("localazyUploadService"); - const chunks = LocalazyUploadService.splitToChunks(pickedFlatten); const importFile = LocalazyUploadService.createImportFileRepresentation( - config.LOCALAZY_DEFAULT_FILE_NAME, - config.LOCALAZY_DEFAULT_FILE_PATH, - config.LOCALAZY_DEFAULT_FILE_EXTENSION, eventEntryLocale, - chunks + pickedFlatten ); - const result = await LocalazyUploadService.upload(importFile); + const uploadConfig = { + contentOptions: { + type: config.LOCALAZY_DEFAULT_FILE_EXTENSION, + }, + fileOptions: { + name: config.LOCALAZY_DEFAULT_FILE_NAME, + path: config.LOCALAZY_DEFAULT_FILE_PATH, + } + }; + const result = await LocalazyUploadService.upload(importFile, uploadConfig); return result; } diff --git a/server/models/supported-custom-field-plugins.js b/server/models/supported-custom-field-plugins.js index 7f0c67e..44dfc53 100644 --- a/server/models/supported-custom-field-plugins.js +++ b/server/models/supported-custom-field-plugins.js @@ -1,5 +1,6 @@ const SUPPORTED_CUSTOM_FIELD_PLUGINS = [ "plugin::ckeditor.CKEditor", + "plugin::ckeditor5.CKEditor", ]; module.exports = SUPPORTED_CUSTOM_FIELD_PLUGINS; diff --git a/server/routes/strapi.js b/server/routes/strapi.js index b4d461e..8a24a52 100644 --- a/server/routes/strapi.js +++ b/server/routes/strapi.js @@ -27,4 +27,12 @@ module.exports = [ policies: [], }, }, + { + method: "GET", + path: `${ROUTE_PREFIX}/version`, + handler: "strapiController.getPluginVersion", + config: { + policies: [], + }, + }, ]; diff --git a/server/services/index.js b/server/services/index.js index 06e263f..bd88cba 100644 --- a/server/services/index.js +++ b/server/services/index.js @@ -1,11 +1,9 @@ "use strict"; const localazyUserService = require("./localazy-user-service"); -const localazyAuthService = require("./localazy-auth-service"); const strapiService = require("./strapi-service"); const pluginSettingsService = require("./plugin-settings-service"); const localazyUploadService = require("./localazy-upload-service"); -const localazyDownloadService = require("./localazy-download-service"); const localazyPubApiService = require("./localazy-pubapi-service"); const strapiI18nService = require("./strapi-i18n-service"); const strapiLocalazyI18nService = require("./strapi-localazy-i18n-service"); @@ -14,11 +12,9 @@ const localazyTransferDownloadService = require("./localazy-transfer-download-se module.exports = { localazyUserService, - localazyAuthService, strapiService, pluginSettingsService, localazyUploadService, - localazyDownloadService, localazyPubApiService, strapiI18nService, strapiLocalazyI18nService, diff --git a/server/services/localazy-auth-service.js b/server/services/localazy-auth-service.js deleted file mode 100644 index c7a0709..0000000 --- a/server/services/localazy-auth-service.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; - -const axios = require("axios"); -const config = require("../config"); - -const ROOT_URL = config.default.LOCALAZY_PLUGIN_CONNECTOR_API_URL; -const PLUGIN_ID = config.default.LOCALAZY_PLUGIN_ID; - -module.exports = (/* { strapi } */) => ({ - async generateKeys() { - try { - const result = await axios.get(`${ROOT_URL}/public/keys`, { - headers: { - "X-Localazy-Plugin-Id": PLUGIN_ID, - }, - }); - return result.data; - } catch (e) { - throw e.data; - } - }, - - async completeLogin(readKey) { - try { - const result = await axios.get( - `${ROOT_URL}/oauth/poll?readKey=${readKey}`, - { - headers: { - "X-Localazy-Plugin-Id": PLUGIN_ID, - }, - } - ); - return result.data; - } catch (e) { - throw e.data; - } - }, -}); diff --git a/server/services/localazy-download-service.js b/server/services/localazy-download-service.js deleted file mode 100644 index d33e5c0..0000000 --- a/server/services/localazy-download-service.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; - -const getLocalazyApi = require("../utils/get-localazy-api"); -const delay = require("../utils/delay"); - -const fetchChunkResult = async (projectId, fileId, lang, next) => { - try { - const LocalazyApi = await getLocalazyApi(); - const chunkResult = await LocalazyApi.listKeysInFileForLanguage({ - projectId, - fileId, - lang, - next, - }); - - return chunkResult; - } catch (e) { - strapi.log.error(e); - return { - keys: [], - }; - } -}; - -module.exports = ({ strapi }) => ({ - async download(config = {}) { - try { - const data = []; - let chunkResult; - do { - const next = (chunkResult && chunkResult.next) || ""; - chunkResult = await fetchChunkResult( - config.projectId, - config.fileId, - config.lang, - next - ); - await delay(); - data.push(chunkResult); - } while (chunkResult.next); - - return { - success: true, - data: data.map((chunk) => chunk.keys).flat(), - }; - } catch (e) { - strapi.log.error(e); - return { - success: false, - message: e.message, - }; - } - }, -}); diff --git a/server/services/localazy-pubapi-service.js b/server/services/localazy-pubapi-service.js index dab27f1..a6d8591 100644 --- a/server/services/localazy-pubapi-service.js +++ b/server/services/localazy-pubapi-service.js @@ -1,13 +1,13 @@ "use strict"; -const getLocalazyApi = require("../utils/get-localazy-api"); +const localazyApiClientFactory = require("../utils/localazy-api-client-factory"); const config = require("../config").default; module.exports = ({ strapi }) => ({ async listFiles(projectId) { try { - const LocalazyApi = await getLocalazyApi(); - const result = await LocalazyApi.listFiles({ projectId }); + const LocalazyApi = await localazyApiClientFactory(); + const result = await LocalazyApi.files.list({ project: projectId }); return result; } catch (e) { @@ -27,8 +27,8 @@ module.exports = ({ strapi }) => ({ }, async listProjects(addOrganization = true, addLanguages = true) { try { - const LocalazyApi = await getLocalazyApi(); - const result = await LocalazyApi.listProjects({ + const LocalazyApi = await localazyApiClientFactory(); + const result = await LocalazyApi.projects.list({ organization: addOrganization, languages: addLanguages, }); @@ -45,8 +45,8 @@ module.exports = ({ strapi }) => ({ return projects.find((project) => project.id === projectId); }, async getWebhooksSecret(projectId) { - const LocalazyApi = await getLocalazyApi(); - const result = await LocalazyApi.getWebhooksSecret({ projectId }); + const LocalazyApi = await localazyApiClientFactory(); + const result = await LocalazyApi.webhooks.getSecret({ project: projectId }); return result; } diff --git a/server/services/localazy-transfer-download-service.js b/server/services/localazy-transfer-download-service.js index 48a7d94..5397deb 100644 --- a/server/services/localazy-transfer-download-service.js +++ b/server/services/localazy-transfer-download-service.js @@ -13,6 +13,7 @@ const isEmpty = require("lodash/isEmpty"); const RequestInitiatorHelper = require('../utils/request-initiator-helper'); const PluginSettingsServiceHelper = require('../services/helpers/plugin-settings-service-helper'); const { DOWNLOAD_EVENT, DOWNLOAD_FINISHED_EVENT } = require('../constants/events'); +const localazyApiClientFactory = require("../utils/localazy-api-client-factory"); const getFilteredLanguagesCodesForDownload = async (languagesCodes) => { const pluginSettingsServiceHelper = new PluginSettingsServiceHelper(strapi); @@ -63,9 +64,6 @@ module.exports = ({ strapi }) => ({ const LocalazyPubApiService = strapi .plugin("localazy") .service("localazyPubApiService"); - const LocalazyDownloadService = strapi - .plugin("localazy") - .service("localazyDownloadService"); const strapiLocalazyI18nService = strapi .plugin("localazy") .service("strapiLocalazyI18nService"); @@ -204,19 +202,19 @@ module.exports = ({ strapi }) => ({ (languageCode) => !strapiUnsupportedLanguages.includes(languageCode) ); const localazyContent = {}; + const LocalazyApi = await localazyApiClientFactory(); for (const isoLocalazy of supportedLanguages) { const isoStrapi = isoLocalazyToStrapi(isoLocalazy); - const result = await LocalazyDownloadService.download({ - projectId: user.project.id, - fileId: strapiFile.id, + const langKeys = await LocalazyApi.files.listKeys({ + project: user.project.id, + file: strapiFile.id, lang: isoStrapi, }); - if (!result.success) { + if (!langKeys) { await JobNotificationService.emit(DOWNLOAD_EVENT, { - message: result.message, + message: `No keys found for language ${isoLocalazy}`, }); } - const langKeys = result.data; localazyContent[isoLocalazy] = langKeys; } diff --git a/server/services/localazy-transfer-upload-service.js b/server/services/localazy-transfer-upload-service.js index b585cd7..8b402ff 100644 --- a/server/services/localazy-transfer-upload-service.js +++ b/server/services/localazy-transfer-upload-service.js @@ -146,17 +146,21 @@ module.exports = ({ strapi }) => ({ ? isoStrapiToLocalazy(defaultLocale.code) : config.LOCALAZY_DEFAULT_LOCALE; - const chunks = LocalazyUploadService.splitToChunks(flattenContent); const importFile = LocalazyUploadService.createImportFileRepresentation( - config.LOCALAZY_DEFAULT_FILE_NAME, - config.LOCALAZY_DEFAULT_FILE_PATH, - config.LOCALAZY_DEFAULT_FILE_EXTENSION, locale, - chunks + flattenContent ); - // Use `deprecate: "file"` if there is one chunk of transferred data only! - const hasMoreTransferFilesChunks = importFile.length > 1; - const uploadConfig = !hasMoreTransferFilesChunks ? { deprecate: "file" } : {}; + // Use `deprecate: "file"` if there is one chunk of transferred data only (99900 keys)! + const uploadConfig = { + contentOptions: { + type: config.LOCALAZY_DEFAULT_FILE_EXTENSION, + }, + i18nOptions: { deprecate: "file" }, + fileOptions: { + name: config.LOCALAZY_DEFAULT_FILE_NAME, + path: config.LOCALAZY_DEFAULT_FILE_PATH, + } + }; await JobNotificationService.emit(UPLOAD_EVENT, { message: "Uploading collections to Localazy...", }); diff --git a/server/services/localazy-upload-service.js b/server/services/localazy-upload-service.js index 99d137d..40b64a6 100644 --- a/server/services/localazy-upload-service.js +++ b/server/services/localazy-upload-service.js @@ -2,9 +2,7 @@ "use strict"; -const getLocalazyApi = require("../utils/get-localazy-api"); -const delay = require("../utils/delay"); -const config = require("../config").default; +const localazyApiClientFactory = require("../utils/localazy-api-client-factory"); module.exports = ({ strapi }) => ({ /** @@ -12,31 +10,24 @@ module.exports = ({ strapi }) => ({ * Use config to adjust the upload process. * Returns status and id of a last chunk */ - async upload(files, config = {}) { - let ret = { - success: false, - message: "No data was uploaded", - }; + async upload(file, config = {}) { try { - for (const file of files) { - const LocalazyApi = await getLocalazyApi(); - const user = await strapi - .plugin("localazy") - .service("localazyUserService") - .getUser(); + const LocalazyApi = await localazyApiClientFactory(); + const user = await strapi + .plugin("localazy") + .service("localazyUserService") + .getUser(); + + const result = await LocalazyApi.import.json({ + project: user.project.id, + json: file, + ...config, + }); - const result = await LocalazyApi.import({ - projectId: user.project.id, - files: file, - ...config, - }); - await delay(); - ret = { - success: true, - result: result.result, - }; - } - return ret; + return { + success: true, + result, + }; } catch (e) { strapi.log.error(e); return { @@ -46,57 +37,16 @@ module.exports = ({ strapi }) => ({ } }, - /** - * Check Directus for the Lifted Limits OAuth Apps IDs - */ - CHUNK_LIMIT: config.LOCALAZY_PUBLIC_API_LIFTED_LIMITS ? 99900 : 9990, - - splitToChunks(data, CHUNK_LIMIT = null) { - const chunks = []; - const keys = Object.keys(data); - const keysCount = keys.length; - const localChunkLimit = CHUNK_LIMIT || this.CHUNK_LIMIT; - const chunksCount = Math.ceil(keysCount / localChunkLimit); - for (let i = 0; i < chunksCount; i += 1) { - const chunkStrings = {}; - const from = localChunkLimit * i; - const to = localChunkLimit * (i + 1); - - const currentKeys = keys.slice(from, to); - currentKeys.forEach((key) => { - chunkStrings[key] = data[key]; - }); - chunks.push(chunkStrings); - } - - return chunks; - }, - createImportFileRepresentation( - filename, - path, - type, sourceLang, - stringsChunks + strings ) { - const files = []; - - for (const strings of stringsChunks) { - const file = [ - { - name: filename, - path, - content: { - type, - [sourceLang]: { - ...strings, - }, - }, - }, - ]; - files.push(file); - } + const file = { + [sourceLang]: { + ...strings, + }, + }; - return files; + return file; }, }); diff --git a/server/services/strapi-service.js b/server/services/strapi-service.js index 633e0bf..c70894d 100644 --- a/server/services/strapi-service.js +++ b/server/services/strapi-service.js @@ -20,4 +20,7 @@ module.exports = ({ strapi }) => ({ const models = strapi.db.config.models; return buildPopulate(models, modelUid); }, + async getPluginVersion() { + return require("../../package.json").version; + } }); diff --git a/server/utils/get-localazy-api.js b/server/utils/localazy-api-client-factory.js similarity index 69% rename from server/utils/get-localazy-api.js rename to server/utils/localazy-api-client-factory.js index d039d95..587c616 100644 --- a/server/utils/get-localazy-api.js +++ b/server/utils/localazy-api-client-factory.js @@ -1,6 +1,6 @@ "use strict"; -const LocalazyApi = require("@localazy/ts-api").default; +const ApiClient = require("@localazy/api-client").ApiClient; const { LOCALAZY_PUBLIC_API_URL } = require("../config").default; module.exports = async () => { @@ -14,9 +14,9 @@ module.exports = async () => { throw new Error("Localazy user is not logged in."); } - const api = LocalazyApi({ - projectToken: accessToken, - baseUrl: LOCALAZY_PUBLIC_API_URL, + const api = new ApiClient({ + authToken: accessToken, + apiUrl: LOCALAZY_PUBLIC_API_URL, }); return api; }; diff --git a/server/utils/localazy-generic-connector-client-factory.js b/server/utils/localazy-generic-connector-client-factory.js new file mode 100644 index 0000000..92af3d4 --- /dev/null +++ b/server/utils/localazy-generic-connector-client-factory.js @@ -0,0 +1,15 @@ +"use strict"; + +const GenericConnectorClient = require("@localazy/generic-connector-client").GenericConnectorClient; +const config = require("../config"); + +const ROOT_URL = config.default.LOCALAZY_PLUGIN_CONNECTOR_API_URL; +const PLUGIN_ID = config.default.LOCALAZY_PLUGIN_ID; + +module.exports = async () => { + const api = new GenericConnectorClient({ + pluginId: PLUGIN_ID, + genericConnectorUrl: ROOT_URL, + }); + return api; +};