solara 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/solara +18 -0
- data/solara/lib/.DS_Store +0 -0
- data/solara/lib/core/.DS_Store +0 -0
- data/solara/lib/core/aliases/alias_generator.rb +128 -0
- data/solara/lib/core/aliases/alias_generator_manager.rb +28 -0
- data/solara/lib/core/aliases/solara_terminal_setup.rb +103 -0
- data/solara/lib/core/brands/brand_onboarder.rb +46 -0
- data/solara/lib/core/brands/brand_switcher.rb +204 -0
- data/solara/lib/core/brands/brands_manager.rb +154 -0
- data/solara/lib/core/dashboard/.DS_Store +0 -0
- data/solara/lib/core/dashboard/brand/.DS_Store +0 -0
- data/solara/lib/core/dashboard/brand/BrandDetail.js +11 -0
- data/solara/lib/core/dashboard/brand/BrandDetailController.js +361 -0
- data/solara/lib/core/dashboard/brand/BrandDetailModel.js +155 -0
- data/solara/lib/core/dashboard/brand/BrandDetailView.js +245 -0
- data/solara/lib/core/dashboard/brand/brand.html +477 -0
- data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +123 -0
- data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +260 -0
- data/solara/lib/core/dashboard/brands/Brands.js +10 -0
- data/solara/lib/core/dashboard/brands/BrandsController.js +155 -0
- data/solara/lib/core/dashboard/brands/BrandsModel.js +136 -0
- data/solara/lib/core/dashboard/brands/BrandsView.js +136 -0
- data/solara/lib/core/dashboard/brands/brands.html +345 -0
- data/solara/lib/core/dashboard/component/AddFieldSheet.js +212 -0
- data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +128 -0
- data/solara/lib/core/dashboard/component/BrandOptionsBottomSheet.js +130 -0
- data/solara/lib/core/dashboard/component/ConfirmationDialog.js +103 -0
- data/solara/lib/core/dashboard/component/MessageBottomSheet.js +80 -0
- data/solara/lib/core/dashboard/component/OnboardBrandBottomSheet.js +214 -0
- data/solara/lib/core/dashboard/dashboard_manager.rb +19 -0
- data/solara/lib/core/dashboard/dashboard_server.rb +132 -0
- data/solara/lib/core/dashboard/handler/base_handler.rb +25 -0
- data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +33 -0
- data/solara/lib/core/dashboard/handler/brand_configurations_handler.rb +18 -0
- data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +73 -0
- data/solara/lib/core/dashboard/handler/brand_icon_handler.rb +20 -0
- data/solara/lib/core/dashboard/handler/brand_section_handler.rb +20 -0
- data/solara/lib/core/dashboard/handler/brands_handler.rb +14 -0
- data/solara/lib/core/dashboard/handler/current_brand_handler.rb +18 -0
- data/solara/lib/core/dashboard/handler/doctor_handler.rb +39 -0
- data/solara/lib/core/dashboard/handler/edit_section_handler.rb +55 -0
- data/solara/lib/core/dashboard/handler/offboard_brand_handler.rb +34 -0
- data/solara/lib/core/dashboard/handler/onboard_brand_handler.rb +53 -0
- data/solara/lib/core/dashboard/handler/redirect_handler.rb +12 -0
- data/solara/lib/core/dashboard/handler/switch_handler.rb +25 -0
- data/solara/lib/core/dashboard/index.html +36 -0
- data/solara/lib/core/dashboard/local.html +41 -0
- data/solara/lib/core/dashboard/res/favicon/android-chrome-192x192.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/android-chrome-512x512.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/apple-touch-icon.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon-16x16.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon-32x32.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon.ico +0 -0
- data/solara/lib/core/dashboard/res/favicon/site.webmanifest +1 -0
- data/solara/lib/core/dashboard/solara.png +0 -0
- data/solara/lib/core/doctor/brand_doctor.rb +94 -0
- data/solara/lib/core/doctor/doctor_manager.rb +35 -0
- data/solara/lib/core/doctor/project_doctor.rb +8 -0
- data/solara/lib/core/doctor/schema/brand_configurations.json +60 -0
- data/solara/lib/core/doctor/schema/platform/android/android_config.json +23 -0
- data/solara/lib/core/doctor/schema/platform/android/android_signing.json +23 -0
- data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +27 -0
- data/solara/lib/core/doctor/schema/platform/ios/ios_signing.json +27 -0
- data/solara/lib/core/doctor/schema/platform/shared/theme.json +48 -0
- data/solara/lib/core/doctor/validator/brand_settings_validator.rb +55 -0
- data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +82 -0
- data/solara/lib/core/doctor/validator/directory_structure_validator.rb +38 -0
- data/solara/lib/core/doctor/validator/file_structure_validator.rb +37 -0
- data/solara/lib/core/doctor/validator/json_file_validator.rb +21 -0
- data/solara/lib/core/doctor/validator/json_schema_validator.rb +32 -0
- data/solara/lib/core/doctor/validator/project_filesystem_validator.rb +70 -0
- data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +51 -0
- data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +53 -0
- data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +51 -0
- data/solara/lib/core/doctor/validator/template/template_validator.rb +108 -0
- data/solara/lib/core/doctor/validator/validation_strategy.rb +7 -0
- data/solara/lib/core/scripts/brand_config_generator.rb +245 -0
- data/solara/lib/core/scripts/brand_config_manager.rb +90 -0
- data/solara/lib/core/scripts/brand_exporter.rb +38 -0
- data/solara/lib/core/scripts/brand_importer.rb +84 -0
- data/solara/lib/core/scripts/brand_offboarder.rb +19 -0
- data/solara/lib/core/scripts/brand_resources_manager.rb +77 -0
- data/solara/lib/core/scripts/directory_creator.rb +22 -0
- data/solara/lib/core/scripts/file_manager.rb +90 -0
- data/solara/lib/core/scripts/file_path.rb +327 -0
- data/solara/lib/core/scripts/folder_copier.rb +41 -0
- data/solara/lib/core/scripts/gitignore_manager.rb +54 -0
- data/solara/lib/core/scripts/interactive_file_system_validator.rb +110 -0
- data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +24 -0
- data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +39 -0
- data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +233 -0
- data/solara/lib/core/scripts/platform/android/properties_generator.rb +31 -0
- data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +109 -0
- data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +42 -0
- data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +44 -0
- data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +56 -0
- data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +82 -0
- data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +130 -0
- data/solara/lib/core/scripts/project_settings_manager.rb +39 -0
- data/solara/lib/core/scripts/solara_logger.rb +103 -0
- data/solara/lib/core/scripts/solara_settings_manager.rb +73 -0
- data/solara/lib/core/scripts/solara_status_manager.rb +55 -0
- data/solara/lib/core/scripts/solara_version_manager.rb +42 -0
- data/solara/lib/core/scripts/strings_xml_manager.rb +22 -0
- data/solara/lib/core/scripts/terminal_input_manager.rb +22 -0
- data/solara/lib/core/scripts/theme_generator.rb +250 -0
- data/solara/lib/core/scripts/yaml_manager.rb +72 -0
- data/solara/lib/core/solara_configurator.rb +15 -0
- data/solara/lib/core/template/brands/android/android_config.json +8 -0
- data/solara/lib/core/template/brands/android/android_signing.json +6 -0
- data/solara/lib/core/template/brands/android/res/.DS_Store +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/brands.json +4 -0
- data/solara/lib/core/template/brands/ios/assets/.DS_Store +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/100.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/102.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/1024.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/114.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/120.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/128.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/144.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/152.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/16.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/167.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/172.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/180.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/196.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/20.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/216.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/256.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/29.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/32.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/40.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/48.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/50.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/512.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/55.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/57.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/58.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/60.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/64.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/66.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/72.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/76.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/80.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/87.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/88.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/92.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/Contents.json +1 -0
- data/solara/lib/core/template/brands/ios/ios_config.json +7 -0
- data/solara/lib/core/template/brands/ios/ios_signing.json +7 -0
- data/solara/lib/core/template/brands/shared/.DS_Store +0 -0
- data/solara/lib/core/template/brands/shared/brand_config.json +2 -0
- data/solara/lib/core/template/brands/shared/theme.json +46 -0
- data/solara/lib/core/template/config/android_template_config.json +57 -0
- data/solara/lib/core/template/config/flutter_template_config.json +62 -0
- data/solara/lib/core/template/config/ios_template_config.json +57 -0
- data/solara/lib/core/template/project_template_generator.rb +63 -0
- data/solara/lib/platform_detector.rb +84 -0
- data/solara/lib/solara/cli.rb +5 -0
- data/solara/lib/solara/version.rb +3 -0
- data/solara/lib/solara.rb +238 -0
- data/solara/lib/solara_initializer.rb +44 -0
- data/solara/lib/solara_manager.rb +73 -0
- metadata +346 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
class BaseHandler
|
2
|
+
def initialize(server, dashboard_server)
|
3
|
+
@server = server
|
4
|
+
@dashboard_server = dashboard_server
|
5
|
+
end
|
6
|
+
|
7
|
+
def mount
|
8
|
+
raise NotImplementedError, "Subclasses must implement the 'mount' method"
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def handle_error(res, error, message, status = 500)
|
14
|
+
Solara.logger.failure("#{message}: #{error.message}")
|
15
|
+
res.status = status
|
16
|
+
res.body = JSON.generate({ success: false, error: "#{message}: #{error.message}" })
|
17
|
+
res.content_type = 'application/json'
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_not_allowed(res)
|
21
|
+
res.status = 405
|
22
|
+
res.body = JSON.generate({ success: false, error: 'Method Not Allowed' })
|
23
|
+
res.content_type = 'application/json'
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class BrandAliasesHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/brand/aliases') do |req, res|
|
4
|
+
if req.request_method == 'GET'
|
5
|
+
begin
|
6
|
+
query = CGI.parse(req.query_string)
|
7
|
+
brand_key = query['brand_key']&.first
|
8
|
+
|
9
|
+
if brand_key
|
10
|
+
aliases = get_brand_aliases(brand_key)
|
11
|
+
res.status = 200
|
12
|
+
res.body = JSON.generate({ success: true, aliases: aliases })
|
13
|
+
else
|
14
|
+
res.status = 400
|
15
|
+
res.body = JSON.generate({ success: false, error: 'Missing brand_key parameter' })
|
16
|
+
end
|
17
|
+
rescue StandardError => e
|
18
|
+
handle_error(res, e, "Error fetching brand aliases")
|
19
|
+
end
|
20
|
+
else
|
21
|
+
method_not_allowed(res)
|
22
|
+
end
|
23
|
+
res.content_type = 'application/json'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_brand_aliases(brand_key)
|
28
|
+
AliasGeneratorManager.aliases_json
|
29
|
+
rescue StandardError => e
|
30
|
+
Solara.logger.failure("Error getting brand aliases: #{e.message}")
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class BrandConfigurationsHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/configurations') do |req, res|
|
4
|
+
begin
|
5
|
+
query = CGI.parse(req.query_string)
|
6
|
+
brand_key = query['brand_key']&.first
|
7
|
+
|
8
|
+
response_data = BrandsManager.instance.brand_with_configurations(brand_key)
|
9
|
+
res.body = JSON.generate({ success: true, message: "Configurations response", result: response_data })
|
10
|
+
res['Content-Type'] = 'application/json'
|
11
|
+
rescue StandardError => e
|
12
|
+
handle_error(res, e, "Error in brand configurations handler")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class BrandConfigurationsManager
|
2
|
+
|
3
|
+
def initialize(brand_key)
|
4
|
+
@brand_key = brand_key
|
5
|
+
end
|
6
|
+
|
7
|
+
def template_with_key(key)
|
8
|
+
templates.select { |section| section[:key] === key }.first
|
9
|
+
end
|
10
|
+
|
11
|
+
def templates
|
12
|
+
[
|
13
|
+
{
|
14
|
+
key: 'theme',
|
15
|
+
name: 'Theme Configuration',
|
16
|
+
input_type: 'color',
|
17
|
+
path: FilePath.brand_theme(@brand_key)
|
18
|
+
},
|
19
|
+
{
|
20
|
+
key: 'brand_config',
|
21
|
+
name: 'Brand Configuration',
|
22
|
+
input_type: 'text',
|
23
|
+
path: FilePath.brand_config(@brand_key)
|
24
|
+
},
|
25
|
+
{
|
26
|
+
key: 'android_config',
|
27
|
+
name: 'Android Platform Configuration',
|
28
|
+
input_type: 'text',
|
29
|
+
path: FilePath.android_brand_config(@brand_key)
|
30
|
+
},
|
31
|
+
{
|
32
|
+
key: 'android_signing',
|
33
|
+
name: 'Android Signing',
|
34
|
+
input_type: 'text',
|
35
|
+
path: FilePath.brand_signing(@brand_key, Platform::Android)
|
36
|
+
},
|
37
|
+
{
|
38
|
+
key: 'ios_config',
|
39
|
+
name: 'iOS Platform Configuration',
|
40
|
+
input_type: 'text',
|
41
|
+
path: FilePath.ios_config(@brand_key)
|
42
|
+
},
|
43
|
+
{
|
44
|
+
key: 'ios_signing',
|
45
|
+
name: 'iOS Signing',
|
46
|
+
input_type: 'text',
|
47
|
+
path: FilePath.brand_signing(@brand_key, Platform::IOS)
|
48
|
+
}
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
def create
|
53
|
+
config_templates = templates
|
54
|
+
|
55
|
+
config_templates.map do |template|
|
56
|
+
create_config_item(
|
57
|
+
template[:key],
|
58
|
+
template[:name],
|
59
|
+
template[:input_type],
|
60
|
+
template[:path].tap { |p| File.expand_path(p) }
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_config_item(key, name, input_type, path)
|
66
|
+
{
|
67
|
+
key: key,
|
68
|
+
name: name,
|
69
|
+
inputType: input_type,
|
70
|
+
content: JSON.parse(File.read(path)),
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class BrandIconHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc("/brand/icon") do |req, res|
|
4
|
+
begin
|
5
|
+
brand_key = req.query['brand_key']
|
6
|
+
filepath = FilePath.launcher_icon(brand_key)
|
7
|
+
if File.exist?(filepath)
|
8
|
+
res.body = File.read(filepath)
|
9
|
+
res['Content-Type'] = 'image/png' # Adjust as necessary
|
10
|
+
else
|
11
|
+
res.status = 404
|
12
|
+
res.body = JSON.generate({ error: "Icon not found for brand: #{brand_key}" })
|
13
|
+
res['Content-Type'] = 'application/json'
|
14
|
+
end
|
15
|
+
rescue StandardError => e
|
16
|
+
handle_error(res, e, "Error fetching brand icon")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class BrandSectionHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc("/section") do |req, res|
|
4
|
+
begin
|
5
|
+
query = CGI.parse(req.query_string)
|
6
|
+
path = query['path']&.first
|
7
|
+
if File.exist?(path)
|
8
|
+
res.body = File.read(path)
|
9
|
+
res['Content-Type'] = 'application/json'
|
10
|
+
else
|
11
|
+
res.status = 404
|
12
|
+
res.body = JSON.generate({ error: "Config file not found: #{path}" })
|
13
|
+
res['Content-Type'] = 'application/json'
|
14
|
+
end
|
15
|
+
rescue StandardError => e
|
16
|
+
handle_error(res, e, "Error in brand section handler")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class BrandsHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/brands.json') do |req, res|
|
4
|
+
begin
|
5
|
+
brands_list = BrandsManager.instance.brands_list
|
6
|
+
json = JSON.generate(brands_list)
|
7
|
+
res.body = json
|
8
|
+
res['Content-Type'] = 'application/json'
|
9
|
+
rescue StandardError => e
|
10
|
+
handle_error(res, e, "Error fetching brands list")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CurrentBrandHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/brand/current') do |req, res|
|
4
|
+
begin
|
5
|
+
current_brand = BrandsManager.instance.current_brand
|
6
|
+
if current_brand
|
7
|
+
res.status = 200
|
8
|
+
res.body = JSON.generate(current_brand)
|
9
|
+
else
|
10
|
+
res.status = 204 # No Content
|
11
|
+
end
|
12
|
+
res.content_type = 'application/json'
|
13
|
+
rescue StandardError => e
|
14
|
+
handle_error(res, e, "Error fetching current brand")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class DoctorHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/brand/doctor') do |req, res|
|
4
|
+
if req.request_method == 'GET'
|
5
|
+
begin
|
6
|
+
query = CGI.parse(req.query_string)
|
7
|
+
brand_key = query['brand_key']&.first
|
8
|
+
|
9
|
+
if brand_key
|
10
|
+
doctor_result = run_doctor(brand_key)
|
11
|
+
res.status = 200
|
12
|
+
res.body = JSON.generate({ success: true, result: doctor_result })
|
13
|
+
else
|
14
|
+
res.status = 400
|
15
|
+
res.body = JSON.generate({ success: false, error: 'Missing brand_key parameter' })
|
16
|
+
end
|
17
|
+
rescue StandardError => e
|
18
|
+
handle_error(res, e, "Error running doctor")
|
19
|
+
end
|
20
|
+
else
|
21
|
+
method_not_allowed(res)
|
22
|
+
end
|
23
|
+
res.content_type = 'application/json'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run_doctor(brand_key)
|
28
|
+
errors = SolaraManager.new.doctor(brand_key)
|
29
|
+
{
|
30
|
+
message: "Health check completed.",
|
31
|
+
brand_key: brand_key,
|
32
|
+
passed: errors.empty?,
|
33
|
+
errors: errors
|
34
|
+
}
|
35
|
+
rescue StandardError => e
|
36
|
+
Solara.logger.failure("Error running doctor: #{e.message}")
|
37
|
+
raise
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
Dir['*.rb'].each { |file| require_relative file }
|
2
|
+
|
3
|
+
class EditSectionHandler < BaseHandler
|
4
|
+
def mount
|
5
|
+
@server.mount_proc('/section/edit') do |req, res|
|
6
|
+
if req.request_method == 'POST'
|
7
|
+
begin
|
8
|
+
request_payload = JSON.parse(req.body)
|
9
|
+
brand_key = request_payload['brand_key']
|
10
|
+
key = request_payload['key']
|
11
|
+
data = request_payload['data']
|
12
|
+
|
13
|
+
update_section(key, data, brand_key)
|
14
|
+
set_current_brand_content_changed(brand_key, true)
|
15
|
+
|
16
|
+
res.status = 200
|
17
|
+
res.body = JSON.generate({ success: true, message: "Configuration for #{key} updated successfully" })
|
18
|
+
res.content_type = 'application/json'
|
19
|
+
rescue JSON::ParserError => e
|
20
|
+
handle_error(res, e, "Invalid JSON in request body", 400)
|
21
|
+
rescue StandardError => e
|
22
|
+
handle_error(res, e, "Error updating configuration")
|
23
|
+
end
|
24
|
+
else
|
25
|
+
method_not_allowed(res)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_section(key, data, brand_key)
|
31
|
+
template = BrandConfigurationsManager.new(brand_key).template_with_key(key)
|
32
|
+
|
33
|
+
path = template[:path]
|
34
|
+
if File.exist?(path)
|
35
|
+
File.write(path, JSON.pretty_generate(data))
|
36
|
+
Solara.logger.debug("Updated Config for #{path}: #{data}")
|
37
|
+
else
|
38
|
+
raise "Config file not found: #{path}"
|
39
|
+
end
|
40
|
+
rescue StandardError => e
|
41
|
+
Solara.logger.failure("Error updating section: #{e.message}")
|
42
|
+
raise
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_theme(path, data)
|
46
|
+
json = JSON.parse(File.read(path))
|
47
|
+
json['colors'] = data
|
48
|
+
File.write(path, JSON.pretty_generate(json))
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_current_brand_content_changed(brand_key, changed)
|
52
|
+
BrandsManager.instance.set_current_brand_content_changed(brand_key, changed)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class OffboardBrandHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/brand/offboard') do |req, res|
|
4
|
+
if req.request_method == 'GET'
|
5
|
+
begin
|
6
|
+
query = CGI.parse(req.query_string)
|
7
|
+
brand_key = query['brand_key']&.first
|
8
|
+
|
9
|
+
if brand_key
|
10
|
+
offboard(brand_key)
|
11
|
+
res.status = 200
|
12
|
+
res.body = JSON.generate({ success: true, message: "Deleted brand: #{brand_key}" })
|
13
|
+
else
|
14
|
+
res.status = 400
|
15
|
+
res.body = JSON.generate({ success: false, error: 'Missing brand_key parameter' })
|
16
|
+
end
|
17
|
+
rescue StandardError => e
|
18
|
+
handle_error(res, e, "Error deleting brand")
|
19
|
+
end
|
20
|
+
else
|
21
|
+
method_not_allowed(res)
|
22
|
+
end
|
23
|
+
res.content_type = 'application/json'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def offboard(brand_key)
|
28
|
+
SolaraManager.new.offboard(brand_key, confirm: false)
|
29
|
+
rescue StandardError => e
|
30
|
+
Solara.logger.failure("Error deleting brand: #{e.message}")
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class OnboardBrandHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/brand/onboard') do |req, res|
|
4
|
+
if req.request_method == 'POST'
|
5
|
+
begin
|
6
|
+
data = JSON.parse(req.body)
|
7
|
+
brand_name = data['brand_name']
|
8
|
+
brand_key = data['brand_key']
|
9
|
+
clone_brand_key = data['clone_brand_key']
|
10
|
+
|
11
|
+
if brand_key
|
12
|
+
result = onboard_brand(brand_name, brand_key, clone_brand_key)
|
13
|
+
res.status = result[:success] ? 200 : 409 # 409 Conflict for existing brand
|
14
|
+
res.body = JSON.generate(result)
|
15
|
+
else
|
16
|
+
res.status = 400
|
17
|
+
res.body = JSON.generate({ success: false, error: 'Missing brand_key parameter' })
|
18
|
+
end
|
19
|
+
rescue JSON::ParserError => e
|
20
|
+
handle_error(res, e, "Invalid JSON in request body", 400)
|
21
|
+
rescue StandardError => e
|
22
|
+
handle_error(res, e, "Error adding brand")
|
23
|
+
end
|
24
|
+
else
|
25
|
+
method_not_allowed(res)
|
26
|
+
end
|
27
|
+
res.content_type = 'application/json'
|
28
|
+
end
|
29
|
+
|
30
|
+
def onboard_brand(brand_name, brand_key, clone_brand_key = nil)
|
31
|
+
if BrandsManager.instance.exists(brand_key)
|
32
|
+
return { success: false, message: "Brand with key (#{brand_key}) already added!" }
|
33
|
+
end
|
34
|
+
SolaraManager.new.onboard(brand_key, brand_name, clone_brand_key: clone_brand_key, open_dashboard: false)
|
35
|
+
{ success: true, message: "Brand added successfully" }
|
36
|
+
rescue StandardError => e
|
37
|
+
Solara.logger.failure("Error adding brand: #{e.message}")
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def onboard_brand(brand_name, brand_key, clone_brand_key = nil)
|
44
|
+
if BrandsManager.instance.exists(brand_key)
|
45
|
+
return { success: false, message: "Brand with key (#{brand_key}) already added!" }
|
46
|
+
end
|
47
|
+
SolaraManager.new.onboard(brand_key, brand_name, clone_brand_key: clone_brand_key, open_dashboard: false)
|
48
|
+
{ success: true, message: "Brand added successfully" }
|
49
|
+
rescue StandardError => e
|
50
|
+
Solara.logger.failure("Error adding brand: #{e.message}")
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class RedirectHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/redirect') do |req, res|
|
4
|
+
begin
|
5
|
+
res.content_type = 'application/json'
|
6
|
+
res.body = JSON.generate({ redirect_url: @dashboard_server.home })
|
7
|
+
rescue StandardError => e
|
8
|
+
handle_error(res, e, "Error in redirect handler")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class SwitchToBrandHandler < BaseHandler
|
2
|
+
def mount
|
3
|
+
@server.mount_proc('/switch') do |req, res|
|
4
|
+
if req.request_method == 'POST'
|
5
|
+
begin
|
6
|
+
request_payload = JSON.parse(req.body)
|
7
|
+
brand_key = request_payload['brand_key']
|
8
|
+
|
9
|
+
result = SolaraManager.new.switch(brand_key)
|
10
|
+
Solara.logger.debug(result)
|
11
|
+
|
12
|
+
res.status = 200
|
13
|
+
res.body = JSON.generate({ success: true, message: "Switched to brand: #{brand_key}", result: result })
|
14
|
+
res.content_type = 'application/json'
|
15
|
+
rescue JSON::ParserError => e
|
16
|
+
handle_error(res, e, "Invalid JSON in request body", 400)
|
17
|
+
rescue StandardError => e
|
18
|
+
handle_error(res, e, "Error switching to brand")
|
19
|
+
end
|
20
|
+
else
|
21
|
+
method_not_allowed(res)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>Redirecting...</title>
|
7
|
+
<style>
|
8
|
+
body, html {
|
9
|
+
height: 100%;
|
10
|
+
margin: 0;
|
11
|
+
display: flex;
|
12
|
+
justify-content: center;
|
13
|
+
align-items: center;
|
14
|
+
background-color: #f0f0f0;
|
15
|
+
}
|
16
|
+
.container {
|
17
|
+
text-align: center;
|
18
|
+
}
|
19
|
+
img {
|
20
|
+
max-width: 50%;
|
21
|
+
max-height: 80vh;
|
22
|
+
object-fit: contain;
|
23
|
+
}
|
24
|
+
</style>
|
25
|
+
<script>
|
26
|
+
setTimeout(() => {
|
27
|
+
window.location.href = 'brand/brand.html?source=remote';
|
28
|
+
}, 500);
|
29
|
+
</script>
|
30
|
+
</head>
|
31
|
+
<body>
|
32
|
+
<div class="container">
|
33
|
+
<img src="solara.png" alt="Logo Image">
|
34
|
+
</div>
|
35
|
+
</body>
|
36
|
+
</html>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>Redirecting...</title>
|
7
|
+
<style>
|
8
|
+
body, html {
|
9
|
+
height: 100%;
|
10
|
+
margin: 0;
|
11
|
+
display: flex;
|
12
|
+
justify-content: center;
|
13
|
+
align-items: center;
|
14
|
+
background-color: #f0f0f0;
|
15
|
+
}
|
16
|
+
.container {
|
17
|
+
text-align: center;
|
18
|
+
}
|
19
|
+
img {
|
20
|
+
max-width: 50%;
|
21
|
+
max-height: 80vh;
|
22
|
+
object-fit: contain;
|
23
|
+
}
|
24
|
+
</style>
|
25
|
+
<script>
|
26
|
+
fetch('/redirect')
|
27
|
+
.then(response => response.json())
|
28
|
+
.then(data => {
|
29
|
+
setTimeout(() => {
|
30
|
+
window.location.href = data.redirect_url;
|
31
|
+
}, 500);
|
32
|
+
})
|
33
|
+
.catch(error => console.error('Error:', error));
|
34
|
+
</script>
|
35
|
+
</head>
|
36
|
+
<body>
|
37
|
+
<div class="container">
|
38
|
+
<img src="solara.png" alt="Logo Image">
|
39
|
+
</div>
|
40
|
+
</body>
|
41
|
+
</html>
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
Binary file
|
@@ -0,0 +1,94 @@
|
|
1
|
+
Dir.glob("#{__dir__}/*.rb").each { |file| require file }
|
2
|
+
Dir.glob("#{__dir__}/../../.solara/core/brands/*.rb").each { |file| require file }
|
3
|
+
Dir.glob("#{__dir__}/validator/template/*.rb").each { |file| require file }
|
4
|
+
|
5
|
+
class Issue < StandardError
|
6
|
+
ERROR = 'ERROR'
|
7
|
+
WARNING = 'WARNING'
|
8
|
+
|
9
|
+
attr_reader :type, :error
|
10
|
+
|
11
|
+
def initialize(type, error)
|
12
|
+
@type = type
|
13
|
+
@error = error
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"#{@type}: #{@error}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def <=>(other)
|
21
|
+
[type, error] <=> [other.type, other.error]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.error(error)
|
25
|
+
Issue.new(ERROR, error)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.warning(error)
|
29
|
+
Issue.new(WARNING, error)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class BrandDoctor
|
34
|
+
def initialize
|
35
|
+
end
|
36
|
+
|
37
|
+
def visit(brand_keys = [], print_logs: true)
|
38
|
+
keys = brand_keys.empty? ? BrandsManager.instance.brands_list.map { |brand| brand['key'] } : brand_keys
|
39
|
+
issues = []
|
40
|
+
|
41
|
+
keys.each do |brand_key|
|
42
|
+
validator = TemplateValidator.new(FilePath.brand(brand_key), FilePath.template_validation_config)
|
43
|
+
errors = validator.validate
|
44
|
+
|
45
|
+
errors.each { |error|
|
46
|
+
issues << Issue.error(error)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
# Validate settings only if all validations so far are passed to avoid files issues
|
51
|
+
if issues.select { |issue| issue.type == Issue::ERROR }.empty?
|
52
|
+
issues += BrandSettingsValidatorManager.new.validate
|
53
|
+
end
|
54
|
+
|
55
|
+
if print_logs && !issues.empty?
|
56
|
+
Solara.logger.title("Healt Check Result")
|
57
|
+
|
58
|
+
issues.sort!.each { |issue|
|
59
|
+
case issue.type
|
60
|
+
when Issue::ERROR
|
61
|
+
Solara.logger.failure(issue.to_s)
|
62
|
+
when Issue::WARNING
|
63
|
+
Solara.logger.warn(issue.to_s)
|
64
|
+
else
|
65
|
+
Solara.logger.failure(issue.to_s)
|
66
|
+
issues.sort!
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
issues.sort!
|
72
|
+
end
|
73
|
+
|
74
|
+
def validate_brand(brand_key, strategies = [])
|
75
|
+
Solara.logger.start_step("Brand Health Check: #{brand_key}")
|
76
|
+
|
77
|
+
project_path = FilePath.brand(brand_key)
|
78
|
+
issues = []
|
79
|
+
|
80
|
+
strategies.each do |strategy|
|
81
|
+
Solara.logger.debug("Running #{strategy.class.name}...")
|
82
|
+
begin
|
83
|
+
strategy.validate(project_path)
|
84
|
+
Solara.logger.debug("#{strategy.class.name} passed.")
|
85
|
+
rescue => e
|
86
|
+
issues << Issue.error("#{e.message} (#{strategy.class.name})")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Solara.logger.end_step("Brand Health Check #{brand_key}")
|
91
|
+
issues
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|