fci 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +21 -10
- data/bin/fci +21 -6
- data/fci.gemspec +1 -1
- data/fci.yml.example +18 -9
- data/lib/fci/commands/02_import.rb +118 -112
- data/lib/fci/commands/04_export.rb +132 -126
- data/lib/fci/export.rb +1 -1
- data/lib/fci/helpers.rb +18 -0
- data/lib/fci/init.rb +20 -11
- data/lib/fci/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f358abc6af346556ae042946ba6677a43c17323a
|
4
|
+
data.tar.gz: 43940e9e2707254c66745a8f8b06eeeb3156452a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34b6e4f68cec0550dd52c3204a3f8f01cc39ff00c066fb17cb43b1e840adcba5331b7eebbd59b582c545a2f04c9ba28d7d48191eccc16a467365922bd0554689
|
7
|
+
data.tar.gz: 5e7706624f504603c0178549177f73262a92ff8d62bc183514129d9ebb0cc0fc6bfd552bc6fe07e9954fa86493fb8c7913caef51532a17e718eb55147b50aff4
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -68,24 +68,34 @@ The scaffold project that was created in ./todo comes with a `fci.yml` shell.
|
|
68
68
|
|
69
69
|
```
|
70
70
|
---
|
71
|
+
# Crowdin API credentials
|
71
72
|
crowdin_project_id: '<%your-crowdin-project-id%>'
|
72
73
|
crowdin_api_key: '<%your-crowdin-api-key%>'
|
73
74
|
crowdin_base_url: 'https://api.crowdin.com'
|
74
75
|
|
76
|
+
# Freshdesk API credentials
|
75
77
|
freshdesk_base_url: 'https://<%subdomain%>.freshdesk.com'
|
76
78
|
freshdesk_username: '<%your-freshdek-username%>'
|
77
79
|
freshdesk_password: '<%your-freshdesk-password%>'
|
78
80
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
81
|
+
# Freshdesk catogories
|
82
|
+
categories:
|
83
|
+
- freshdesk_category: '<%freshdesk-category-id%>'
|
84
|
+
translations:
|
85
|
+
-
|
86
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
87
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
88
|
+
-
|
89
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
90
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
91
|
+
- freshdesk_category: '<%freshdesk-category-id%>'
|
92
|
+
translations:
|
93
|
+
-
|
94
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
95
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
96
|
+
-
|
97
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
98
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
89
99
|
```
|
90
100
|
|
91
101
|
## Supported Rubies
|
@@ -93,6 +103,7 @@ translations:
|
|
93
103
|
Tested with the following Ruby versions:
|
94
104
|
|
95
105
|
- MRI 2.2.0
|
106
|
+
- JRuby 9.0.0.0.pre2
|
96
107
|
|
97
108
|
## Contributing
|
98
109
|
|
data/bin/fci
CHANGED
@@ -9,6 +9,8 @@ rescue LoadError
|
|
9
9
|
exit 64
|
10
10
|
end
|
11
11
|
|
12
|
+
# GLI_DEBUG=true bundle exec bin/fci
|
13
|
+
|
12
14
|
include GLI::App
|
13
15
|
include FCI
|
14
16
|
|
@@ -47,20 +49,33 @@ pre do |global, command, options, args|
|
|
47
49
|
|
48
50
|
# load project-specific configuration
|
49
51
|
begin
|
50
|
-
@
|
52
|
+
@cli_config = YAML.load(File.read(global[:config])) || {}
|
51
53
|
rescue Psych::SyntaxError => err
|
52
54
|
exit_now! <<-EOS
|
53
55
|
Could not parse YAML: #{err.message}
|
54
56
|
EOS
|
55
57
|
end
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
if global[:verbose]
|
60
|
+
ENV['GLI_DEBUG'] = 'true'
|
61
|
+
end
|
62
|
+
|
63
|
+
@freshdesk = FreshdeskAPI::Client.new do |config|
|
64
|
+
config.base_url = @cli_config['freshdesk_base_url']
|
65
|
+
config.username = @cli_config['freshdesk_username']
|
66
|
+
config.password = @cli_config['freshdesk_password']
|
67
|
+
|
68
|
+
if global[:verbose]
|
69
|
+
require 'logger'
|
70
|
+
config.logger = Logger.new(STDOUT)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if global[:verbose]
|
75
|
+
Crowdin::API.log = Logger.new(STDOUT)
|
61
76
|
end
|
62
77
|
|
63
|
-
@crowdin = Crowdin::API.new(api_key: @
|
78
|
+
@crowdin = Crowdin::API.new(api_key: @cli_config['crowdin_api_key'], project_id: @cli_config['crowdin_project_id'], base_url: @cli_config['crowdin_base_url'])
|
64
79
|
|
65
80
|
true
|
66
81
|
end
|
data/fci.gemspec
CHANGED
@@ -18,7 +18,7 @@ spec = Gem::Specification.new do |s|
|
|
18
18
|
s.add_runtime_dependency('nokogiri')
|
19
19
|
s.add_runtime_dependency('rubyzip')
|
20
20
|
s.add_runtime_dependency('crowdin-api')
|
21
|
-
s.add_runtime_dependency('freshdesk_api')
|
21
|
+
s.add_runtime_dependency('freshdesk_api','>=0.1.1')
|
22
22
|
s.add_runtime_dependency('gli','2.13.0')
|
23
23
|
s.add_development_dependency('rake')
|
24
24
|
s.add_development_dependency('rdoc')
|
data/fci.yml.example
CHANGED
@@ -9,12 +9,21 @@ freshdesk_base_url: 'https://<%subdomain%>.freshdesk.com'
|
|
9
9
|
freshdesk_username: '<%your-freshdek-username%>'
|
10
10
|
freshdesk_password: '<%your-freshdesk-password%>'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
# Freshdesk catogories
|
13
|
+
categories:
|
14
|
+
- freshdesk_category: '<%freshdesk-category-id%>'
|
15
|
+
translations:
|
16
|
+
-
|
17
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
18
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
19
|
+
-
|
20
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
21
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
22
|
+
- freshdesk_category: '<%freshdesk-category-id%>'
|
23
|
+
translations:
|
24
|
+
-
|
25
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
26
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
27
|
+
-
|
28
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
29
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
@@ -33,139 +33,145 @@ command :'import:sources' do |c|
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# for store information about folders/articles ids
|
36
|
+
# for store information about categories/folders/articles ids
|
37
37
|
resources_config = YAML.load(File.open(resources_config_file))
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
@cli_config['categories'].each do |category|
|
40
|
+
# Source Category
|
41
|
+
source_category_id = category['freshdesk_category'].to_i
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
# Check if Category exists in Freshdesk
|
44
|
+
source_category = FreshdeskAPI::SolutionCategory.find!(@freshdesk, id: source_category_id)
|
45
|
+
raise('No such category') unless source_category.id == source_category_id
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
# Check if Category exists in resources config
|
48
|
+
unless resources_config[source_category_id]
|
49
|
+
category_config = resources_config.merge!(source_category_id => {})[source_category_id]
|
50
|
+
else
|
51
|
+
category_config = resources_config[source_category_id]
|
52
|
+
end
|
49
53
|
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
# Get category's folders in Freshdesk
|
55
|
+
puts "[Freshdesk] Get folders for Category with id #{source_category_id}"
|
56
|
+
folders = @freshdesk.solution_folders(category_id: source_category_id).all!
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
folders_builder = []
|
59
|
+
folders.each do |folder|
|
60
|
+
folder_xml = build_folder_xml(folder)
|
61
|
+
|
62
|
+
# write to resources config file
|
63
|
+
unless folder_xml.nil?
|
64
|
+
category_config[:folders] = [] unless category_config[:folders]
|
65
|
+
unless category_config[:folders].detect { |f| f[:id] == folder.id }
|
66
|
+
category_config[:folders] << { id: folder.id }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
unless folder_xml.nil?
|
71
|
+
folders_builder << build_folder_hash(folder).merge({ xml: folder_xml })
|
59
72
|
end
|
60
73
|
end
|
61
74
|
|
62
|
-
|
63
|
-
|
75
|
+
folders_config = resources_config[source_category_id][:folders]
|
76
|
+
# Get articles for each folder
|
77
|
+
articles_builder = []
|
78
|
+
folders.each do |folder|
|
79
|
+
puts "[Freshdesk] Get articles for Folder with id #{folder.id}"
|
80
|
+
articles = @freshdesk.solution_articles(category_id: source_category_id, folder_id: folder.id).all!
|
81
|
+
|
82
|
+
articles.each do |article|
|
83
|
+
article_xml = build_article_xml(article)
|
84
|
+
|
85
|
+
# write to resources config file
|
86
|
+
if folder_config = folders_config.detect { |f| f[:id] == folder.id }
|
87
|
+
folder_config[:articles] = [] unless folder_config[:articles]
|
88
|
+
unless folder_config[:articles].detect { |a| a[:id] == article.id }
|
89
|
+
folder_config[:articles] << { id: article.id }
|
90
|
+
end
|
91
|
+
else
|
92
|
+
abort 'No such folder!'
|
93
|
+
end
|
94
|
+
|
95
|
+
unless article_xml.nil?
|
96
|
+
articles_builder << build_article_hash(article).merge({ xml: article_xml })
|
97
|
+
end
|
98
|
+
end
|
64
99
|
end
|
65
|
-
end
|
66
100
|
|
67
|
-
|
68
|
-
|
69
|
-
folders.each do |folder|
|
70
|
-
puts "[Freshdesk] Get articles for Folder with id #{folder.id}"
|
71
|
-
articles = @freshdesk.solution_articles(category_id: source_category_id, folder_id: folder.id).all!
|
101
|
+
crowdin_project_info = @crowdin.project_info
|
102
|
+
remote_project_tree = get_remote_files_hierarchy(crowdin_project_info['files'])
|
72
103
|
|
73
|
-
|
74
|
-
|
104
|
+
resources_category_dir = File.join(resources_dir, source_category_id.to_s)
|
105
|
+
unless File.exists?(resources_category_dir)
|
106
|
+
FileUtils.mkdir(resources_category_dir)
|
107
|
+
end
|
75
108
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
109
|
+
# Create directory for Category on Crowdin if it does not exist yet
|
110
|
+
unless remote_project_tree[:dirs].include?("/#{source_category_id}")
|
111
|
+
puts "[Crowdin] Create directory `#{source_category_id}`"
|
112
|
+
@crowdin.add_directory(source_category_id.to_s)
|
113
|
+
@crowdin.change_directory(source_category_id.to_s, title: source_category.attributes[:name])
|
114
|
+
end
|
82
115
|
|
83
|
-
|
84
|
-
|
116
|
+
# Creates xml files for folders and upload to Crowdin
|
117
|
+
folders_builder.each do |folder|
|
118
|
+
file_name = "folder_#{folder[:id]}.xml"
|
119
|
+
|
120
|
+
o = File.new(File.join(resources_category_dir, file_name), 'w')
|
121
|
+
o.write folder[:xml].to_xml
|
122
|
+
o.close
|
123
|
+
|
124
|
+
files = [
|
125
|
+
{
|
126
|
+
source: File.join(resources_category_dir, file_name),
|
127
|
+
dest: File.join(source_category_id.to_s, file_name),
|
128
|
+
export_pattert: '/%two_letters_code%/%original_path%/%original_file_name%',
|
129
|
+
title: folder[:name]
|
130
|
+
}
|
131
|
+
]
|
132
|
+
|
133
|
+
if remote_project_tree[:files].include?("/#{source_category_id}/#{file_name}")
|
134
|
+
puts "[Crowdin] Update file `#{file_name}`"
|
135
|
+
@crowdin.update_file(files, type: 'webxml')
|
136
|
+
else
|
137
|
+
puts "[Crowdin] Add file `#{file_name}`"
|
138
|
+
@crowdin.add_file(files, type: 'webxml')
|
85
139
|
end
|
86
140
|
end
|
87
|
-
end
|
88
141
|
|
142
|
+
# Creates xml files for articles and upload to Crowdin
|
143
|
+
articles_builder.each do |article|
|
144
|
+
file_name = "article_#{article[:id]}.xml"
|
145
|
+
|
146
|
+
o = File.new(File.join(resources_category_dir, file_name), 'w')
|
147
|
+
o.write article[:xml].to_xml
|
148
|
+
o.close
|
149
|
+
|
150
|
+
files = [
|
151
|
+
{
|
152
|
+
source: File.join(resources_category_dir, file_name),
|
153
|
+
dest: File.join(source_category_id.to_s, file_name),
|
154
|
+
export_pattert: '/%two_letters_code%/%original_path%/%original_file_name%',
|
155
|
+
title: article[:title]
|
156
|
+
}
|
157
|
+
]
|
158
|
+
|
159
|
+
if remote_project_tree[:files].include?("/#{source_category_id}/#{file_name}")
|
160
|
+
puts "[Crowdin] Update file `#{file_name}`"
|
161
|
+
@crowdin.update_file(files, type: 'webxml')
|
162
|
+
else
|
163
|
+
puts "[Crowdin] Add file `#{file_name}`"
|
164
|
+
@crowdin.add_file(files, type: 'webxml')
|
89
165
|
|
90
|
-
|
91
|
-
|
92
|
-
# Creates xml files for folders and upload to Crowdin
|
93
|
-
folders_builder.each do |folder|
|
94
|
-
file_name = "folder_#{folder[:id]}.xml"
|
95
|
-
|
96
|
-
o = File.new(File.join(resources_dir, file_name), 'w')
|
97
|
-
o.write folder[:xml].to_xml
|
98
|
-
o.close
|
99
|
-
|
100
|
-
if crowdin_project_info['files'].detect { |file| file['name'] == file_name }
|
101
|
-
puts "[Crowdin] Update file `#{file_name}`"
|
102
|
-
@crowdin.update_file(
|
103
|
-
files = [
|
104
|
-
{
|
105
|
-
source: File.join(resources_dir, file_name),
|
106
|
-
dest: file_name,
|
107
|
-
export_pattert: '/%two_letters_code%/%original_file_name%',
|
108
|
-
title: folder[:name]
|
109
|
-
}
|
110
|
-
], type: 'webxml'
|
111
|
-
)
|
112
|
-
else
|
113
|
-
puts "[Crowdin] Add file `#{file_name}`"
|
114
|
-
@crowdin.add_file(
|
115
|
-
files = [
|
116
|
-
{
|
117
|
-
source: File.join(resources_dir, file_name),
|
118
|
-
dest: file_name,
|
119
|
-
export_pattert: '/%two_letters_code%/%original_file_name%',
|
120
|
-
title: folder[:name]
|
121
|
-
}
|
122
|
-
], type: 'webxml'
|
123
|
-
)
|
166
|
+
end
|
124
167
|
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# Creates xml files for articles and upload to Crowdin
|
128
|
-
articles_builder.each do |article|
|
129
|
-
file_name = "article_#{article[:id]}.xml"
|
130
|
-
|
131
|
-
o = File.new(File.join(resources_dir, file_name), 'w')
|
132
|
-
o.write article[:xml].to_xml
|
133
|
-
o.close
|
134
|
-
|
135
|
-
if crowdin_project_info['files'].detect { |file| file['name'] == file_name }
|
136
|
-
puts "[Crowdin] Update file `#{file_name}`"
|
137
|
-
@crowdin.update_file(
|
138
|
-
files = [
|
139
|
-
{
|
140
|
-
source: File.join(resources_dir, file_name),
|
141
|
-
dest: file_name,
|
142
|
-
export_pattert: '/%two_letters_code%/%original_file_name%',
|
143
|
-
title: article[:title]
|
144
|
-
}
|
145
|
-
], type: 'webxml'
|
146
|
-
)
|
147
|
-
else
|
148
|
-
puts "[Crowdin] Add file `#{file_name}`"
|
149
|
-
@crowdin.add_file(
|
150
|
-
files = [
|
151
|
-
{
|
152
|
-
source: File.join(resources_dir, file_name),
|
153
|
-
dest: file_name,
|
154
|
-
export_pattert: '/%two_letters_code%/%original_file_name%',
|
155
|
-
title: article[:title]
|
156
|
-
}
|
157
|
-
], type: 'webxml'
|
158
|
-
)
|
159
168
|
|
169
|
+
# Write resources config file
|
170
|
+
puts "Write config file for Category with id `#{source_category_id}`"
|
171
|
+
File.open(resources_config_file, 'w') do |f|
|
172
|
+
f.write resources_config.to_yaml
|
160
173
|
end
|
161
|
-
end
|
162
|
-
|
163
|
-
# Write resources config file
|
164
|
-
puts "Write config file"
|
165
|
-
File.open(resources_config_file, 'w') do |f|
|
166
|
-
f.write resources_config.to_yaml
|
167
|
-
end
|
168
174
|
|
175
|
+
end # @cli_config['categories'].each
|
169
176
|
end
|
170
177
|
end
|
171
|
-
|
@@ -22,67 +22,89 @@ command :'export:translations' do |c|
|
|
22
22
|
|
23
23
|
# for store information about folders/articles ids
|
24
24
|
unless File.exists?(resources_config_file)
|
25
|
-
raise "Error! Config file does not exist. First run `push` command"
|
25
|
+
raise "Error! Config file does not exist. First run `push` command."
|
26
26
|
end
|
27
27
|
|
28
28
|
resources_config = YAML.load(File.open(resources_config_file))
|
29
29
|
|
30
30
|
if !resources_config || resources_config.nil? || resources_config.empty?
|
31
|
-
raise "Error! Resources config empty. First run `push` command"
|
31
|
+
raise "Error! Resources config empty. First run `push` command."
|
32
32
|
end
|
33
33
|
|
34
|
-
@
|
35
|
-
|
36
|
-
|
34
|
+
@cli_config['categories'].each do |category|
|
35
|
+
category['translations'].each do |lang|
|
36
|
+
folder_xml_files = Dir["#{resources_dir}/#{lang['crowdin_language_code']}/#{category['freshdesk_category']}/folder_*.xml"]
|
37
|
+
article_xml_files = Dir["#{resources_dir}/#{lang['crowdin_language_code']}/#{category['freshdesk_category']}/article_*.xml"]
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
unless freshdesk_category = FreshdeskAPI::SolutionCategory.find(@freshdesk, id: lang['freshdesk_category_id'].to_i)
|
40
|
+
raise "Not such Category\##{lang['freshdesk_category_id']} for language `#{lang['crowdin_language_code']}` in Freshdesk. Please create new one and set `:freshdesk_category_id` in config file."
|
41
|
+
end
|
42
|
+
|
43
|
+
all_folders = []
|
44
|
+
all_articles = []
|
45
|
+
|
46
|
+
# Read folders from XML files
|
47
|
+
folder_xml_files.each do |file|
|
48
|
+
folder_xml_file = File.read(file)
|
41
49
|
|
42
|
-
|
43
|
-
all_articles = []
|
50
|
+
folder = parse_folder_xml(folder_xml_file)
|
44
51
|
|
45
|
-
|
46
|
-
|
47
|
-
# Load the xml file into a String
|
48
|
-
folder_xml_file = File.read(file)
|
52
|
+
all_folders << folder
|
53
|
+
end
|
49
54
|
|
50
|
-
|
55
|
+
# Read articles from XML filse
|
56
|
+
article_xml_files.each do |file|
|
57
|
+
article_xml_file = File.read(file)
|
51
58
|
|
52
|
-
|
53
|
-
end
|
59
|
+
article = parse_article_xml(article_xml_file)
|
54
60
|
|
55
|
-
|
56
|
-
|
57
|
-
article_xml_file = File.read(file)
|
61
|
+
all_articles << article
|
62
|
+
end
|
58
63
|
|
59
|
-
|
64
|
+
### Folders ###
|
65
|
+
#
|
66
|
+
all_folders.each do |folder|
|
67
|
+
category_config = resources_config[category['freshdesk_category'].to_i]
|
60
68
|
|
61
|
-
|
62
|
-
end
|
69
|
+
if folder_config = category_config[:folders].detect { |f| f[:id].to_s == folder[:id].to_s }
|
63
70
|
|
64
|
-
|
65
|
-
#
|
66
|
-
all_folders.each do |folder|
|
67
|
-
if config_folder = resources_config[:folders].detect { |f| f[:id].to_s == folder[:id].to_s }
|
71
|
+
folder_config[:translations] = [] unless folder_config[:translations]
|
68
72
|
|
69
|
-
|
73
|
+
# if Folder translation ID exists in config
|
74
|
+
if folder_translation = folder_config[:translations].detect { |tr| tr[:lang] == lang['crowdin_language_code'] }
|
75
|
+
# Get folder from Freshdesk and update it
|
76
|
+
freshdesk_folder = FreshdeskAPI::SolutionFolder.find(
|
77
|
+
@freshdesk,
|
78
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
79
|
+
id: folder_translation[:id]
|
80
|
+
)
|
70
81
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
82
|
+
# Remove Folder translation from config it it not found in Freshdesk
|
83
|
+
if freshdesk_folder.nil?
|
84
|
+
puts "Remove undefined Folder from config."
|
85
|
+
folder_config[:translations].delete_if { |tr| tr[:lang] == lang['crowdin_language_code'] }
|
86
|
+
|
87
|
+
puts "[Freshdesk] Create new Folder."
|
88
|
+
freshdesk_folder = FreshdeskAPI::SolutionFolder.create!(
|
89
|
+
@freshdesk,
|
90
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
91
|
+
name: folder[:name],
|
92
|
+
description: folder[:description],
|
93
|
+
visibility: 1
|
94
|
+
)
|
79
95
|
|
80
|
-
|
81
|
-
|
82
|
-
puts "Remove undefined Folder from config"
|
83
|
-
config_folder[:translations].delete_if { |tr| tr[:lang] == lang['crowdin_language_code'] }
|
96
|
+
folder_config[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_folder.id }
|
97
|
+
end
|
84
98
|
|
85
|
-
|
99
|
+
if freshdesk_folder.attributes[:name] != folder[:name] || freshdesk_folder.attributes[:description] != folder[:description]
|
100
|
+
puts "[Freshdesk] Update existing Folder."
|
101
|
+
freshdesk_folder.update!(name: folder[:name], description: folder[:description])
|
102
|
+
else
|
103
|
+
puts "[Freshdesk] Nothing to update. An existing Folder still the same."
|
104
|
+
end
|
105
|
+
else
|
106
|
+
# create new folder in Freshdesk and save id to config file
|
107
|
+
puts "[Freshdesk] Create new Folder."
|
86
108
|
freshdesk_folder = FreshdeskAPI::SolutionFolder.create!(
|
87
109
|
@freshdesk,
|
88
110
|
category_id: lang['freshdesk_category_id'].to_i,
|
@@ -91,116 +113,100 @@ command :'export:translations' do |c|
|
|
91
113
|
visibility: 1
|
92
114
|
)
|
93
115
|
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
if freshdesk_folder.attributes[:name] != folder[:name] || freshdesk_folder.attributes[:description] != folder[:description]
|
99
|
-
puts "[Freshdesk] Update existing Folder"
|
100
|
-
freshdesk_folder.update!(name: folder[:name], description: folder[:description])
|
101
|
-
else
|
102
|
-
puts "[Freshdesk] Nothing to update. An existing Folder still the same."
|
116
|
+
folder_config[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_folder.id }
|
103
117
|
end
|
104
|
-
|
105
118
|
else
|
106
|
-
|
107
|
-
puts "[Freshdesk] Create new Folder"
|
108
|
-
freshdesk_folder = FreshdeskAPI::SolutionFolder.create!(
|
109
|
-
@freshdesk,
|
110
|
-
category_id: lang['freshdesk_category_id'].to_i,
|
111
|
-
name: folder[:name],
|
112
|
-
description: folder[:description],
|
113
|
-
visibility: 1
|
114
|
-
)
|
115
|
-
|
116
|
-
config_folder[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_folder.id }
|
119
|
+
abort "No such folder!"
|
117
120
|
end
|
118
|
-
|
119
|
-
|
121
|
+
end # all_folders.each
|
122
|
+
|
123
|
+
puts "Write info about Folders localization for Category `#{freshdesk_category.id}` to config."
|
124
|
+
File.open(resources_config_file, 'w') do |f|
|
125
|
+
f.write resources_config.to_yaml
|
120
126
|
end
|
121
|
-
end # all_folders
|
122
|
-
|
123
|
-
### Articles ###
|
124
|
-
#
|
125
|
-
all_articles.each do |article|
|
126
|
-
if config_folder = resources_config[:folders].detect { |f| f[:id].to_s == article[:folder_id].to_s }
|
127
|
-
unless folder_translation = config_folder[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
128
|
-
abort "No `#{lang['crowdin_language_code']}` translations for folder"
|
129
|
-
end
|
130
127
|
|
131
|
-
|
132
|
-
|
128
|
+
### Articles ###
|
129
|
+
#
|
130
|
+
all_articles.each do |article|
|
131
|
+
category_config = resources_config[category['freshdesk_category'].to_i]
|
132
|
+
if folder_config = category_config[:folders].detect { |f| f[:id].to_s == article[:folder_id].to_s }
|
133
|
+
unless folder_translation = folder_config[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
134
|
+
abort "No `#{lang['crowdin_language_code']}` translations for folder."
|
135
|
+
end
|
133
136
|
|
134
|
-
|
135
|
-
|
136
|
-
freshdesk_article = FreshdeskAPI::SolutionArticle.find(
|
137
|
-
@freshdesk,
|
138
|
-
category_id: lang['freshdesk_category_id'].to_i,
|
139
|
-
folder_id: folder_translation[:id],
|
140
|
-
id: article_translation[:id]
|
141
|
-
)
|
137
|
+
if article_config = folder_config[:articles].detect { |f| f[:id].to_s == article[:id].to_s }
|
138
|
+
article_config[:translations] = [] unless article_config[:translations]
|
142
139
|
|
143
|
-
#
|
144
|
-
if
|
145
|
-
|
146
|
-
|
140
|
+
# if Article translation ID exists in config - update article on Freshdesk
|
141
|
+
if article_translation = article_config[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
142
|
+
freshdesk_article = FreshdeskAPI::SolutionArticle.find(
|
143
|
+
@freshdesk,
|
144
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
145
|
+
folder_id: folder_translation[:id],
|
146
|
+
id: article_translation[:id]
|
147
|
+
)
|
147
148
|
|
148
|
-
|
149
|
-
freshdesk_article
|
149
|
+
# Remove Article translation from config if it not found in Freshdesk
|
150
|
+
if freshdesk_article.nil?
|
151
|
+
puts "Remove undefined Article from config."
|
152
|
+
article_config[:translations].delete_if { |tr| tr[:lang] == lang['crowdin_language_code'] }
|
153
|
+
|
154
|
+
puts "[Freshdesk] Create new Article."
|
155
|
+
freshdesk_article = FreshdeskAPI::SolutionArticle.create!(
|
150
156
|
@freshdesk,
|
151
157
|
category_id: lang['freshdesk_category_id'].to_i,
|
152
158
|
folder_id: folder_translation[:id],
|
153
159
|
title: article[:title],
|
154
160
|
description: article[:description]
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
161
|
+
)
|
162
|
+
article_config[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_article.id }
|
163
|
+
next
|
164
|
+
end
|
159
165
|
|
160
|
-
|
161
|
-
|
166
|
+
if freshdesk_article.attributes[:title] != article[:title] || freshdesk_article.attributes[:description] != article[:description]
|
167
|
+
puts "[Freshdesk] Update existing Article."
|
162
168
|
|
163
|
-
|
169
|
+
freshdesk_article.update!(
|
170
|
+
title: article[:title],
|
171
|
+
description: article[:description]
|
172
|
+
)
|
173
|
+
else
|
174
|
+
puts "[Freshdesk] Nothing to update. An existing Article still the same."
|
175
|
+
end
|
176
|
+
|
177
|
+
else
|
178
|
+
# creates new article on Freshdesk and save ID to config file
|
179
|
+
if folder_translation = folder_config[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
180
|
+
# do nothing for now
|
181
|
+
else
|
182
|
+
abort "No translation for this folder."
|
183
|
+
end
|
184
|
+
|
185
|
+
puts "[Freshdesk] Create new Article."
|
186
|
+
freshdesk_article = FreshdeskAPI::SolutionArticle.create!(
|
187
|
+
@freshdesk,
|
188
|
+
category_id: lang['freshdesk_category_id'].to_i,
|
189
|
+
folder_id: folder_translation[:id],
|
164
190
|
title: article[:title],
|
165
191
|
description: article[:description]
|
166
192
|
)
|
167
|
-
|
168
|
-
puts "[Freshdesk] Nothing to update. An existing Article still the same."
|
193
|
+
article_config[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_article.id }
|
169
194
|
end
|
170
|
-
|
171
195
|
else
|
172
|
-
|
173
|
-
if folder_translation = config_folder[:translations].detect { |t| t[:lang] == lang['crowdin_language_code'] }
|
174
|
-
# do nothing for now
|
175
|
-
else
|
176
|
-
abort "No translation for this folder"
|
177
|
-
end
|
178
|
-
|
179
|
-
puts "[Freshdesk] Create new Article"
|
180
|
-
freshdesk_article = FreshdeskAPI::SolutionArticle.create!(
|
181
|
-
@freshdesk,
|
182
|
-
category_id: lang['freshdesk_category_id'].to_i,
|
183
|
-
folder_id: folder_translation[:id],
|
184
|
-
title: article[:title],
|
185
|
-
description: article[:description]
|
186
|
-
)
|
187
|
-
config_article[:translations] << { lang: lang['crowdin_language_code'], id: freshdesk_article.id }
|
196
|
+
abort "No such article!"
|
188
197
|
end
|
189
198
|
else
|
190
|
-
abort "No such
|
199
|
+
abort "No such folder!"
|
191
200
|
end
|
192
|
-
|
193
|
-
abort "No such folder!"
|
194
|
-
end
|
195
|
-
end # all_articles
|
201
|
+
end # all_articles.each
|
196
202
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
203
|
+
puts "Write info about Articles localization for Category `#{freshdesk_category.id}` to config."
|
204
|
+
File.open(resources_config_file, 'w') do |f|
|
205
|
+
f.write resources_config.to_yaml
|
206
|
+
end
|
201
207
|
|
202
|
-
|
208
|
+
end # category['translations'].each
|
209
|
+
end # @cli_config['categories'].each
|
203
210
|
|
204
211
|
end
|
205
212
|
end
|
206
|
-
|
data/lib/fci/export.rb
CHANGED
data/lib/fci/helpers.rb
CHANGED
@@ -4,3 +4,21 @@ class String
|
|
4
4
|
gsub(/^[ \t]{#{indent}}/, '')
|
5
5
|
end
|
6
6
|
end
|
7
|
+
|
8
|
+
# Return +hierarchy+ of directories and files in Crowdin project
|
9
|
+
#
|
10
|
+
# +files+ - basically, it's project files details from API method `project_info`
|
11
|
+
#
|
12
|
+
def get_remote_files_hierarchy(files, root = '/', hierarchy = { dirs: [], files: [] })
|
13
|
+
files.each do |node|
|
14
|
+
case node['node_type']
|
15
|
+
when 'directory'
|
16
|
+
hierarchy[:dirs] << "#{root}#{node['name']}"
|
17
|
+
get_remote_files_hierarchy(node['files'], root + node['name'] + '/', hierarchy)
|
18
|
+
when 'file'
|
19
|
+
hierarchy[:files] << "#{root}#{node['name']}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
return hierarchy
|
24
|
+
end
|
data/lib/fci/init.rb
CHANGED
@@ -31,19 +31,28 @@ module FCI
|
|
31
31
|
|
32
32
|
def mk_config(root_dir, project_name)
|
33
33
|
config = <<-EOS.strip_heredoc
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
---
|
35
|
+
# Crowdin API credentials
|
36
|
+
crowdin_project_id: '<%your-crowdin-project-id%>'
|
37
|
+
crowdin_api_key: '<%your-crowdin-api-key%>'
|
38
|
+
crowdin_base_url: 'https://api.crowdin.com'
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
freshdesk_category: '<%freshdesk-category-id%>'
|
40
|
+
# Freshdesk API credentials
|
41
|
+
freshdesk_base_url: 'https://<%subdomain%>.freshdesk.com'
|
42
|
+
freshdesk_username: '<%your-freshdesk-username%>'
|
43
|
+
freshdesk_password: '<%your-freshdesk-password%>'
|
46
44
|
|
45
|
+
# Freshdesk catogories
|
46
|
+
categories:
|
47
|
+
- freshdesk_category: '<%freshdesk-category-id%>'
|
48
|
+
translations:
|
49
|
+
-
|
50
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
51
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
52
|
+
-
|
53
|
+
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
54
|
+
freshdesk_category_id: '<%freshdesk-category-id%>'
|
55
|
+
- freshdesk_category: '<%freshdesk-category-id%>'
|
47
56
|
translations:
|
48
57
|
-
|
49
58
|
crowdin_language_code: '<%crowdin-two-letters-code%>'
|
data/lib/fci/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Maminov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.1.1
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.1.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: gli
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -189,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
189
|
version: '0'
|
190
190
|
requirements: []
|
191
191
|
rubyforge_project:
|
192
|
-
rubygems_version: 2.4.
|
192
|
+
rubygems_version: 2.4.7
|
193
193
|
signing_key:
|
194
194
|
specification_version: 4
|
195
195
|
summary: Freshdesk and Crowdin integration Command Line Interface (CLI)
|