Skip to content

Commit 2174324

Browse files
authored
Merge pull request #898 from crazyserver/MOBILE-1985
MOBILE-1985 ws: Strip unicode chars when failing
2 parents b0a7329 + 7f26b57 commit 2174324

File tree

9 files changed

+122
-28
lines changed

9 files changed

+122
-28
lines changed

www/addons/messages/controllers/discussion.js

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -148,18 +148,14 @@ angular.module('mm.addons.messages')
148148

149149
notifyNewMessage();
150150
});
151-
}, function(error) {
151+
}).catch(function(error) {
152152
messagesBeingSent--;
153153

154154
// Only close the keyboard if an error happens, we want the user to be able to send multiple
155155
// messages without the keyboard being closed.
156156
$mmApp.closeKeyboard();
157157

158-
if (typeof error === 'string') {
159-
$mmUtil.showErrorModal(error);
160-
} else {
161-
$mmUtil.showErrorModal('mma.messages.messagenotsent', true);
162-
}
158+
$mmUtil.showErrorModalDefault(error, 'mma.messages.messagenotsent', true);
163159
$scope.messages.splice($scope.messages.indexOf(message), 1);
164160
});
165161
});
@@ -570,11 +566,7 @@ angular.module('mm.addons.messages')
570566
$scope.messages.splice(index, 1); // Remove message from the list without having to wait for re-fetch.
571567
fetchMessages(); // Re-fetch messages to update cached data.
572568
}).catch(function(error) {
573-
if (typeof error === 'string') {
574-
$mmUtil.showErrorModal(error);
575-
} else {
576-
$mmUtil.showErrorModal('mma.messages.errordeletemessage', true);
577-
}
569+
$mmUtil.showErrorModalDefault(error, 'mma.messages.errordeletemessage', true);
578570
}).finally(function() {
579571
modal.dismiss();
580572
});

www/addons/messages/services/messages.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ angular.module('mm.addons.messages')
2121
* @ngdoc service
2222
* @name $mmaMessages
2323
*/
24-
.factory('$mmaMessages', function($mmSite, $mmSitesManager, $log, $q, $mmUser, $mmaMessagesOffline, $mmApp,
24+
.factory('$mmaMessages', function($mmSite, $mmSitesManager, $log, $q, $mmUser, $mmaMessagesOffline, $mmApp, $mmUtil,
2525
mmaMessagesNewMessageEvent, mmaMessagesLimitMessages) {
2626
$log = $log.getInstance('$mmaMessages');
2727

@@ -1092,7 +1092,7 @@ angular.module('mm.addons.messages')
10921092
return self.sendMessagesOnline(messages, siteId).catch(function(error) {
10931093
return $q.reject({
10941094
error: error,
1095-
wserror: false
1095+
wserror: $mmUtil.isWebServiceError(error)
10961096
});
10971097
}).then(function(response) {
10981098
if (response && response[0] && response[0].msgid === -1) {
@@ -1122,8 +1122,6 @@ angular.module('mm.addons.messages')
11221122
* have been sent, the resolve param can contain errors for messages not sent.
11231123
*/
11241124
self.sendMessagesOnline = function(messages, siteId) {
1125-
siteId = siteId || $mmSite.getId();
1126-
11271125
return $mmSitesManager.getSite(siteId).then(function(site) {
11281126
var data = {
11291127
messages: messages

www/core/lang/en.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,15 @@
179179
"twoparagraphs": "{{p1}}<br><br>{{p2}}",
180180
"tryagain": "Try again",
181181
"uhoh": "Uh oh!",
182+
"unicodenotsupported" : "Unicode text like emojis are not supported on this site, text will be sent removing those characters.",
183+
"unicodenotsupportedcleanerror" : "Empty text was found when cleaning Unicode chars.",
184+
"unknown": "Unknown",
185+
"unlimited": "Unlimited",
186+
"unzipping": "Unzipping",
182187
"upgraderunning": "Site is being upgraded, please retry later.",
183188
"unexpectederror": "Unexepected error. Please close and reopen the application to try again",
184189
"userdeleted": "This user account has been deleted",
185190
"userdetails": "User details",
186-
"unknown": "Unknown",
187-
"unlimited": "Unlimited",
188-
"unzipping": "Unzipping",
189191
"usernotfullysetup": "User not fully set-up",
190192
"users": "Users",
191193
"view": "View",

www/core/lib/sitesfactory.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ angular.module('mm.core')
197197
mmCoreWSPrefix, mmCoreSessionExpired, $mmEvents, mmCoreEventSessionExpired, mmCoreUserDeleted, mmCoreEventUserDeleted,
198198
$mmText, $translate, mmCoreConfigConstants, mmCoreUserPasswordChangeForced, mmCoreEventPasswordChangeForced,
199199
mmCoreLoginTokenChangePassword, mmCoreSecondsMinute, mmCoreUserNotFullySetup, mmCoreEventUserNotFullySetup,
200-
mmCoreSitePolicyNotAgreed, mmCoreEventSitePolicyNotAgreed) {
200+
mmCoreSitePolicyNotAgreed, mmCoreEventSitePolicyNotAgreed, mmCoreUnicodeNotSupported) {
201201

202202
$log = $log.getInstance('$mmSite');
203203

@@ -258,6 +258,7 @@ angular.module('mm.core')
258258
this.privateToken = privateToken;
259259
this.config = config;
260260
this.loggedOut = !!loggedOut;
261+
this.cleanUnicode = false;
261262

262263
if (this.id) {
263264
this.db = $mmDB.getDB('Site-' + this.id, siteSchema, dboptions);
@@ -499,6 +500,9 @@ angular.module('mm.core')
499500
saveToCache: 0
500501
};
501502

503+
// Reset clean Unicode to check if it's supported again.
504+
site.cleanUnicode = false;
505+
502506
site.read('core_webservice_get_site_info', {}, preSets).then(deferred.resolve, function(error) {
503507
site.read('moodle_webservice_get_siteinfo', {}, preSets).then(deferred.resolve, function(error) {
504508
deferred.reject(error);
@@ -613,6 +617,16 @@ angular.module('mm.core')
613617
preSets = angular.copy(preSets) || {};
614618
preSets.wstoken = site.token;
615619
preSets.siteurl = site.siteurl;
620+
preSets.cleanUnicode = site.cleanUnicode;
621+
622+
if (preSets.cleanUnicode && $mmText.hasUnicodeData(data)) {
623+
// Data will be cleaned, notify the user.
624+
// @todo: Detect if the call is a syncing call and not notify.
625+
$mmUtil.showToast('mm.core.unicodenotsupported', true, 3000);
626+
} else {
627+
// No need to clean data in this call.
628+
preSets.cleanUnicode = false;
629+
}
616630

617631
// Enable text filtering by default.
618632
data.moodlewssettingfilter = preSets.filter === false ? false : true;
@@ -673,6 +687,14 @@ angular.module('mm.core')
673687
// Site policy not agreed, trigger event.
674688
$mmEvents.trigger(mmCoreEventSitePolicyNotAgreed, site.id);
675689
return $mmLang.translateAndReject('mm.login.sitepolicynotagreederror');
690+
} else if (error === mmCoreUnicodeNotSupported) {
691+
if (!site.cleanUnicode) {
692+
// Try again cleaning unicode.
693+
site.cleanUnicode = true;
694+
return site.request(method, data, preSets);
695+
}
696+
// This should not happen.
697+
return $mmLang.translateAndReject('mm.core.unicodenotsupported');
676698
} else if (typeof preSets.emergencyCache !== 'undefined' && !preSets.emergencyCache) {
677699
$log.debug('WS call ' + method + ' failed. Emergency cache is forbidden, rejecting.');
678700
return $q.reject(error);

www/core/lib/text.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,5 +579,66 @@ angular.module('mm.core')
579579
return /<[a-z][\s\S]*>/i.test(text);
580580
};
581581

582+
/**
583+
* Check if a text contains Unicode long chars.
584+
* Using as threshold Hex value D800
585+
*
586+
* @module mm.core
587+
* @ngdoc method
588+
* @name $mmText#hasUnicode
589+
* @param {String} text Text to check.
590+
* @return {Boolean} True if has Unicode chars, false otherwise.
591+
*/
592+
self.hasUnicode = function(text) {
593+
for (var x = 0; x < text.length; x++) {
594+
if (text.charCodeAt(x) > 55295) {
595+
return true;
596+
}
597+
}
598+
return false;
599+
};
600+
601+
/**
602+
* Check if an object has any long Unicode char.
603+
*
604+
* @module mm.core
605+
* @ngdoc method
606+
* @name $mmText#hasUnicodeData
607+
* @param {Mixed} data Object to be checked.
608+
* @return {Boolean} If the data has any long Unicode char on it.
609+
*/
610+
self.hasUnicodeData = function(data) {
611+
for (var el in data) {
612+
if (angular.isObject(data[el])) {
613+
if (self.hasUnicodeData(data[el])) {
614+
return true;
615+
}
616+
} else if (typeof data[el] == "string" && self.hasUnicode(data[el])) {
617+
return true;
618+
}
619+
}
620+
return false;
621+
}
622+
623+
/**
624+
* Strip Unicode long char of a given text.
625+
* Using as threshold Hex value D800
626+
*
627+
* @module mm.core
628+
* @ngdoc method
629+
* @name $mmText#stripUnicode
630+
* @param {String} text Text to check.
631+
* @return {String} Without the Unicode chars.
632+
*/
633+
self.stripUnicode = function(text) {
634+
var stripped = "";
635+
for (var x = 0; x < text.length; x++) {
636+
if (text.charCodeAt(x) <= 55295){
637+
stripped += text.charAt(x);
638+
}
639+
}
640+
return stripped;
641+
};
642+
582643
return self;
583644
});

www/core/lib/util.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1945,7 +1945,8 @@ angular.module('mm.core')
19451945
$translate.instant('mm.core.errorinvalidresponse'),
19461946
$translate.instant('mm.core.sitemaintenance'),
19471947
$translate.instant('mm.core.upgraderunning'),
1948-
$translate.instant('mm.core.nopasswordchangeforced')
1948+
$translate.instant('mm.core.nopasswordchangeforced'),
1949+
$translate.instant('mm.core.unicodenotsupported')
19491950
];
19501951
return error && localErrors.indexOf(error) == -1;
19511952
};

www/core/lib/ws.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ angular.module('mm.core')
2525
* @name $mmWS
2626
*/
2727
.factory('$mmWS', function($http, $q, $log, $mmLang, $cordovaFileTransfer, $mmApp, $mmFS, mmCoreSessionExpired, $translate, $window,
28-
mmCoreUserDeleted, md5, $timeout, mmWSTimeout, mmCoreUserPasswordChangeForced, mmCoreUserNotFullySetup,
29-
mmCoreSitePolicyNotAgreed) {
28+
mmCoreUserDeleted, md5, $timeout, mmWSTimeout, mmCoreUserPasswordChangeForced, mmCoreUserNotFullySetup, $mmText,
29+
mmCoreSitePolicyNotAgreed, mmCoreUnicodeNotSupported) {
3030

3131
$log = $log.getInstance('$mmWS');
3232

@@ -49,14 +49,13 @@ angular.module('mm.core')
4949
* - wstoken string The Webservice token.
5050
* - responseExpected boolean Defaults to true. Set to false when the expected response is null.
5151
* - typeExpected string Defaults to 'object'. Use it when you expect a type that's not an object|array.
52+
* - cleanUnicode boolean Defaults to false. Clean multibyte Unicode chars from data.
5253
* @return {Promise} Promise resolved with the response data in success and rejected with the error message if it fails.
5354
*/
5455
self.call = function(method, data, preSets) {
5556

5657
var siteurl;
5758

58-
data = convertValuesToString(data);
59-
6059
if (typeof preSets == 'undefined' || preSets === null ||
6160
typeof preSets.wstoken == 'undefined' || typeof preSets.siteurl == 'undefined') {
6261
return $mmLang.translateAndReject('mm.core.unexpectederror');
@@ -69,6 +68,13 @@ angular.module('mm.core')
6968
preSets.responseExpected = true;
7069
}
7170

71+
try {
72+
data = convertValuesToString(data, preSets.cleanUnicode);
73+
} catch (e) {
74+
// Empty cleaned text found.
75+
return $mmLang.translateAndReject('mm.core.unicodenotsupportedcleanerror');
76+
}
77+
7278
data.wsfunction = method;
7379
data.wstoken = preSets.wstoken;
7480
siteurl = preSets.siteurl + '/webservice/rest/server.php?moodlewsrestformat=json';
@@ -133,6 +139,8 @@ angular.module('mm.core')
133139
return $q.reject(mmCoreUserNotFullySetup);
134140
} else if (data.errorcode === 'sitepolicynotagreed') {
135141
return $q.reject(mmCoreSitePolicyNotAgreed);
142+
} else if (data.errorcode === 'dmlwriteexception' && $mmText.hasUnicodeData(ajaxData)) {
143+
return $q.reject(mmCoreUnicodeNotSupported);
136144
} else {
137145
return $q.reject(data.message);
138146
}
@@ -280,19 +288,27 @@ angular.module('mm.core')
280288
* Converts an objects values to strings where appropriate.
281289
* Arrays (associative or otherwise) will be maintained.
282290
*
283-
* @param {Object} data The data that needs all the non-object values set to strings.
291+
* @param {Object} data The data that needs all the non-object values set to strings.
292+
* @param {Boolean} stripUnicode If Unicode long chars need to be stripped.
284293
* @return {Object} The cleaned object, with multilevel array and objects preserved.
285294
*/
286-
function convertValuesToString(data) {
295+
function convertValuesToString(data, stripUnicode) {
287296
var result = [];
288297
if (!angular.isArray(data) && angular.isObject(data)) {
289298
result = {};
290299
}
291300
for (var el in data) {
292301
if (angular.isObject(data[el])) {
293-
result[el] = convertValuesToString(data[el]);
302+
result[el] = convertValuesToString(data[el], stripUnicode);
294303
} else {
295-
result[el] = data[el] + '';
304+
if (typeof data[el] == "string") {
305+
result[el] = stripUnicode ? $mmText.stripUnicode(data[el]) : data[el];
306+
if (stripUnicode && data[el] != result[el] && result[el].trim().length == 0) {
307+
throw new Exception();
308+
}
309+
} else {
310+
result[el] = data[el] + '';
311+
}
296312
}
297313
}
298314
return result;

www/core/main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ angular.module('mm.core', ['pascalprecht.translate'])
1919
.constant('mmCoreUserPasswordChangeForced', 'mmCoreUserPasswordChangeForced')
2020
.constant('mmCoreUserNotFullySetup', 'mmCoreUserNotFullySetup')
2121
.constant('mmCoreSitePolicyNotAgreed', 'mmCoreSitePolicyNotAgreed')
22+
.constant('mmCoreUnicodeNotSupported', 'mmCoreUnicodeNotSupported')
2223
.constant('mmCoreSecondsYear', 31536000)
2324
.constant('mmCoreSecondsDay', 86400)
2425
.constant('mmCoreSecondsHour', 3600)

www/core/scss/styles.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,7 @@ mm-timer {
10991099
.loading {
11001100
padding: 10px 20px;
11011101
border-radius: 25px;
1102+
margin: 0 10px;
11021103
}
11031104
}
11041105

0 commit comments

Comments
 (0)