ZReviewTender 1.2.8 → 1.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bcc9b0eab8e7b7c5aacfbc1add9a591e860222656d4097b3184011e41f8d93b
4
- data.tar.gz: cf092f42c2d81f62394713040fea08748810c283e4f0540f019b381042cf305b
3
+ metadata.gz: 42b1c7196a1088ba1af0ea680c1fe89b41daa91be09c137f3b9ab61d1b775501
4
+ data.tar.gz: d9d29e7dca76fde9d957cbc8360726baa925f25cf232e918b045d68c8d2206e1
5
5
  SHA512:
6
- metadata.gz: 7ddf0c24a5120da15392ca8c2b5053d39b6ae48853ed85e16fb8e445ca76ec3039ff2c97ee02e6015d20641ae697245de715951015397c44de4002d3456494f8
7
- data.tar.gz: 03afbee02b7543121a52a645258845780e0fbadf42b7b8ab65f8f9553317447500ee004df953c62735ba82cc584c0e1e3193a07b98f396913ce1217db40eb56b
6
+ metadata.gz: 4181c131a12529197907e3859577169e029dfafb52d49f3d2e91e1352a4a549b331a7a0c621bf9a9243af9c51922b704ef94dd5e3b9030f05753f1a30be1820a
7
+ data.tar.gz: 5a23d413b5e4ed62d302eeecbff51d90df24b254060aca00f5542ada623a4332d3771ca068971561c51ca390be32ea4325f8c2491ac989d2cea4e717683aae25
data/.version CHANGED
@@ -1 +1 @@
1
- 1.2.8
1
+ 1.3.2
@@ -1,6 +1,6 @@
1
1
  platform: 'android'
2
2
  packageName: '' # Android App Package Name
3
- keyFilePath: '' # Google Android Publisher API Credential .json File Path
3
+ keyFilePath: '' # Google Android Publisher API Service Account Credential .json File Path
4
4
  playConsoleDeveloperAccountID: '' # Google Console Developer Account ID
5
5
  playConsoleAppID: '' # Google Console App ID
6
6
  processors:
@@ -13,7 +13,7 @@ processors:
13
13
  - GoogleTranslateProcessor: # Google Translate Processor, will translate review text to your language, you can remove whole block if you don't needed it.
14
14
  class: "GoogleTranslateProcessor"
15
15
  enable: false # enable
16
- googleTranslateAPIKeyFilePath: '' # Google Translate API Credential .json File Path
16
+ googleTranslateAPIKeyFilePath: '' # Google Translate API Service Account Credential .json File Path
17
17
  googleTranslateTargetLang: 'zh-TW' # Translate to what Language
18
18
  googleTranslateTerritoriesExclude: ["zh-Hant","zh-Hans"] # Review origin Territory (language) that you don't want to translate. (language for android e.g. zh-Hant, en)
19
19
  - SlackProcessor: # Slack Processor, resend App Review to Slack.
@@ -24,3 +24,25 @@ processors:
24
24
  slackBotToken: "" # Slack Bot Token, send slack message throught Slack Bot.
25
25
  slackBotTargetChannel: "" # Slack Bot Token, send slack message throught Slack Bot. (recommended, first priority)
26
26
  slackInCommingWebHookURL: "" # Slack In-Comming WebHook URL, Send slack message throught In-Comming WebHook, not recommended, deprecated.
27
+ - GoogleSheetProcessor: # Google Sheet Processor, log review to google sheet
28
+ class: "GoogleSheetProcessor"
29
+ enable: false # enable
30
+ googleSheetAPIKeyFilePath: "" # Google Translate API Service Account Credential .json File Path
31
+ googleSheetTimeZoneOffset: "+08:00" # Review Created Date TimeZone
32
+ googleSheetID: "" # Google Sheet ID, you can get it on google sheet url: e.g. https://docs.google.com/spreadsheets/d/googleSheetID/
33
+ googleSheetName: "Sheet1" # Sheet Name
34
+ values: ["%RATING%","%TITLE%\n%BODY%","%APPVERSION%","%CREATEDDATE%"] # Columns Data, you can uses magic variable below to compose string.
35
+ # %TITLE% for review's title
36
+ # %BODY% for review's content
37
+ # %RATING% for review's rating 1~5
38
+ # %PLATFORM% for review's platform Apple or Android
39
+ # %ID% for review's ID
40
+ # %USERNAME% for review's reviewer username
41
+ # %URL% for link to review
42
+ # %TERRITORY% for review's territory (language for android e.g. zh-Hant, en)
43
+ # %APPVERSION% for review's reviewer app version
44
+ # %CREATEDDATE% for review's created date
45
+
46
+ keywordsInclude: [] # keywords you want to filter out
47
+ ratingsInclude: [] # ratings you want to filter out
48
+ territoriesInclude: [] # territories you want to filter out(language for android e.g. zh-Hant, en)
@@ -9,13 +9,13 @@ processors:
9
9
  enable: true # enable
10
10
  keywordsInclude: [] # keywords you want to filter out
11
11
  ratingsInclude: [] # ratings you want to filter out
12
- territoriesInclude: [] # territories you want to filter out
12
+ territoriesInclude: [] # territories you want to filter out (territory for Apple e.g. TWN)
13
13
  - GoogleTranslateProcessor: # Google Translate Processor, will translate review text to your language, you can remove whole block if you don't needed it.
14
14
  class: "GoogleTranslateProcessor"
15
15
  enable: false # enable
16
- googleTranslateAPIKeyFilePath: '' # Google Translate API Credential .json File Path
16
+ googleTranslateAPIKeyFilePath: '' # Google Translate API Service Account Credential .json File Path
17
17
  googleTranslateTargetLang: 'zh-TW' # Translate to what Language
18
- googleTranslateTerritoriesExclude: ["TWN","CHN"] # Review origin Territory that you don't want to translate.
18
+ googleTranslateTerritoriesExclude: ["TWN","CHN"] # Review origin Territory that you don't want to translate. (territory for Apple e.g. TWN)
19
19
  - SlackProcessor: # Slack Processor, resend App Review to Slack.
20
20
  class: "SlackProcessor"
21
21
  enable: true # enable
@@ -24,3 +24,25 @@ processors:
24
24
  slackBotToken: "" # Slack Bot Token, send slack message throught Slack Bot.
25
25
  slackBotTargetChannel: "" # Slack Bot Token, send slack message throught Slack Bot. (recommended, first priority)
26
26
  slackInCommingWebHookURL: "" # Slack In-Comming WebHook URL, Send slack message throught In-Comming WebHook, not recommended, deprecated.
27
+ - GoogleSheetProcessor: # Google Sheet Processor, log review to google sheet
28
+ class: "GoogleSheetProcessor"
29
+ enable: false # enable
30
+ googleSheetAPIKeyFilePath: "" # Google Translate API Service Account Credential .json File Path
31
+ googleSheetTimeZoneOffset: "+08:00" # Review Created Date TimeZone
32
+ googleSheetID: "" # Google Sheet ID, you can get it on google sheet url: e.g. https://docs.google.com/spreadsheets/d/googleSheetID/
33
+ googleSheetName: "Sheet1" # Sheet Name
34
+ values: ["%RATING%","%TITLE%\n%BODY%","%APPVERSION%","%CREATEDDATE%"] # Columns Data, you can uses magic variable below to compose string.
35
+ # %TITLE% for review's title
36
+ # %BODY% for review's content
37
+ # %RATING% for review's rating 1~5
38
+ # %PLATFORM% for review's platform Apple or Android
39
+ # %ID% for review's ID
40
+ # %USERNAME% for review's reviewer username
41
+ # %URL% for link to review
42
+ # %TERRITORY% for review's territory (territory for Apple e.g. TWN)
43
+ # %APPVERSION% for review's reviewer app version
44
+ # %CREATEDDATE% for review's created date
45
+
46
+ keywordsInclude: [] # keywords you want to filter out
47
+ ratingsInclude: [] # ratings you want to filter out
48
+ territoriesInclude: [] # territories you want to filter out (territory for Apple e.g. TWN)
@@ -1,21 +1,20 @@
1
1
  $lib = File.expand_path('../lib', File.dirname(__FILE__))
2
2
 
3
- require "Models/Review"
4
3
  require "Helper"
4
+ require "GoogleAPI"
5
+ require "Models/Review"
5
6
  require "Models/ReviewFetcher"
6
- require "jwt"
7
- require "time"
8
7
 
9
8
  class AndroidFetcher < ReviewFetcher
10
9
 
11
- attr_accessor :token
10
+ attr_accessor :token, :googleAPI
12
11
 
13
12
  def initialize(config)
14
13
  @processors = []
15
14
  @config = config
16
15
  @platform = 'Android'
17
16
  @logger = ZLogger.new(config.baseExecutePath)
18
- @token = generateJWT()
17
+ @googleAPI = GoogleAPI.new(config.keyFilePath, config.baseExecutePath, ["https://www.googleapis.com/auth/androidpublisher"])
19
18
 
20
19
  puts "[AndroidFetcher] Init Success."
21
20
  end
@@ -36,7 +35,7 @@ class AndroidFetcher < ReviewFetcher
36
35
  puts "[AndroidFetcher] Fetch reviews in #{config.packageName}"
37
36
 
38
37
  loop do
39
- reviewsInfo = request(reviewsInfoLink)
38
+ reviewsInfo = googleAPI.request(reviewsInfoLink)
40
39
  reviewsInfoLink = reviewsInfo&.dig("tokenPagination", "nextPageToken")
41
40
 
42
41
  customerReviews = reviewsInfo["reviews"]
@@ -96,7 +95,7 @@ class AndroidFetcher < ReviewFetcher
96
95
  end
97
96
 
98
97
  if deviceInfo.length > 0
99
- customerReviewTitle = "#{deviceInfo.join("/")}"
98
+ customerReviewReviewerNickname = "#{customerReviewReviewerNickname} - #{deviceInfo.join("/")}"
100
99
  end
101
100
  end
102
101
 
@@ -138,58 +137,4 @@ class AndroidFetcher < ReviewFetcher
138
137
  processReviews(reviews, platform)
139
138
  end
140
139
  end
141
-
142
- private
143
- def generateJWT()
144
- payload = {
145
- iss: config.clientEmail,
146
- sub: config.clientEmail,
147
- scope: "https://www.googleapis.com/auth/androidpublisher",
148
- aud: config.tokenURI,
149
- iat: Time.now.to_i,
150
- exp: Time.now.to_i + 60*20
151
- }
152
-
153
- rsa_private = OpenSSL::PKey::RSA.new(config.keyContent)
154
- token = JWT.encode payload, rsa_private, 'RS256', header_fields = {kid:config.keyID, typ:"JWT"}
155
-
156
- uri = URI(config.tokenURI)
157
- https = Net::HTTP.new(uri.host, uri.port)
158
- https.use_ssl = true
159
- request = Net::HTTP::Post.new(uri)
160
- request.body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=#{token}"
161
-
162
- response = https.request(request).read_body
163
- result = JSON.parse(response)
164
-
165
- return result["access_token"]
166
- end
167
-
168
- private
169
- def request(url, retryCount = 0)
170
- uri = URI(url)
171
- https = Net::HTTP.new(uri.host, uri.port)
172
- https.use_ssl = true
173
-
174
- request = Net::HTTP::Get.new(uri)
175
- request['Authorization'] = "Bearer #{token}";
176
-
177
- response = https.request(request).read_body
178
-
179
- result = JSON.parse(response)
180
- if result["reviews"].nil?
181
- if retryCount >= 10
182
- raise "Could not connect to androidpublisher.googleapis.com, error message: #{response}"
183
- else
184
- @token = generateJWT()
185
- message = "JWT Expired, refresh a new one. (#{retryCount + 1})"
186
- logger.logWarn(message)
187
- puts "[AndroidFetcher] #{message}"
188
- return request(url, retryCount + 1)
189
- end
190
- else
191
- return result
192
- end
193
-
194
- end
195
140
  end
data/lib/GoogleAPI.rb ADDED
@@ -0,0 +1,106 @@
1
+ $lib = File.expand_path('../lib', File.dirname(__FILE__))
2
+
3
+ require "jwt"
4
+ require "time"
5
+
6
+ class GoogleAPI < Processor
7
+
8
+ attr_accessor :keyContent, :keyID, :tokenURI, :clientEmail, :logger, :scopes, :token
9
+
10
+ def initialize(keyFilePath, baseExecutePath, scopes = [])
11
+
12
+ @logger = ZLogger.new(baseExecutePath)
13
+
14
+ keyFileContent = JSON.parse(File.read(keyFilePath))
15
+
16
+ @keyContent = Helper.unwrapRequiredParameter(keyFileContent,"private_key")
17
+ @keyID = Helper.unwrapRequiredParameter(keyFileContent,"private_key_id")
18
+ @clientEmail = Helper.unwrapRequiredParameter(keyFileContent,"client_email")
19
+ @tokenURI = Helper.unwrapRequiredParameter(keyFileContent,"token_uri")
20
+
21
+ @scopes = scopes
22
+
23
+ @token = generateJWT()
24
+
25
+ puts "[GoogleAPI] Init Success."
26
+ end
27
+
28
+ def request(url, method = "GET", data = nil, retryCount = 0)
29
+ uri = URI(url)
30
+ https = Net::HTTP.new(uri.host, uri.port)
31
+ https.use_ssl = true
32
+
33
+ request = Net::HTTP::Get.new(uri)
34
+ if method.upcase == "POST"
35
+ request = Net::HTTP::Post.new(uri)
36
+ if !data.nil?
37
+ request['Content-Type'] = 'application/json'
38
+ request.body = JSON.dump(data)
39
+ end
40
+ end
41
+
42
+ request['Authorization'] = "Bearer #{token}";
43
+
44
+ response = https.request(request).read_body
45
+ result = JSON.parse(response)
46
+
47
+ if !result["error"].nil?
48
+ # Quota exceeded for quota metric 'Write requests' and limit 'Write requests per minute per user
49
+ if result["error"]["code"] == 429
50
+ puts "[GoogleAPI] Reached Rate Limited, sleep 30 secs..."
51
+ sleep(30)
52
+ return request(url, method, data, 0)
53
+ else
54
+ if retryCount >= 10
55
+ raise "Could not connect to #{tokenURI}, key id: #{keyID}, error message: #{response}"
56
+ else
57
+ @token = generateJWT()
58
+ message = "JWT Invalid, retry. (#{retryCount + 1})"
59
+ logger.logWarn(message)
60
+ puts "[GoogleAPI] #{message}"
61
+ return request(url, method, data, retryCount + 1)
62
+ end
63
+ end
64
+ else
65
+ return result
66
+ end
67
+
68
+ end
69
+
70
+ private
71
+ def generateJWT(retryCount = 0)
72
+ payload = {
73
+ iss: clientEmail,
74
+ sub: clientEmail,
75
+ scope: scopes.join(' '),
76
+ aud: tokenURI,
77
+ iat: Time.now.to_i,
78
+ exp: Time.now.to_i + 60*20
79
+ }
80
+
81
+ rsa_private = OpenSSL::PKey::RSA.new(keyContent)
82
+ token = JWT.encode payload, rsa_private, 'RS256', header_fields = {kid:keyID, typ:"JWT"}
83
+
84
+ uri = URI(tokenURI)
85
+ https = Net::HTTP.new(uri.host, uri.port)
86
+ https.use_ssl = true
87
+ request = Net::HTTP::Post.new(uri)
88
+ request.body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=#{token}"
89
+
90
+ response = https.request(request).read_body
91
+ result = JSON.parse(response)
92
+
93
+ if result["access_token"].nil?
94
+ if retryCount >= 10
95
+ raise "Could not generate google api JWT, key id: #{keyID}, error message: #{response}"
96
+ else
97
+ message = "Could not generate google api JWT, retry. (#{retryCount + 1})"
98
+ logger.logWarn(message)
99
+ puts "[GoogleAPI] #{message}"
100
+ return generateJWT(retryCount + 1)
101
+ end
102
+ else
103
+ return result["access_token"]
104
+ end
105
+ end
106
+ end
@@ -5,23 +5,17 @@ require "Helper"
5
5
  require "time"
6
6
 
7
7
  class AndroidConfig
8
- attr_accessor :keyContent, :keyID, :tokenURI, :clientEmail, :packageName, :accountID, :appID, :baseExecutePath
8
+ attr_accessor :keyFilePath, :packageName, :accountID, :appID, :baseExecutePath
9
9
  def initialize(configYMLObj, configFilePath, baseExecutePath)
10
- keyFilePath = Helper.unwrapRequiredParameter(configYMLObj,"keyFilePath")
10
+ @keyFilePath = Helper.unwrapRequiredParameter(configYMLObj,"keyFilePath")
11
11
 
12
12
  if Pathname.new(keyFilePath).absolute?
13
13
  configDir = File.dirname(configFilePath)
14
- keyFilePath = "#{configDir}#{keyFilePath}"
14
+ @keyFilePath = "#{configDir}#{keyFilePath}"
15
15
  end
16
16
 
17
- keyFileContent = JSON.parse(File.read(keyFilePath))
18
-
19
17
  @accountID = configYMLObj["playConsoleDeveloperAccountID"]
20
18
  @appID = configYMLObj["playConsoleAppID"]
21
- @keyContent = Helper.unwrapRequiredParameter(keyFileContent,"private_key")
22
- @keyID = Helper.unwrapRequiredParameter(keyFileContent,"private_key_id")
23
- @clientEmail = Helper.unwrapRequiredParameter(keyFileContent,"client_email")
24
- @tokenURI = Helper.unwrapRequiredParameter(keyFileContent,"token_uri")
25
19
  @baseExecutePath = baseExecutePath
26
20
  @packageName = Helper.unwrapRequiredParameter(configYMLObj,"packageName")
27
21
  end
@@ -0,0 +1,106 @@
1
+ $lib = File.expand_path('../lib', File.dirname(__FILE__))
2
+
3
+ require "Models/Review"
4
+ require "Models/Processor"
5
+ require "Helper"
6
+ require "pathname"
7
+ require "GoogleAPI"
8
+
9
+ class GoogleSheetProcessor < Processor
10
+
11
+ attr_accessor :keywordsInclude, :ratingsInclude, :territoriesInclude, :logger, :googleAPI, :sheetID, :sheetName, :formatValues, :timeZoneOffset
12
+
13
+ def initialize(config, configFilePath, baseExecutePath)
14
+ @config = config
15
+ @configFilePath = configFilePath
16
+ @baseExecutePath = baseExecutePath
17
+ @logger = ZLogger.new(baseExecutePath)
18
+
19
+ keyFilePath = Helper.unwrapRequiredParameter(config, "googleSheetAPIKeyFilePath")
20
+
21
+ if Pathname.new(keyFilePath).absolute?
22
+ configDir = File.dirname(configFilePath)
23
+ keyFilePath = "#{configDir}#{keyFilePath}"
24
+ end
25
+
26
+ @googleAPI = GoogleAPI.new(keyFilePath, baseExecutePath, ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/spreadsheets"])
27
+
28
+ @keywordsInclude = []
29
+ if !config["keywordsInclude"].nil?
30
+ @keywordsInclude = config["keywordsInclude"]
31
+ end
32
+
33
+ @ratingsInclude = []
34
+ if !config["ratingsInclude"].nil?
35
+ @ratingsInclude = config["ratingsInclude"]
36
+ end
37
+
38
+ @territoriesInclude = []
39
+ if !config["territoriesInclude"].nil?
40
+ @territoriesInclude = config["territoriesInclude"]
41
+ end
42
+
43
+ @timeZoneOffset = Helper.unwrapRequiredParameter(config, "googleSheetTimeZoneOffset")
44
+ @sheetID = Helper.unwrapRequiredParameter(config, "googleSheetID")
45
+ @sheetName = Helper.unwrapRequiredParameter(config, "googleSheetName")
46
+ @formatValues = []
47
+ if !config["values"].nil?
48
+ @formatValues = config["values"]
49
+ end
50
+
51
+ puts "[GoogleSheetProcessor] Init Success."
52
+ end
53
+
54
+ def processReviews(reviews, platform)
55
+
56
+ if reviews.length < 1
57
+ return reviews
58
+ end
59
+
60
+ filterReviews = reviews
61
+
62
+ if ratingsInclude.length > 0
63
+ filterReviews = filterReviews.select{ |review| ratingsInclude.map{ |rating| rating.to_i }.include? review.rating }
64
+ end
65
+
66
+ if territoriesInclude.length > 0
67
+ filterReviews = filterReviews.select{ |review| territoriesInclude.map{ |territory| territory.upcase }.include? review.territory.upcase }
68
+ end
69
+
70
+ if keywordsInclude.length > 0
71
+ keywordsInclude.select{ |keywordsInclude| keywordsInclude != "" }.each do |keywordInclude|
72
+ filterReviews = filterReviews.select{ |review| review.body.include? keywordInclude }
73
+ end
74
+ end
75
+
76
+ values = []
77
+ filterReviews.each do |review|
78
+ cols = []
79
+ formatValues.each do |formatValue|
80
+ formatValue = formatValue.gsub("%TITLE%", review.title || "")
81
+ formatValue = formatValue.gsub("%BODY%", review.body || "")
82
+ formatValue = formatValue.gsub("%RATING%", review.rating.nil? ? "" :review.rating.to_s)
83
+ formatValue = formatValue.gsub("%PLATFORM%", review.platform || "")
84
+ formatValue = formatValue.gsub("%ID%", review.id || "")
85
+ formatValue = formatValue.gsub("%USERNAME%", review.userName || "")
86
+ formatValue = formatValue.gsub("%URL%", review.url || "")
87
+ formatValue = formatValue.gsub("%TERRITORY%", review.territory || "")
88
+ formatValue = formatValue.gsub("%APPVERSION%", review.appVersion || "")
89
+ formatValue = formatValue.gsub("%CREATEDDATE%", review.createdDateTimestamp.nil? ? "" : Time.at(review.createdDateTimestamp).getlocal(timeZoneOffset).to_s)
90
+
91
+ cols.append(formatValue)
92
+ end
93
+ values.append(cols)
94
+ end
95
+
96
+ page = 1
97
+ limit = 500
98
+ values.each_slice(limit) do |value|
99
+ puts "[GoogleSheetProcessor] Insert rows(#{page}/#{(values.length/limit).ceil + 1}) to #{sheetID}-#{sheetName}"
100
+ page += 1
101
+ googleAPI.request("https://sheets.googleapis.com/v4/spreadsheets/#{sheetID}/values/#{sheetName}!A1:append?valueInputOption=RAW", "POST", {:values => value})
102
+ end
103
+
104
+ return reviews
105
+ end
106
+ end
@@ -4,12 +4,11 @@ require "Models/Review"
4
4
  require "Models/Processor"
5
5
  require "Helper"
6
6
  require "pathname"
7
- require "jwt"
8
- require "time"
7
+ require "GoogleAPI"
9
8
 
10
9
  class GoogleTranslateProcessor < Processor
11
10
 
12
- attr_accessor :keyContent, :keyID, :tokenURI, :clientEmail, :targetLang, :territoriesExclude, :token, :logger
11
+ attr_accessor :targetLang, :territoriesExclude, :token, :logger, :googleAPI
13
12
 
14
13
  def initialize(config, configFilePath, baseExecutePath)
15
14
  @config = config
@@ -24,12 +23,7 @@ class GoogleTranslateProcessor < Processor
24
23
  keyFilePath = "#{configDir}#{keyFilePath}"
25
24
  end
26
25
 
27
- keyFileContent = JSON.parse(File.read(keyFilePath))
28
-
29
- @keyContent = Helper.unwrapRequiredParameter(keyFileContent,"private_key")
30
- @keyID = Helper.unwrapRequiredParameter(keyFileContent,"private_key_id")
31
- @clientEmail = Helper.unwrapRequiredParameter(keyFileContent,"client_email")
32
- @tokenURI = Helper.unwrapRequiredParameter(keyFileContent,"token_uri")
26
+ @googleAPI = GoogleAPI.new(keyFilePath, baseExecutePath, ["https://www.googleapis.com/auth/cloud-translation","https://www.googleapis.com/auth/cloud-platform"])
33
27
 
34
28
  @targetLang = Helper.unwrapRequiredParameter(config, "googleTranslateTargetLang")
35
29
  @territoriesExclude = []
@@ -37,8 +31,6 @@ class GoogleTranslateProcessor < Processor
37
31
  @territoriesExclude = config['googleTranslateTerritoriesExclude']
38
32
  end
39
33
 
40
- @token = generateJWT()
41
-
42
34
  puts "[GoogleTranslateProcessor] Init Success."
43
35
  end
44
36
 
@@ -49,20 +41,22 @@ class GoogleTranslateProcessor < Processor
49
41
 
50
42
  reviews.each_index do |index|
51
43
  if territoriesExclude.include? reviews[index].territory
52
- #next
44
+ next
53
45
  end
54
46
 
55
47
  puts "[GoogleTranslateProcessor] translate #{reviews[index].body} from #{reviews[index].territory} to #{targetLang}"
56
48
 
57
49
  if !reviews[index].title.nil?
58
- translateTitle = translate(reviews[index].title)
50
+ translateTitle = googleAPI.request("https://translation.googleapis.com/language/translate/v2", "POST", {:q => reviews[index].title, :target => targetLang})
51
+ translateTitle = translateTitle&.dig("data", "translations", 0, "translatedText")
59
52
  if !translateTitle.nil? && translateTitle != reviews[index].title
60
53
  reviews[index].title = "#{translateTitle} (#{reviews[index].title})"
61
54
  end
62
55
  end
63
56
 
64
57
  if !reviews[index].body.nil?
65
- translateBody = translate(reviews[index].body)
58
+ translateBody = googleAPI.request("https://translation.googleapis.com/language/translate/v2", "POST", {:q => reviews[index].body, :target => targetLang})
59
+ translateBody = translateBody&.dig("data", "translations", 0, "translatedText")
66
60
  if !translateBody.nil? && translateBody != reviews[index].body
67
61
  body = "#{translateBody}"
68
62
  body += "\r\n===== Translate by Google =====\r\n"
@@ -74,60 +68,4 @@ class GoogleTranslateProcessor < Processor
74
68
 
75
69
  return reviews
76
70
  end
77
-
78
- private
79
- def generateJWT()
80
- payload = {
81
- iss: clientEmail,
82
- sub: clientEmail,
83
- scope: ["https://www.googleapis.com/auth/cloud-translation","https://www.googleapis.com/auth/cloud-platform"].join(' '),
84
- aud: tokenURI,
85
- iat: Time.now.to_i,
86
- exp: Time.now.to_i + 60*20
87
- }
88
-
89
- rsa_private = OpenSSL::PKey::RSA.new(keyContent)
90
- token = JWT.encode payload, rsa_private, 'RS256', header_fields = {kid:keyID, typ:"JWT"}
91
-
92
- uri = URI(tokenURI)
93
- https = Net::HTTP.new(uri.host, uri.port)
94
- https.use_ssl = true
95
- request = Net::HTTP::Post.new(uri)
96
- request.body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=#{token}"
97
-
98
- response = https.request(request).read_body
99
- result = JSON.parse(response)
100
-
101
- return result["access_token"]
102
- end
103
-
104
- private
105
- def translate(text, retryCount = 0)
106
- uri = URI("https://translation.googleapis.com/language/translate/v2")
107
- https = Net::HTTP.new(uri.host, uri.port)
108
- https.use_ssl = true
109
-
110
- request = Net::HTTP::Post.new(uri)
111
- request.body = "q=#{text}&target=#{targetLang}"
112
- request['Authorization'] = "Bearer #{token}";
113
-
114
- response = https.request(request).read_body
115
-
116
- result = JSON.parse(response)
117
- translate = result&.dig("data", "translations", 0, "translatedText")
118
- if translate.nil?
119
- if retryCount >= 10
120
- raise "Could not connect to translation.googleapis.com, error message: #{response}"
121
- else
122
- @token = generateJWT()
123
- message = "JWT Expired, refresh a new one. (#{retryCount + 1})"
124
- logger.logWarn(message)
125
- puts "[GoogleTranslateProcessor] #{message}"
126
- return request(text, retryCount + 1)
127
- end
128
- else
129
- return translate
130
- end
131
-
132
- end
133
71
  end
@@ -82,6 +82,7 @@ class SlackProcessor < Processor
82
82
  logger.logError(payload)
83
83
  logger.logError(result)
84
84
  if result[:message] == "ratelimited"
85
+ puts "[SlackProcessor] Reached Rate Limited, sleep 1 sec..."
85
86
  sleep(1)
86
87
  pendingPayloads.insert(0, payload)
87
88
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ZReviewTender
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.8
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ZhgChgLi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-19 00:00:00.000000000 Z
11
+ date: 2022-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-http
@@ -79,6 +79,7 @@ files:
79
79
  - config/apple.example.yml
80
80
  - lib/AndroidFetcher.rb
81
81
  - lib/AppleFetcher.rb
82
+ - lib/GoogleAPI.rb
82
83
  - lib/Helper.rb
83
84
  - lib/Models/AndroidConfig.rb
84
85
  - lib/Models/AppleConfig.rb
@@ -87,6 +88,7 @@ files:
87
88
  - lib/Models/ReviewFetcher.rb
88
89
  - lib/Models/Version.rb
89
90
  - lib/Processors/FilterProcessor.rb
91
+ - lib/Processors/GoogleSheetProcessor.rb
90
92
  - lib/Processors/GoogleTranslateProcessor.rb
91
93
  - lib/Processors/ProcessorTemplate.rb
92
94
  - lib/Processors/SlackProcessor.rb