@shoper/cli 0.1.0-9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli/auth/cli_auth_errors_factory.js +1 -1
- package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +1 -1
- package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +1 -1
- package/build/cli/class/errors/file_system_errors_factory.js +1 -1
- package/build/cli/class/errors/http/http_errors_constants.js +1 -0
- package/build/cli/class/errors/{http_errors_factory.js → http/http_errors_factory.js} +3 -2
- package/build/cli/commands/auth/cli_auth_add_token_command.js +22 -19
- package/build/cli/commands/auth/cli_auth_commands_constants.js +3 -0
- package/build/cli/commands/auth/cli_auth_commands_utils.js +46 -0
- package/build/cli/commands/auth/cli_auth_list_tokens_command.js +19 -6
- package/build/cli/commands/auth/cli_auth_remove_token_command.js +36 -10
- package/build/cli/commands/auth/cli_auth_switch_token_command.js +19 -9
- package/build/cli/commands/auth/ui/invalid_token_index_error.js +11 -0
- package/build/cli/commands/auth/ui/missing_credentials_error.js +9 -0
- package/build/cli/commands/auth/ui/missing_token_index_error.js +19 -0
- package/build/cli/commands/cli_ui_dump_command.js +11 -0
- package/build/cli/commands/cli_update_command.js +13 -4
- package/build/cli/commands/commands_constants.js +2 -1
- package/build/cli/core/cli_setup.js +5 -1
- package/build/cli/features/controls/controls_constants.js +12 -0
- package/build/cli/features/controls/controls_dto_mappers.js +55 -0
- package/build/cli/features/controls/ui/controls_mappers.js +62 -0
- package/build/cli/features/controls/ui/form.js +4 -0
- package/build/cli/features/controls/ui/form_constants.js +7 -0
- package/build/cli/features/controls/validators/greater_eq_than_validator.js +5 -0
- package/build/cli/features/controls/validators/length_validator.js +6 -0
- package/build/cli/features/controls/validators/required_validator.js +5 -0
- package/build/cli/features/controls/validators/validator_constants.js +13 -0
- package/build/cli/features/execution_context/execution_context_service.js +5 -5
- package/build/cli/features/http_requester/http_requester_initializer.js +1 -1
- package/build/cli/hooks/authorization/ensure_authorization_hook.js +2 -2
- package/build/cli/hooks/authorization/ensure_authorization_hook_constants.js +8 -8
- package/build/index.js +37 -19
- package/build/theme/class/checksums/theme_checksums.js +174 -0
- package/build/theme/{features/theme/utils → class}/checksums/theme_checksums_error_factory.js +1 -1
- package/build/theme/class/checksums/theme_checksums_utils.js +17 -0
- package/build/theme/class/fetch_resources/fetch_resources.js +1 -0
- package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +1 -1
- package/build/theme/class/fetch_resources/fetch_resources_utils.js +4 -1
- package/build/theme/commands/delete/theme_delete_command.js +111 -0
- package/build/theme/commands/delete/ui/theme_deleted_successfully.js +15 -0
- package/build/theme/commands/delete/ui/theme_deletion_warning.js +10 -0
- package/build/theme/commands/info/theme_info_command.js +94 -0
- package/build/theme/commands/info/theme_info_command_utils.js +39 -0
- package/build/theme/commands/init/theme_init_command.js +97 -0
- package/build/theme/commands/init/ui/theme_created_success.js +15 -0
- package/build/theme/commands/list/theme_list_command.js +25 -0
- package/build/theme/commands/list/theme_list_command_utils.js +27 -0
- package/build/theme/commands/publish/theme_publish_command.js +92 -0
- package/build/theme/commands/pull/theme_pull_command.js +194 -0
- package/build/theme/commands/pull/ui/theme_pull_id_mismatch_error.js +7 -0
- package/build/theme/commands/pull/ui/theme_pull_unpublished_changes_warning.js +10 -0
- package/build/theme/commands/pull/ui/theme_pulled_success.js +5 -0
- package/build/theme/commands/push/theme_push_command.js +134 -0
- package/build/theme/commands/push/ui/theme_push_skip_into.js +7 -0
- package/build/theme/commands/push/ui/theme_pushed_success.js +5 -0
- package/build/theme/commands/push/ui/theme_unpermitted_actions_error.js +12 -0
- package/build/theme/commands/theme_commands_constants.js +4 -1
- package/build/theme/commands/theme_show_changes_command.js +1 -0
- package/build/theme/commands/theme_verify_command.js +8 -7
- package/build/theme/commands/ui/invalid_theme_id.js +11 -0
- package/build/theme/commands/ui/missing_theme_files.js +15 -0
- package/build/theme/commands/ui/missing_theme_id_error.js +13 -0
- package/build/theme/commands/ui/ouside_of_theme_directory_context_error.js +7 -0
- package/build/theme/commands/ui/theme_directory_context_error.js +7 -0
- package/build/theme/commands/ui/theme_work_url_mismatch.js +17 -0
- package/build/theme/commands/ui/unpermitted_command_error.js +18 -0
- package/build/theme/features/theme/actions/api/theme_actions_api.js +3 -0
- package/build/theme/features/theme/actions/service/theme_actions_service.js +15 -3
- package/build/theme/features/theme/actions/service/theme_actions_service_constants.js +1 -0
- package/build/theme/features/theme/actions/theme_actions_constants.js +3 -1
- package/build/theme/features/theme/actions/theme_actions_initializer.js +1 -1
- package/build/theme/features/theme/actions/theme_actions_utils.js +20 -7
- package/build/theme/features/theme/delete/api/theme_delete_api.js +13 -0
- package/build/theme/features/theme/delete/http/theme_delete_http_api.js +17 -0
- package/build/theme/features/theme/delete/service/theme_delete_service.js +31 -0
- package/build/theme/features/theme/delete/theme_delete_constants.js +2 -0
- package/build/theme/features/theme/delete/theme_delete_initalizer.js +20 -0
- package/build/theme/features/theme/fetch/service/theme_fetch_service.js +30 -10
- package/build/theme/features/theme/info/theme_info_utils.js +9 -0
- package/build/theme/features/theme/init/service/theme_init_service.js +9 -4
- package/build/theme/features/theme/merge/api/theme_merge_api.js +0 -12
- package/build/theme/features/theme/merge/service/theme_merge_service.js +20 -28
- package/build/theme/features/theme/push/service/theme_push_service.js +92 -69
- package/build/theme/features/theme/push/theme_push_constants.js +2 -0
- package/build/theme/features/theme/push/theme_push_errors_factory.js +7 -4
- package/build/theme/features/theme/push/theme_push_initializer.js +0 -3
- package/build/theme/features/theme/push/theme_push_utils.js +25 -0
- package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +19 -0
- package/build/theme/features/theme/skinstore/http/theme_skinstore_http_api.js +17 -0
- package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +32 -0
- package/build/theme/features/theme/skinstore/theme_publish_constants.js +4 -0
- package/build/theme/features/theme/skinstore/theme_skinstore_initialzier.js +20 -0
- package/build/theme/features/theme/utils/files_structure/theme_files_structure_utils.js +40 -0
- package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +32 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_constants.js +1 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +15 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_utils.js +39 -0
- package/build/theme/features/theme/utils/{directories → resources}/theme_resources_with_id_directory_utils.js +3 -14
- package/build/theme/features/theme/utils/theme_images_utils.js +1 -1
- package/build/theme/features/themes/list/api/themes_list_api.js +3 -0
- package/build/theme/features/themes/list/services/themes_list_service.js +13 -7
- package/build/theme/hooks/{ensure_theme_meta_data_untouched.js → ensure_theme_meta_data_untouched_hook.js} +2 -2
- package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_constants.js +1 -1
- package/build/theme/hooks/theme_checksums/{ensure_theme_current_checksums_up_to_date.js → ensure_theme_current_checksums_up_to_date_hook.js} +2 -5
- package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +1 -0
- package/build/theme/hooks/themes_actions/ensure_themes_actions_hook_constants.js +1 -0
- package/build/theme/index.js +11 -5
- package/build/theme/utils/directory_validator/directory_validator_constants.js +2 -6
- package/build/theme/utils/directory_validator/directory_validator_utils.js +7 -25
- package/build/ui/box.js +2 -0
- package/build/ui/color_constants.js +30 -0
- package/build/ui/command.js +6 -0
- package/build/ui/file_name.js +6 -0
- package/build/ui/flag.js +6 -0
- package/build/ui/icons/error_icon.js +7 -0
- package/build/ui/icons/info_icon.js +7 -0
- package/build/ui/icons/success_icon.js +7 -0
- package/build/ui/icons/warning_icon.js +7 -0
- package/build/ui/link.js +8 -0
- package/build/ui/list/list.js +10 -0
- package/build/ui/list/list_constants.js +4 -0
- package/build/ui/list/list_item.js +11 -0
- package/build/ui/message_box/error.js +4 -0
- package/build/ui/message_box/info.js +4 -0
- package/build/ui/message_box/message_box.js +11 -0
- package/build/ui/message_box/message_box_constants.js +24 -0
- package/build/ui/message_box/success.js +4 -0
- package/build/ui/message_box/warning.js +4 -0
- package/build/ui/prompts/prompt_confirmation.js +11 -0
- package/build/ui/prompts/prompt_input.js +10 -0
- package/build/ui/table/t_cell.js +7 -0
- package/build/ui/table/t_header.js +9 -0
- package/build/ui/table/t_row.js +5 -0
- package/build/ui/table/table.js +18 -0
- package/build/ui/text.js +2 -0
- package/build/ui/tip.js +9 -0
- package/build/ui/ui_dump/ui_component_box.js +9 -0
- package/build/ui/ui_dump/ui_dump.js +53 -0
- package/build/ui/ui_dump/ui_dump_constants.js +21 -0
- package/build/ui/ui_utils.js +11 -0
- package/build/ui/validation_errors/validation_error_content.js +19 -0
- package/build/ui/validation_errors/validation_errors.js +21 -0
- package/build/ui/validation_errors/validation_errors_utils.js +17 -0
- package/build/utils/checksums/checksums_utils.js +9 -26
- package/build/utils/download_file/download_file_errors_factory.js +1 -1
- package/build/utils/download_file/download_file_utils.js +4 -2
- package/build/utils/fs/errors/stream_read_error.js +1 -1
- package/build/utils/fs/errors/stream_write_error.js +1 -1
- package/build/utils/fs/fs_utils.js +12 -1
- package/build/utils/path_utils.js +18 -2
- package/build/utils/platform_utils.js +3 -0
- package/build/utils/zip/create_zip_utils.js +1 -1
- package/build/utils/zip/errors/create_zip_error.js +1 -1
- package/build/utils/zip/errors/open_zip_error.js +1 -1
- package/oclif.config.js +2 -2
- package/package.json +13 -8
- package/build/theme/commands/theme_init_command.js +0 -53
- package/build/theme/commands/theme_list_command.js +0 -16
- package/build/theme/commands/theme_pull_command.js +0 -126
- package/build/theme/commands/theme_push_command.js +0 -65
- package/build/theme/features/theme/directory/theme_directory_utils.js +0 -76
- package/build/theme/features/theme/publish/theme_publish_constants.js +0 -2
- package/build/theme/features/theme/utils/checksums/theme_checksums_utils.js +0 -94
- /package/build/cli/{features → class}/caches/cache_factory.js +0 -0
- /package/build/cli/{features → class}/caches/json_cache/json_cache.js +0 -0
- /package/build/cli/{features → class}/caches/memory_cache.js +0 -0
- /package/build/cli/class/errors/{app_error → app}/app_error.js +0 -0
- /package/build/cli/class/errors/{app_error → app}/app_error_constants.js +0 -0
- /package/build/theme/features/theme/{publish → skinstore}/theme_publish_utils.js +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Info } from '../../../../ui/message_box/info.js';
|
|
3
|
+
import { Text } from '../../../../ui/text.js';
|
|
4
|
+
export const ThemePushSkipInfo = () => {
|
|
5
|
+
return (React.createElement(Info, null,
|
|
6
|
+
React.createElement(Text, null, "Nothing to push, skipped.")));
|
|
7
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { List } from '../../../../ui/list/list.js';
|
|
2
|
+
import { Error } from '../../../../ui/message_box/error.js';
|
|
3
|
+
import { Text } from '../../../../ui/text.js';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
export const ThemeUnpermittedActionsError = ({ unpermittedActions }) => {
|
|
6
|
+
const items = unpermittedActions.map((action) => ({
|
|
7
|
+
content: `${action.type} - ${action.relativePath}`
|
|
8
|
+
}));
|
|
9
|
+
return (React.createElement(Error, { header: "Theme validation error" },
|
|
10
|
+
React.createElement(Text, null, "Theme file structure is not valid. The following actions are not permitted:"),
|
|
11
|
+
React.createElement(List, { items: items })));
|
|
12
|
+
};
|
|
@@ -9,6 +9,7 @@ import { join } from '../../utils/path_utils.js';
|
|
|
9
9
|
import ora from 'ora';
|
|
10
10
|
export class ThemeShowChangesCommand extends BaseThemeCommand {
|
|
11
11
|
static description = 'Show local theme changes';
|
|
12
|
+
static hidden = true;
|
|
12
13
|
async run() {
|
|
13
14
|
const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
|
|
14
15
|
const credentials = cliAuthApi.getCredentials();
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { BaseThemeCommand } from '../class/base_theme_command.js';
|
|
2
2
|
import { CLI_AUTH_API_NAME } from '../../cli/auth/cli_auth_constants.js';
|
|
3
3
|
import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../cli/features/execution_context/execution_context_constants.js';
|
|
4
|
-
import { ThemeDirectoryUtils } from '../features/theme/directory/theme_directory_utils.js';
|
|
5
4
|
import { mapToPermissionsTree } from '../utils/directory_validator/directory_validator_utils.js';
|
|
6
5
|
import { mapChecksumToTree } from '../../utils/checksums/checksums_utils.js';
|
|
7
|
-
import {
|
|
6
|
+
import { ThemeFilesStructureUtils } from '../features/theme/utils/files_structure/theme_files_structure_utils.js';
|
|
7
|
+
import { ThemeChecksums } from '../class/checksums/theme_checksums.js';
|
|
8
8
|
export class ThemeVerifyCommand extends BaseThemeCommand {
|
|
9
9
|
static description = 'Verify theme files structure';
|
|
10
|
+
static hidden = true;
|
|
10
11
|
async run() {
|
|
11
12
|
const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
|
|
12
13
|
const credentials = cliAuthApi.getCredentials();
|
|
@@ -16,13 +17,13 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
|
|
|
16
17
|
const executionContext = await executionContextApi.getExecutionContext();
|
|
17
18
|
if (executionContext.type !== EXECUTION_CONTEXTS.theme)
|
|
18
19
|
this.error('You cannot run this command outside theme context.');
|
|
19
|
-
const
|
|
20
|
-
const permissions = await
|
|
21
|
-
if (!
|
|
20
|
+
const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
|
|
21
|
+
const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
|
|
22
|
+
if (!themeChecksums || !permissions)
|
|
22
23
|
this.error('Theme checksums or permissions not found. Please ensure you are in the correct theme directory.');
|
|
23
24
|
try {
|
|
24
|
-
const validationResult = await
|
|
25
|
-
checksums: mapChecksumToTree(
|
|
25
|
+
const validationResult = await ThemeFilesStructureUtils.validateThemeDirectoryStructure({
|
|
26
|
+
checksums: mapChecksumToTree(await themeChecksums.getInitialChecksums()),
|
|
26
27
|
permissions: mapToPermissionsTree(permissions),
|
|
27
28
|
rootDirectory: executionContext.themeRootDir
|
|
28
29
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
2
|
+
import { Tip } from '../../../ui/tip.js';
|
|
3
|
+
import { Command } from '../../../ui/command.js';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
export const InvalidThemeIdError = ({ themeId }) => {
|
|
6
|
+
return (React.createElement(Error, { header: `Error: Invalid theme ID: ${themeId}` },
|
|
7
|
+
React.createElement(Tip, null,
|
|
8
|
+
"Run ",
|
|
9
|
+
React.createElement(Command, null, "shoper theme list"),
|
|
10
|
+
" to see available theme IDs.")));
|
|
11
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
3
|
+
import { Text } from '../../../ui/text.js';
|
|
4
|
+
import { List } from '../../../ui/list/list.js';
|
|
5
|
+
import { Command } from '../../../ui/command.js';
|
|
6
|
+
export const MissingThemeFiles = ({ files }) => {
|
|
7
|
+
return (React.createElement(Error, { header: `Error: Detected local changes in: ${Array.isArray(files) ? '' : files}` },
|
|
8
|
+
Array.isArray(files) ? (React.createElement(List, { items: files.map((file) => ({
|
|
9
|
+
content: file
|
|
10
|
+
})) })) : null,
|
|
11
|
+
React.createElement(Text, null,
|
|
12
|
+
"This file is managed by the system and should not be modified locally. Please revert it to its original version manually or run",
|
|
13
|
+
React.createElement(Command, null, "shoper theme pull"),
|
|
14
|
+
" to download the correct version from the server.")));
|
|
15
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
3
|
+
import { Box } from '../../../ui/box.js';
|
|
4
|
+
import { Tip } from '../../../ui/tip.js';
|
|
5
|
+
import { Command } from '../../../ui/command.js';
|
|
6
|
+
export const MissingThemeIdError = ({ children }) => {
|
|
7
|
+
return (React.createElement(Error, { header: "Error: Missing theme ID." },
|
|
8
|
+
React.createElement(Box, null, children),
|
|
9
|
+
React.createElement(Tip, null,
|
|
10
|
+
"Run ",
|
|
11
|
+
React.createElement(Command, null, "shoper theme list"),
|
|
12
|
+
" to see available themes and their IDs.")));
|
|
13
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
2
|
+
import { Text } from '../../../ui/text.js';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
export const OutsideOfThemeDirectoryContextError = () => {
|
|
5
|
+
return (React.createElement(Error, null,
|
|
6
|
+
React.createElement(Text, null, "Error: Cannot run this command outside of a theme directory. Please run it inside a theme directory.")));
|
|
7
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
3
|
+
import { Text } from '../../../ui/text.js';
|
|
4
|
+
export const ThemeDirectoryContextError = () => {
|
|
5
|
+
return (React.createElement(Error, null,
|
|
6
|
+
React.createElement(Text, null, "Error: Cannot run this command inside a theme directory. Please run it outside of a theme directory.")));
|
|
7
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
3
|
+
import { Command } from '../../../ui/command.js';
|
|
4
|
+
import { Tip } from '../../../ui/tip.js';
|
|
5
|
+
import { Text } from '../../../ui/text.js';
|
|
6
|
+
export const ThemeWorkUrlMismatch = ({ command }) => {
|
|
7
|
+
return (React.createElement(Error, { header: `Error: This theme belongs to a different store.` },
|
|
8
|
+
React.createElement(Text, null,
|
|
9
|
+
"Switch to the correct token to ",
|
|
10
|
+
command,
|
|
11
|
+
" this theme."),
|
|
12
|
+
React.createElement(Tip, null,
|
|
13
|
+
React.createElement(Text, null,
|
|
14
|
+
"Run ",
|
|
15
|
+
React.createElement(Command, null, "shoper theme auth token switch"),
|
|
16
|
+
" to change your token"))));
|
|
17
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Text } from '../../../ui/text.js';
|
|
2
|
+
import { Tip } from '../../../ui/tip.js';
|
|
3
|
+
import { Command } from '../../../ui/command.js';
|
|
4
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
export const UnpermittedCommandError = ({ commandName, themeId }) => {
|
|
7
|
+
return (React.createElement(Error, null,
|
|
8
|
+
React.createElement(Text, null,
|
|
9
|
+
"You cannot ",
|
|
10
|
+
commandName,
|
|
11
|
+
" theme with id ",
|
|
12
|
+
themeId,
|
|
13
|
+
". Please check if the theme exists or if you have the necessary permissions."),
|
|
14
|
+
React.createElement(Tip, null,
|
|
15
|
+
"Run ",
|
|
16
|
+
React.createElement(Command, null, "shoper auth list-tokens"),
|
|
17
|
+
" to see available token index values.")));
|
|
18
|
+
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { STORE_THEMES_ACTIONS_TTL } from './theme_actions_service_constants.js';
|
|
2
|
-
import { AppError } from '../../../../../cli/class/errors/
|
|
2
|
+
import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
|
|
3
3
|
import { getNMinutesFromNow } from '../../../../../utils/date_utils.js';
|
|
4
4
|
import { computeChecksum } from '../../../../../utils/checksums/checksums_utils.js';
|
|
5
|
+
import { THEME_ACTION_NOT_FOUND_ERROR_CODE, THEME_ACTION_NOTS_FOUND_ERROR_CODE } from '../theme_actions_constants.js';
|
|
5
6
|
export class ThemeActionsService {
|
|
6
7
|
#themesListApi;
|
|
7
8
|
#themesActionsStore;
|
|
@@ -13,17 +14,28 @@ export class ThemeActionsService {
|
|
|
13
14
|
const storeActions = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
|
|
14
15
|
if (!storeActions)
|
|
15
16
|
throw new AppError({
|
|
16
|
-
code:
|
|
17
|
+
code: THEME_ACTION_NOTS_FOUND_ERROR_CODE,
|
|
17
18
|
message: `Theme actions for store ${credentials.shopUrl} not found.`
|
|
18
19
|
});
|
|
19
20
|
const actions = storeActions.actions[themeId];
|
|
20
21
|
if (!actions)
|
|
21
22
|
throw new AppError({
|
|
22
|
-
code:
|
|
23
|
+
code: THEME_ACTION_NOT_FOUND_ERROR_CODE,
|
|
23
24
|
message: `Theme action for theme ${themeId} not found.`
|
|
24
25
|
});
|
|
25
26
|
return actions[actionType];
|
|
26
27
|
}
|
|
28
|
+
removeThemeActions({ themeId, credentials }) {
|
|
29
|
+
const storeActions = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
|
|
30
|
+
if (!storeActions || !storeActions.actions[themeId]) {
|
|
31
|
+
throw new AppError({
|
|
32
|
+
code: THEME_ACTION_NOTS_FOUND_ERROR_CODE,
|
|
33
|
+
message: `Theme actions for store ${credentials.shopUrl} not found.`
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
delete storeActions.actions[themeId];
|
|
37
|
+
this.#themesActionsStore.set(this._getKey(credentials.shopUrl), storeActions);
|
|
38
|
+
}
|
|
27
39
|
async ensureThemesActions({ credentials, themeId }) {
|
|
28
40
|
if (!themeId)
|
|
29
41
|
return;
|
|
@@ -6,10 +6,12 @@ export const THEME_ACTIONS_TYPES = {
|
|
|
6
6
|
push: 'push',
|
|
7
7
|
pull: 'pull',
|
|
8
8
|
delete: 'delete',
|
|
9
|
-
|
|
9
|
+
publishForm: 'publish_form',
|
|
10
10
|
publish: 'publish'
|
|
11
11
|
};
|
|
12
12
|
export const THEME_ACTION_DATA_TYPE = {
|
|
13
13
|
file: 'file',
|
|
14
14
|
zip: 'zip'
|
|
15
15
|
};
|
|
16
|
+
export const THEME_ACTION_NOT_FOUND_ERROR_CODE = 'theme_action_not_found';
|
|
17
|
+
export const THEME_ACTION_NOTS_FOUND_ERROR_CODE = 'theme_actions_not_found';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AsyncFeatureInitializer, FEATURE_CORES_TYPES } from '@dreamcommerce/star_core';
|
|
2
2
|
import { THEMES_LIST_API_NAME } from '../../themes/list/themes_list_constants.js';
|
|
3
|
-
import { JsonCache } from '../../../../cli/
|
|
3
|
+
import { JsonCache } from '../../../../cli/class/caches/json_cache/json_cache.js';
|
|
4
4
|
import { CLI_DATA_DIRECTORY_API_NAME } from '../../../../cli/features/data_directory/cli_data_directory_constants.js';
|
|
5
5
|
import { THEME_ACTIONS_FEATURE_NAME, THEMES_ACTIONS_FILE_NAME } from './theme_actions_constants.js';
|
|
6
6
|
import { ThemeActionsApi } from './api/theme_actions_api.js';
|
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { THEME_ALL_ACTIONS_NAME } from './service/theme_actions_service_constants.js';
|
|
2
|
+
import { toUnixPath } from '../../../../utils/path_utils.js';
|
|
3
|
+
export class ThemeActionsUtils {
|
|
4
|
+
static getFilesGlobsThatMatchesActionName({ filesStructure, actionValue, actionType }) {
|
|
5
|
+
return Object.entries(filesStructure).reduce((acc, [filePath, fileStructureItem]) => {
|
|
6
|
+
if (fileStructureItem._links?.[actionType] && this._doesActionValueMatch(fileStructureItem._links[actionType], actionValue)) {
|
|
7
|
+
return [...acc, toUnixPath(filePath)];
|
|
8
|
+
}
|
|
9
|
+
return acc;
|
|
10
|
+
}, []);
|
|
11
|
+
}
|
|
12
|
+
static _doesActionValueMatch(currentActionValue, valuesToMatch) {
|
|
13
|
+
if (typeof valuesToMatch === 'string') {
|
|
14
|
+
return currentActionValue === valuesToMatch || valuesToMatch === THEME_ALL_ACTIONS_NAME;
|
|
5
15
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
16
|
+
if (Array.isArray(valuesToMatch)) {
|
|
17
|
+
return valuesToMatch.includes(currentActionValue) || valuesToMatch.includes(THEME_ALL_ACTIONS_NAME);
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FeatureApi } from '@dreamcommerce/star_core';
|
|
2
|
+
import { THEME_DELETE_API_NAME } from '../theme_delete_constants.js';
|
|
3
|
+
export class ThemeDeleteApi extends FeatureApi {
|
|
4
|
+
moduleName = THEME_DELETE_API_NAME;
|
|
5
|
+
#service;
|
|
6
|
+
constructor(service) {
|
|
7
|
+
super();
|
|
8
|
+
this.#service = service;
|
|
9
|
+
}
|
|
10
|
+
async deleteTheme(props) {
|
|
11
|
+
return this.#service.deleteTheme(props);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class ThemeDeleteHttpApi {
|
|
2
|
+
#httpApi;
|
|
3
|
+
constructor(httpApi) {
|
|
4
|
+
this.#httpApi = httpApi;
|
|
5
|
+
}
|
|
6
|
+
deleteTheme({ shopUrl, actionData }) {
|
|
7
|
+
const { method, url } = actionData;
|
|
8
|
+
return this.#httpApi.fetch({
|
|
9
|
+
url: `${shopUrl}${url}`,
|
|
10
|
+
method,
|
|
11
|
+
sanitizeOptions: {
|
|
12
|
+
disable: true
|
|
13
|
+
},
|
|
14
|
+
isPrivate: true
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_errors_factory.js';
|
|
2
|
+
import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
|
|
3
|
+
import { STATUS_CODES } from '@dreamcommerce/star_core';
|
|
4
|
+
export class ThemeDeleteService {
|
|
5
|
+
#httpApi;
|
|
6
|
+
constructor(httpApi) {
|
|
7
|
+
this.#httpApi = httpApi;
|
|
8
|
+
}
|
|
9
|
+
async deleteTheme({ actionData, credentials }) {
|
|
10
|
+
try {
|
|
11
|
+
const { response: request } = this.#httpApi.deleteTheme({ actionData, shopUrl: credentials.shopUrl });
|
|
12
|
+
const response = await request;
|
|
13
|
+
if (response?.status !== STATUS_CODES.ok)
|
|
14
|
+
return;
|
|
15
|
+
return response?.data;
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
//TODO to basic class
|
|
19
|
+
switch (err.response?.status) {
|
|
20
|
+
case 403:
|
|
21
|
+
throw HttpErrorsFactory.createForbiddenError();
|
|
22
|
+
case 401:
|
|
23
|
+
throw HttpErrorsFactory.createUnauthorizedError();
|
|
24
|
+
case 404:
|
|
25
|
+
throw HttpErrorsFactory.createNotFoundError();
|
|
26
|
+
default:
|
|
27
|
+
throw DownloadFileErrorsFactory.downloadError(err.response.status);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
|
|
2
|
+
import { ThemeDeleteApi } from './api/theme_delete_api.js';
|
|
3
|
+
import { ThemeDeleteService } from './service/theme_delete_service.js';
|
|
4
|
+
import { ThemeDeleteHttpApi } from './http/theme_delete_http_api.js';
|
|
5
|
+
import { THEME_DELETE_FEATURE_NAME } from './theme_delete_constants.js';
|
|
6
|
+
export class ThemeDeleteInitializer extends SyncFeatureInitializer {
|
|
7
|
+
static featureName = THEME_DELETE_FEATURE_NAME;
|
|
8
|
+
init() {
|
|
9
|
+
const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
|
|
10
|
+
const service = new ThemeDeleteService(new ThemeDeleteHttpApi(httpApi));
|
|
11
|
+
return {
|
|
12
|
+
cores: [
|
|
13
|
+
{
|
|
14
|
+
type: FEATURE_CORES_TYPES.api,
|
|
15
|
+
instance: new ThemeDeleteApi(service)
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -4,17 +4,18 @@ import { downloadFile } from '../../../../../utils/download_file/download_file_u
|
|
|
4
4
|
import { extractZip } from '../../../../../utils/zip/extract_zip_utils.js';
|
|
5
5
|
import { join } from '../../../../../utils/path_utils.js';
|
|
6
6
|
import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
|
|
7
|
-
import { getResources, mapResourcesToTree } from '../../../../class/fetch_resources/fetch_resources_utils.js';
|
|
7
|
+
import { getResources, mapResourcesToTree, removeOldResources } from '../../../../class/fetch_resources/fetch_resources_utils.js';
|
|
8
8
|
import { FetchResources } from '../../../../class/fetch_resources/fetch_resources.js';
|
|
9
9
|
import { jsonIndentTransform } from '../../../../../utils/stream_transforms/json_indent_transform.js';
|
|
10
|
-
import { ThemeDirectoryUtils } from '../../directory/theme_directory_utils.js';
|
|
11
10
|
import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
|
|
12
11
|
import { THEME_FILES_LIST_FILE_NAME } from '../../push/theme_push_constants.js';
|
|
13
12
|
import { JSON_FILE_INDENT } from '../../../../../cli/cli_constants.js';
|
|
14
|
-
import { computeChecksumsFromSource } from '../../../../../utils/checksums/checksums_utils.js';
|
|
15
|
-
import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
|
|
16
13
|
import { createWriteStream } from 'node:fs';
|
|
17
|
-
import { AppError } from '../../../../../cli/class/errors/
|
|
14
|
+
import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
|
|
15
|
+
import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
|
|
16
|
+
import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
|
|
17
|
+
import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
|
|
18
|
+
import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
|
|
18
19
|
export class ThemeFetchService {
|
|
19
20
|
#themeHttpApi;
|
|
20
21
|
#httpApi;
|
|
@@ -53,14 +54,17 @@ export class ThemeFetchService {
|
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
56
|
await this._createGitIgnoreFile(themeDir);
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
await this._updateMetadataFileWithWorkUrl(themeDir, credentials.shopUrl);
|
|
58
|
+
/**
|
|
59
|
+
* moze to nie powinno lezec tutaj :?
|
|
60
|
+
*/
|
|
61
|
+
await new ThemeChecksums(themeDir).updateAllChecksums();
|
|
58
62
|
return {
|
|
59
63
|
name: basename
|
|
60
64
|
};
|
|
61
65
|
}
|
|
62
66
|
async _updateFilesStructure(themeDir) {
|
|
63
|
-
const fileStructure = await
|
|
67
|
+
const fileStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDir);
|
|
64
68
|
const checksumsFiles = [
|
|
65
69
|
`${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_FILE_NAME}`,
|
|
66
70
|
`${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME}`,
|
|
@@ -76,7 +80,15 @@ export class ThemeFetchService {
|
|
|
76
80
|
}
|
|
77
81
|
};
|
|
78
82
|
});
|
|
79
|
-
[THEME_FILES_LIST_FILE_NAME
|
|
83
|
+
fileStructure[THEME_FILES_LIST_FILE_NAME] = {
|
|
84
|
+
permissions: {
|
|
85
|
+
canAdd: true,
|
|
86
|
+
canEdit: true,
|
|
87
|
+
canDelete: true
|
|
88
|
+
},
|
|
89
|
+
_links: { [THEME_ACTIONS_TYPES.push]: '*' }
|
|
90
|
+
};
|
|
91
|
+
['.gitignore'].forEach((fileName) => {
|
|
80
92
|
fileStructure[fileName] = {
|
|
81
93
|
permissions: {
|
|
82
94
|
canAdd: true,
|
|
@@ -85,9 +97,17 @@ export class ThemeFetchService {
|
|
|
85
97
|
}
|
|
86
98
|
};
|
|
87
99
|
});
|
|
88
|
-
await
|
|
100
|
+
await ThemeFilesStructureUtils.writeThemeFilesStructure(themeDir, fileStructure);
|
|
101
|
+
}
|
|
102
|
+
async _updateMetadataFileWithWorkUrl(themeDir, workUrl) {
|
|
103
|
+
const shopMetadata = await ThemeMetaDataUtils.getThemeMetadata(themeDir);
|
|
104
|
+
await ThemeMetaDataUtils.updateThemeMetadata(themeDir, {
|
|
105
|
+
...shopMetadata,
|
|
106
|
+
workUrl
|
|
107
|
+
});
|
|
89
108
|
}
|
|
90
109
|
async fetchResources(shopUrl, dist, resources) {
|
|
110
|
+
await removeOldResources(dist, resources);
|
|
91
111
|
const resourcesTree = mapResourcesToTree(resources);
|
|
92
112
|
await Promise.all(Object.keys(resourcesTree).map((resource) => new FetchResources(this.#httpApi).fetchResources({
|
|
93
113
|
resourcesPart: resourcesTree[resource],
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { readJSONFile } from '../../../../utils/fs/fs_utils.js';
|
|
2
|
+
import { join } from '../../../../utils/path_utils.js';
|
|
3
|
+
export class ThemeInfoUtils {
|
|
4
|
+
static async getThemeName(themeDir) {
|
|
5
|
+
//TODO - wziasc z themeList a to wywalic
|
|
6
|
+
const themeDetails = await readJSONFile(join(themeDir, 'settings', 'details.json'));
|
|
7
|
+
return themeDetails.name ?? 'Storefront';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -3,8 +3,9 @@ import process from 'process';
|
|
|
3
3
|
import tmp from 'tmp-promise';
|
|
4
4
|
import { downloadFile } from '../../../../../utils/download_file/download_file_utils.js';
|
|
5
5
|
import { extractZip } from '../../../../../utils/zip/extract_zip_utils.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
|
|
7
|
+
import { ThemeInfoUtils } from '../../info/theme_info_utils.js';
|
|
8
|
+
import { ThemeChecksums } from '../../../../../theme/class/checksums/theme_checksums.js';
|
|
8
9
|
export class ThemeInitService {
|
|
9
10
|
#httpApi;
|
|
10
11
|
constructor({ httpApi }) {
|
|
@@ -22,7 +23,11 @@ export class ThemeInitService {
|
|
|
22
23
|
source: join(tmpDir, filename),
|
|
23
24
|
dist: distDir
|
|
24
25
|
});
|
|
25
|
-
|
|
26
|
-
await
|
|
26
|
+
new ThemeChecksums(distDir).updateAllChecksums();
|
|
27
|
+
const themeMetaData = await ThemeMetaDataUtils.getThemeMetadata(distDir);
|
|
28
|
+
return {
|
|
29
|
+
themeId: themeMetaData.themeId,
|
|
30
|
+
themeName: await ThemeInfoUtils.getThemeName(distDir)
|
|
31
|
+
};
|
|
27
32
|
}
|
|
28
33
|
}
|
|
@@ -7,22 +7,10 @@ export class ThemeMergeApi extends FeatureApi {
|
|
|
7
7
|
super();
|
|
8
8
|
this.#service = service;
|
|
9
9
|
}
|
|
10
|
-
hasThemeBeenModified(themeRootDir) {
|
|
11
|
-
return this.#service.hasThemeBeenModified(themeRootDir);
|
|
12
|
-
}
|
|
13
10
|
getChangesBetweenThemes(theme1, theme2) {
|
|
14
11
|
return this.#service.getChangesBetweenThemes(theme1, theme2);
|
|
15
12
|
}
|
|
16
13
|
applyChanges(fromTheme, toTheme, changes) {
|
|
17
14
|
return this.#service.applyChanges(fromTheme, toTheme, changes);
|
|
18
15
|
}
|
|
19
|
-
hasFileBeenCreated(path, executionContext) {
|
|
20
|
-
return this.#service.hasFileBeenCreated(path, executionContext);
|
|
21
|
-
}
|
|
22
|
-
hasFileBeenRemoved(path, executionContext) {
|
|
23
|
-
return this.#service.hasFileBeenRemoved(path, executionContext);
|
|
24
|
-
}
|
|
25
|
-
hasFileBeenModified(path, executionContext) {
|
|
26
|
-
return this.#service.hasFileBeenModified(path, executionContext);
|
|
27
|
-
}
|
|
28
16
|
}
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import FSTree from 'fs-tree-diff';
|
|
2
|
-
import {
|
|
3
|
-
import { computeChecksumsFromSource, computeFileChecksum } from '../../../../../utils/checksums/checksums_utils.js';
|
|
4
|
-
import { copyFile, copyFileSync, fileExists } from '../../../../../utils/fs/fs_utils.js';
|
|
5
|
-
import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
|
|
2
|
+
import { copyFileSync, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
|
|
6
3
|
import walkSync from 'walk-sync';
|
|
4
|
+
import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
|
|
5
|
+
import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
|
|
7
6
|
import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
|
|
7
|
+
import { join, platformSeparator } from '../../../../../utils/path_utils.js';
|
|
8
8
|
export class ThemeMergeService {
|
|
9
9
|
async applyChanges(fromTheme, toTheme, changes) {
|
|
10
10
|
FSTree.applyPatch(fromTheme, toTheme, changes, {
|
|
11
11
|
create(inputPath, outputPath) {
|
|
12
|
-
|
|
12
|
+
copyFileSync(inputPath, outputPath);
|
|
13
13
|
},
|
|
14
14
|
change(inputPath, outputPath) {
|
|
15
15
|
copyFileSync(inputPath, outputPath);
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
|
-
|
|
19
|
-
await ThemeChecksumsUtils.createThemeChecksumsFiles(toTheme, checksums);
|
|
18
|
+
new ThemeChecksums(toTheme).updateAllChecksums();
|
|
20
19
|
}
|
|
21
20
|
async getChangesBetweenThemes(theme1, theme2) {
|
|
22
21
|
const theme1Tree = new FSTree({
|
|
@@ -25,32 +24,25 @@ export class ThemeMergeService {
|
|
|
25
24
|
const theme2Tree = new FSTree({
|
|
26
25
|
entries: walkSync.entries(theme2)
|
|
27
26
|
});
|
|
28
|
-
const theme1Checksums =
|
|
29
|
-
const theme2Checksums =
|
|
27
|
+
const theme1Checksums = new ThemeChecksums(theme1);
|
|
28
|
+
const theme2Checksums = new ThemeChecksums(theme2);
|
|
29
|
+
const userDirectories = await this._getUserRootDirectories(theme2);
|
|
30
30
|
return theme2Tree
|
|
31
31
|
.calculatePatch(theme1Tree, (entryA, entryB) => {
|
|
32
32
|
if (entryA.isDirectory() && entryB.isDirectory())
|
|
33
33
|
return true;
|
|
34
|
-
return theme1Checksums
|
|
34
|
+
return (theme1Checksums.getCurrentChecksumFromPathSync(entryA.relativePath) ===
|
|
35
|
+
theme2Checksums.getCurrentChecksumFromPathSync(entryB.relativePath));
|
|
35
36
|
})
|
|
36
|
-
.filter(([, name]) =>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const initialChecksums = await ThemeChecksumsUtils.getInitialChecksumsVerification(themeRootDir);
|
|
40
|
-
const currentChecksums = await ThemeChecksumsUtils.getThemeCurrentChecksumsVerification(themeRootDir);
|
|
41
|
-
return initialChecksums !== currentChecksums;
|
|
42
|
-
}
|
|
43
|
-
async hasFileBeenCreated(path, executionContext) {
|
|
44
|
-
const checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(executionContext.themeRootDir);
|
|
45
|
-
return checksums[path] === undefined && (await fileExists(join(executionContext.themeRootDir, path)));
|
|
46
|
-
}
|
|
47
|
-
async hasFileBeenRemoved(path, executionContext) {
|
|
48
|
-
const checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(executionContext.themeRootDir);
|
|
49
|
-
return !(await fileExists(join(executionContext.themeRootDir, path))) && !!checksums[path];
|
|
37
|
+
.filter(([_, name]) => {
|
|
38
|
+
return !name.startsWith(SHOPER_THEME_METADATA_DIR) && !userDirectories.some((userDir) => name.startsWith(userDir));
|
|
39
|
+
});
|
|
50
40
|
}
|
|
51
|
-
async
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
async _getUserRootDirectories(themeDir) {
|
|
42
|
+
const filesStructure = await ThemeFilesStructureUtils.getThemeRootDirectories(themeDir);
|
|
43
|
+
return (await getAllDirectoriesNamesInside(themeDir, {
|
|
44
|
+
recursive: false,
|
|
45
|
+
hidden: true
|
|
46
|
+
})).filter((directory) => !filesStructure.includes(join(directory, platformSeparator)));
|
|
55
47
|
}
|
|
56
48
|
}
|