mirror of https://github.com/laurent22/joplin.git
Merge branch 'dev' into fix_publish_note
commit
f1fde99d5b
|
@ -49,7 +49,7 @@ Coding style is enforced by a pre-commit hook that runs eslint. This hook is ins
|
|||
|
||||
For new React components, please use [React Hooks](https://reactjs.org/docs/hooks-intro.html). For new code in general, please use TypeScript. Even if you are modifying a file that was originally in JavaScript you should ideally convert it first to TypeScript before modifying it. Doing so is relatively easy and it helps maintain code quality.
|
||||
|
||||
For changes made to the Desktop client that affect the user interface, refer to `packages/app-desktop/theme.ts` for all styling information. The goal is to create a consistent user interface to allow for easy navigation of Joplin's various features and improve the overall user experience.
|
||||
For changes made to the Desktop and mobile clients that affect the user interface, refer to `packages/lib/theme.ts` for all styling information. The goal is to create a consistent user interface to allow for easy navigation of Joplin's various features and improve the overall user experience.
|
||||
|
||||
## Automated tests
|
||||
|
||||
|
|
|
@ -161,8 +161,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||
|
||||
this.onJoplinLinkClick_ = async (msg: string) => {
|
||||
try {
|
||||
if (msg.indexOf('joplin://') === 0) {
|
||||
const resourceUrlInfo = urlUtils.parseResourceUrl(msg);
|
||||
const resourceUrlInfo = urlUtils.parseResourceUrl(msg);
|
||||
if (resourceUrlInfo) {
|
||||
const itemId = resourceUrlInfo.itemId;
|
||||
const item = await BaseItem.loadItemById(itemId);
|
||||
if (!item) throw new Error(_('No item with ID %s', itemId));
|
||||
|
|
|
@ -418,7 +418,7 @@ export default class BaseItem extends BaseModel {
|
|||
const share = item.share_id ? await this.shareService().shareById(item.share_id) : null;
|
||||
const serialized = await ItemClass.serialize(item, shownKeys);
|
||||
|
||||
if (!getEncryptionEnabled() || !ItemClass.encryptionSupported() || !itemCanBeEncrypted(item)) {
|
||||
if (!getEncryptionEnabled() || !ItemClass.encryptionSupported() || !itemCanBeEncrypted(item, share)) {
|
||||
// Normally not possible since itemsThatNeedSync should only return decrypted items
|
||||
if (item.encryption_applied) throw new JoplinError('Item is encrypted but encryption is currently disabled', 'cannotSyncEncrypted');
|
||||
return serialized;
|
||||
|
|
|
@ -411,3 +411,37 @@ describe('models/Note', function() {
|
|||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('models/Note_replacePaths', function() {
|
||||
|
||||
function testResourceReplacment(body: string, pathsToTry: string[], expected: string) {
|
||||
expect(Note['replaceResourceExternalToInternalLinks_'](pathsToTry, body)).toBe(expected);
|
||||
}
|
||||
test('Basic replacement', () => {
|
||||
const body = '![image.png](file:///C:Users/Username/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||
const pathsToTry = ['file:///C:Users/Username/resources'];
|
||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||
testResourceReplacment(body, pathsToTry, expected);
|
||||
});
|
||||
|
||||
test('Replacement with spaces', () => {
|
||||
const body = '![image.png](file:///C:Users/Username%20with%20spaces/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||
const pathsToTry = ['file:///C:Users/Username with spaces/resources'];
|
||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||
testResourceReplacment(body, pathsToTry, expected);
|
||||
});
|
||||
|
||||
test('Replacement with Non-ASCII', () => {
|
||||
const body = '![image.png](file:///C:Users/UsernameWith%C3%A9%C3%A0%C3%B6/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||
const pathsToTry = ['file:///C:Users/UsernameWithéàö/resources'];
|
||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||
testResourceReplacment(body, pathsToTry, expected);
|
||||
});
|
||||
|
||||
test('Replacement with Non-ASCII and spaces', () => {
|
||||
const body = '![image.png](file:///C:Users/Username%20With%20%C3%A9%C3%A0%C3%B6/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||
const pathsToTry = ['file:///C:Users/Username With éàö/resources'];
|
||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||
testResourceReplacment(body, pathsToTry, expected);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -182,7 +182,7 @@ export default class Note extends BaseItem {
|
|||
|
||||
const resourceDir = toForwardSlashes(Setting.value('resourceDir'));
|
||||
|
||||
let pathsToTry = [];
|
||||
const pathsToTry = [];
|
||||
if (options.useAbsolutePaths) {
|
||||
pathsToTry.push(`file://${resourceDir}`);
|
||||
pathsToTry.push(`file:///${resourceDir}`);
|
||||
|
@ -192,6 +192,13 @@ export default class Note extends BaseItem {
|
|||
pathsToTry.push(Resource.baseRelativeDirectoryPath());
|
||||
}
|
||||
|
||||
body = Note.replaceResourceExternalToInternalLinks_(pathsToTry, body);
|
||||
return body;
|
||||
}
|
||||
|
||||
private static replaceResourceExternalToInternalLinks_(pathsToTry: string[], body: string) {
|
||||
// This is a moved to a separate function for the purpose of testing only
|
||||
|
||||
// We support both the escaped and unescaped versions because both
|
||||
// of those paths are valid:
|
||||
//
|
||||
|
@ -202,7 +209,7 @@ export default class Note extends BaseItem {
|
|||
const temp = [];
|
||||
for (const p of pathsToTry) {
|
||||
temp.push(p);
|
||||
temp.push(markdownUtils.escapeLinkUrl(p));
|
||||
temp.push(encodeURI(p));
|
||||
}
|
||||
|
||||
pathsToTry = temp;
|
||||
|
@ -227,7 +234,6 @@ export default class Note extends BaseItem {
|
|||
// Handles joplin://af0edffa4a60496bba1b0ba06b8fb39a
|
||||
body = body.replace(/\(joplin:\/\/([a-zA-Z0-9]{32})\)/g, '(:/$1)');
|
||||
}
|
||||
|
||||
// this.logger().debug('replaceResourceExternalToInternalLinks result', body);
|
||||
|
||||
return body;
|
||||
|
|
|
@ -207,7 +207,7 @@ export default class Resource extends BaseItem {
|
|||
|
||||
const share = resource.share_id ? await this.shareService().shareById(resource.share_id) : null;
|
||||
|
||||
if (!getEncryptionEnabled() || !itemCanBeEncrypted(resource as any)) {
|
||||
if (!getEncryptionEnabled() || !itemCanBeEncrypted(resource as any, share)) {
|
||||
// Normally not possible since itemsThatNeedSync should only return decrypted items
|
||||
if (resource.encryption_blob_encrypted) throw new Error('Trying to access encrypted resource but encryption is currently disabled');
|
||||
return { path: plainTextPath, resource: resource };
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
import { BaseItemEntity } from '../../services/database/types';
|
||||
import { StateShare } from '../../services/share/reducer';
|
||||
|
||||
export default function(resource: BaseItemEntity): boolean {
|
||||
return !resource.is_shared;
|
||||
export default function(item: BaseItemEntity, share: StateShare): boolean {
|
||||
// Note has been published - currently we don't encrypt
|
||||
if (item.is_shared) return false;
|
||||
|
||||
// Item has been shared with user, but sharee is not encrypting his notes,
|
||||
// so we shouldn't encrypt it either. Otherwise sharee will not be able to
|
||||
// view the note anymore. https://github.com/laurent22/joplin/issues/6645
|
||||
if (item.share_id && (!share || !share.master_key_id)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -140,6 +140,7 @@ describe('ShareService', function() {
|
|||
expect(await MasterKey.count()).toBe(1);
|
||||
|
||||
let { folder, note, resource } = await testShareFolder(shareService);
|
||||
await Folder.updateAllShareIds(resourceService());
|
||||
|
||||
// The share service should automatically create a new encryption key
|
||||
// specifically for that shared folder
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
// Sync object
|
||||
/** @type {import('@jest/types').Config.InitialOptions} */
|
||||
const config = {
|
||||
preset: 'react-native',
|
||||
modulePathIgnorePatterns: [
|
||||
'<rootDir>/example/node_modules',
|
||||
'<rootDir>/lib/',
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
|
@ -15,13 +15,9 @@
|
|||
"react-native-saf-x.podspec",
|
||||
"!lib/typescript/example",
|
||||
"!android/build",
|
||||
"!ios/build",
|
||||
"!**/__tests__",
|
||||
"!**/__fixtures__",
|
||||
"!**/__mocks__"
|
||||
"!ios/build"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"linter-precommit": "yarn --cwd ../../ eslint --resolve-plugins-relative-to . --fix packages/react-native-saf-x/**/*.{js,ts,tsx}",
|
||||
"tsc": "tsc --project tsconfig.json"
|
||||
},
|
||||
|
@ -42,10 +38,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/react": "^16.9.55",
|
||||
"@types/react-native": "^0.64.4",
|
||||
"jest": "^26.6.3",
|
||||
"react": "17.0.2",
|
||||
"react-native": "0.66.1",
|
||||
"typescript": "^4.0.5"
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
],
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"tests/support/**/*",
|
||||
"tests-build/**/*",
|
||||
"build/**/*",
|
||||
],
|
||||
}
|
|
@ -3517,10 +3517,8 @@ __metadata:
|
|||
resolution: "@joplin/react-native-saf-x@workspace:packages/react-native-saf-x"
|
||||
dependencies:
|
||||
"@babel/core": ^7.12.9
|
||||
"@types/jest": ^26.0.15
|
||||
"@types/react": ^16.9.55
|
||||
"@types/react-native": ^0.64.4
|
||||
jest: ^26.6.3
|
||||
react: 17.0.2
|
||||
react-native: 0.66.1
|
||||
typescript: ^4.0.5
|
||||
|
|
Loading…
Reference in New Issue