Merge pull request #2791 from NoelDeMartin/MOBILE-3674
MOBILE-3674: Make url comparison case insensitive
This commit is contained in:
		
						commit
						a1a7866021
					
				| @ -22,6 +22,7 @@ import { Network, Platform, NgZone } from '@singletons'; | |||||||
| 
 | 
 | ||||||
| import { mockSingleton, renderComponent } from '@/testing/utils'; | import { mockSingleton, renderComponent } from '@/testing/utils'; | ||||||
| import { CoreNavigator, CoreNavigatorService } from '@services/navigator'; | import { CoreNavigator, CoreNavigatorService } from '@services/navigator'; | ||||||
|  | import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins'; | ||||||
| 
 | 
 | ||||||
| describe('AppComponent', () => { | describe('AppComponent', () => { | ||||||
| 
 | 
 | ||||||
| @ -33,6 +34,7 @@ describe('AppComponent', () => { | |||||||
|         mockSingleton(Network, { onChange: () => new Observable() }); |         mockSingleton(Network, { onChange: () => new Observable() }); | ||||||
|         mockSingleton(Platform, { ready: () => Promise.resolve(), resume: new Subject<void>() }); |         mockSingleton(Platform, { ready: () => Promise.resolve(), resume: new Subject<void>() }); | ||||||
|         mockSingleton(NgZone, { run: jest.fn() }); |         mockSingleton(NgZone, { run: jest.fn() }); | ||||||
|  |         mockSingleton(CoreSitePlugins, { hasSitePluginsLoaded: false }); | ||||||
| 
 | 
 | ||||||
|         navigator = mockSingleton(CoreNavigator, ['navigate']); |         navigator = mockSingleton(CoreNavigator, ['navigate']); | ||||||
|         langProvider = mockSingleton(CoreLang, ['clearCustomStrings']); |         langProvider = mockSingleton(CoreLang, ['clearCustomStrings']); | ||||||
|  | |||||||
| @ -78,6 +78,7 @@ import { Md5 } from 'ts-md5/dist/md5'; | |||||||
| // Import core classes that can be useful for site plugins.
 | // Import core classes that can be useful for site plugins.
 | ||||||
| import { CoreSyncBaseProvider } from '@classes/base-sync'; | import { CoreSyncBaseProvider } from '@classes/base-sync'; | ||||||
| import { CoreArray } from '@singletons/array'; | import { CoreArray } from '@singletons/array'; | ||||||
|  | import { CoreText } from '@singletons/text'; | ||||||
| import { CoreUrl } from '@singletons/url'; | import { CoreUrl } from '@singletons/url'; | ||||||
| import { CoreWindow } from '@singletons/window'; | import { CoreWindow } from '@singletons/window'; | ||||||
| import { CoreCache } from '@classes/cache'; | import { CoreCache } from '@classes/cache'; | ||||||
| @ -340,6 +341,7 @@ export class CoreCompileProvider { | |||||||
|         instance['Md5'] = Md5; |         instance['Md5'] = Md5; | ||||||
|         instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider; |         instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider; | ||||||
|         instance['CoreArray'] = CoreArray; |         instance['CoreArray'] = CoreArray; | ||||||
|  |         instance['CoreText'] = CoreText; | ||||||
|         instance['CoreUrl'] = CoreUrl; |         instance['CoreUrl'] = CoreUrl; | ||||||
|         instance['CoreWindow'] = CoreWindow; |         instance['CoreWindow'] = CoreWindow; | ||||||
|         instance['CoreCache'] = CoreCache; |         instance['CoreCache'] = CoreCache; | ||||||
|  | |||||||
| @ -52,6 +52,7 @@ import { CoreArray } from '../singletons/array'; | |||||||
| import { CoreNetworkError } from '@classes/errors/network-error'; | import { CoreNetworkError } from '@classes/errors/network-error'; | ||||||
| import { CoreNavigationOptions } from './navigator'; | import { CoreNavigationOptions } from './navigator'; | ||||||
| import { CoreSitesFactory } from './sites-factory'; | import { CoreSitesFactory } from './sites-factory'; | ||||||
|  | import { CoreText } from '@singletons/text'; | ||||||
| 
 | 
 | ||||||
| export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS'); | export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS'); | ||||||
| 
 | 
 | ||||||
| @ -1635,10 +1636,10 @@ export class CoreSitesProvider { | |||||||
|         // If more than one site is returned it usually means there are different users stored. Use any of them.
 |         // If more than one site is returned it usually means there are different users stored. Use any of them.
 | ||||||
|         const site = await this.getSite(siteIds[0]); |         const site = await this.getSite(siteIds[0]); | ||||||
| 
 | 
 | ||||||
|         const siteUrl = CoreTextUtils.removeEndingSlash( |         const siteUrl = CoreText.removeEndingSlash( | ||||||
|             CoreUrlUtils.removeProtocolAndWWW(site.getURL()), |             CoreUrlUtils.removeProtocolAndWWW(site.getURL()), | ||||||
|         ); |         ); | ||||||
|         const treatedUrl = CoreTextUtils.removeEndingSlash(CoreUrlUtils.removeProtocolAndWWW(url)); |         const treatedUrl = CoreText.removeEndingSlash(CoreUrlUtils.removeProtocolAndWWW(url)); | ||||||
| 
 | 
 | ||||||
|         if (siteUrl == treatedUrl) { |         if (siteUrl == treatedUrl) { | ||||||
|             result.site = site; |             result.site = site; | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ import { Locutus } from '@singletons/locutus'; | |||||||
| import { CoreViewerTextComponent } from '@features/viewer/components/text/text'; | import { CoreViewerTextComponent } from '@features/viewer/components/text/text'; | ||||||
| import { CoreFileHelper } from '@services/file-helper'; | import { CoreFileHelper } from '@services/file-helper'; | ||||||
| import { CoreDomUtils } from './dom'; | import { CoreDomUtils } from './dom'; | ||||||
|  | import { CoreText } from '@singletons/text'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Different type of errors the app can treat. |  * Different type of errors the app can treat. | ||||||
| @ -710,21 +711,10 @@ export class CoreTextUtilsProvider { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Remove ending slash from a path or URL. |      * @deprecated Use CoreText instead. | ||||||
|      * |  | ||||||
|      * @param text Text to treat. |  | ||||||
|      * @return Treated text. |  | ||||||
|      */ |      */ | ||||||
|     removeEndingSlash(text?: string): string { |     removeEndingSlash(text?: string): string { | ||||||
|         if (!text) { |         return CoreText.removeEndingSlash(text); | ||||||
|             return ''; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (text.slice(-1) == '/') { |  | ||||||
|             return text.substr(0, text.length - 1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return text; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
							
								
								
									
										59
									
								
								src/core/singletons/tests/url.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/core/singletons/tests/url.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | import { CoreUrl } from '@singletons/url'; | ||||||
|  | 
 | ||||||
|  | describe('CoreUrl singleton', () => { | ||||||
|  | 
 | ||||||
|  |     it('parses standard urls', () => { | ||||||
|  |         expect(CoreUrl.parse('https://my.subdomain.com/path/?query=search#hash')).toEqual({ | ||||||
|  |             protocol: 'https', | ||||||
|  |             domain: 'my.subdomain.com', | ||||||
|  |             path: '/path/', | ||||||
|  |             query: 'query=search', | ||||||
|  |             fragment: 'hash', | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('parses domains without TLD', () => { | ||||||
|  |         expect(CoreUrl.parse('ftp://localhost/nested/path')).toEqual({ | ||||||
|  |             protocol: 'ftp', | ||||||
|  |             domain: 'localhost', | ||||||
|  |             path: '/nested/path', | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('parses ips', () => { | ||||||
|  |         expect(CoreUrl.parse('http://192.168.1.157:8080/')).toEqual({ | ||||||
|  |             protocol: 'http', | ||||||
|  |             domain: '192.168.1.157', | ||||||
|  |             port: '8080', | ||||||
|  |             path: '/', | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('compares domains and paths', () => { | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu', 'https://school.edu')).toBe(true); | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu', 'HTTPS://SCHOOL.EDU')).toBe(true); | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'https://school.edu/moodle')).toBe(true); | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'https://school.edu/moodle/')).toBe(true); | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'https://school.edu/moodle#about')).toBe(true); | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'HTTPS://SCHOOL.EDU/MOODLE')).toBe(true); | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'HTTPS://SCHOOL.EDU/MOODLE/')).toBe(true); | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'HTTPS://SCHOOL.EDU/MOODLE#ABOUT')).toBe(true); | ||||||
|  | 
 | ||||||
|  |         expect(CoreUrl.sameDomainAndPath('https://school.edu/moodle', 'https://school.edu/moodle/about')).toBe(false); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | }); | ||||||
							
								
								
									
										43
									
								
								src/core/singletons/text.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/core/singletons/text.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Singleton with helper functions for text manipulation. | ||||||
|  |  */ | ||||||
|  | export class CoreText { | ||||||
|  | 
 | ||||||
|  |     // Avoid creating singleton instances.
 | ||||||
|  |     private constructor() { | ||||||
|  |         // Nothing to do.
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Remove ending slash from a path or URL. | ||||||
|  |      * | ||||||
|  |      * @param text Text to treat. | ||||||
|  |      * @return Treated text. | ||||||
|  |      */ | ||||||
|  |     static removeEndingSlash(text?: string): string { | ||||||
|  |         if (!text) { | ||||||
|  |             return ''; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (text.slice(-1) == '/') { | ||||||
|  |             return text.substr(0, text.length - 1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return text; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -12,7 +12,7 @@ | |||||||
| // See the License for the specific language governing permissions and
 | // See the License for the specific language governing permissions and
 | ||||||
| // limitations under the License.
 | // limitations under the License.
 | ||||||
| 
 | 
 | ||||||
| import { CoreTextUtils } from '@services/utils/text'; | import { CoreText } from './text'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Parts contained within a url. |  * Parts contained within a url. | ||||||
| @ -196,8 +196,11 @@ export class CoreUrl { | |||||||
|         const partsA = CoreUrl.parse(urlA); |         const partsA = CoreUrl.parse(urlA); | ||||||
|         const partsB = CoreUrl.parse(urlB); |         const partsB = CoreUrl.parse(urlB); | ||||||
| 
 | 
 | ||||||
|         return partsA?.domain == partsB?.domain && |         partsA && Object.entries(partsA).forEach(([part, value]) => partsA[part] = value?.toLowerCase()); | ||||||
|             CoreTextUtils.removeEndingSlash(partsA?.path) == CoreTextUtils.removeEndingSlash(partsB?.path); |         partsB && Object.entries(partsB).forEach(([part, value]) => partsB[part] = value?.toLowerCase()); | ||||||
|  | 
 | ||||||
|  |         return partsA?.domain === partsB?.domain | ||||||
|  |             && CoreText.removeEndingSlash(partsA?.path) === CoreText.removeEndingSlash(partsB?.path); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,6 +21,12 @@ console.debug = () => { | |||||||
|     // Silence.
 |     // Silence.
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | // eslint-disable-next-line no-console, jest/no-jasmine-globals, @typescript-eslint/no-explicit-any
 | ||||||
|  | console.error = (...args: any[]) => fail(args.map(a => a.toString()).join('')); | ||||||
|  | 
 | ||||||
|  | // eslint-disable-next-line jest/no-jasmine-globals
 | ||||||
|  | process.on('unhandledRejection', error => fail(error)); | ||||||
|  | 
 | ||||||
| // Override the method to create singleton method proxies in order to facilitate setting up
 | // Override the method to create singleton method proxies in order to facilitate setting up
 | ||||||
| // test expectations about method calls.
 | // test expectations about method calls.
 | ||||||
| setCreateSingletonMethodProxy( | setCreateSingletonMethodProxy( | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user