Skip to content

Commit

Permalink
V1.2.0
Browse files Browse the repository at this point in the history
FIX: Closes #18, handle attachment resources with empty title values
IMPROVED: now able to browse for file location in settings
IMPROVED: minor update to menu option name
IMPROVED: info logs in console
DOCS: README clarifications
CHORE: debug statements
  • Loading branch information
manuerwin committed Jul 19, 2023
1 parent e2c06fb commit 852cab3
Show file tree
Hide file tree
Showing 8 changed files with 1,254 additions and 1,138 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## not released

## v1.2.0 (2023-07-18)

FIX: handle attachment resources that do not have title values (e.g. iPhone image upload).
IMPROVED: now able to browse for file location in settings.
IMPROVED: minor update to menu option name.
IMPROVED: better info logs in console.
DOCS: detail added to README re: importance of taking backups and original attachment resource name not being changed.

## v1.1.1 (2022-01-03)

IMPROVED: no need to remove files from step 2 directory for subsequent replacements.
Expand Down
55 changes: 16 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,97 +2,74 @@
A Joplin plugin. Your attachment updater. Mass replacement of Joplin attachments (resources) such as resized image files, current music playlists, and any other attachments you need to one-off or regularly update within Joplin.

# Installation

## Automatic

- Go to `Preferences > Plugins` (Mac) OR `Tools > Options > Plugins`
- Search for `Attaché`
- Click Install plugin
- Restart Joplin to enable the plugin

## Manual

- Download the latest released JPL package (`io.github.manuerwin.attache.jpl`) from [here](https://github.com/manuerwin/joplin-plugin-attache/releases/latest)
- Close Joplin
- Copy the downloaded JPL package into your profile `plugins` folder
- Start Joplin

# Usage
First backup your data!

First configure the Plugin under `Preferences > Plugins > Attaché` (Mac) OR `Tools > Options > Attaché` (PC?)
Then configure the Plugin under `Preferences > Plugins > Attaché` (Mac) OR `Tools > Options > Attaché` (PC?)

Note: due to Joplin's synchronisation conflict safeguards, this is a two-step automated process.

## Manual use
After setting the configuration settings and restarting, the file and processing sub-directories are automatically created for you.

There has been a report of problems processing a large number of replacement files (8000+), please backup your Joplin data by using the easy export option, perform a small test to make sure all works ok for you. and suggest not touching Joplin notes/resources while the replacement is happening.

### Step One - deleting resources and sync'ing
Move your source files into the files path that you entered into settings. Your source files can be named in two ways:
Move your source files into the files path that you entered/choose in settings. Your source files can be named in two ways:
1) the same filename as shown in your notes (for example, music.m3u)
2) the id of the resource (for example, b8bf831c8d804f6d8e5ab13ae12de595.jpg)

IMPORTANT: If you are choosing to replace resources via filename (for example, music.m3u), you must be certain there is only one resource with that filename across all your notes. If there are more, none will be replaced.
AND: The filename in your note must be unchanged from when you originally attached it.
**IMPORTANT**: If you are choosing to replace resources via filename (for example, music.m3u), you must be certain:
1. there is **only one resource with that filename across all your notes**. If there are more, none will be replaced. AND
2. The **filename in your note must be unchanged** from when you originally attached it. This is because of the way Joplin stores references to resources(attachments) under the covers.

Choose the `Tools > Replace/update attachments` command.
Choose the `Tools > Attaché - Replace/update attachments` command (Mac) OR '???' command (PC).
This will delete each matching resource within Joplin, and move each source file to the `Step 1 - Resource Deleted Sync Needed` sub-directory.

Important: this step has NOT updated your Notes, you will see the resource reference within any note still exists, however the preview of the note/resource will show a placeholder icon.
Important: this step has NOT updated your Notes, you will see the resource reference within any note still exists, however the preview of the note/resource will show a placeholder icon because the underlying resource (aka attachment) no longer exists.

Synchronisation is automatically started for you, you'll see remote resources being deleted.

Note: a .REPLACE file is created in this sub-directory for each of the resources you are replacing, you can ignore these.
Note: a .REPLACE file is created in this sub-directory for each of the resources you are replacing, please don't touch these as Attaché uses them for step two.

### Step Two - creating resources
After the above synchronisation has finished, the plugin will create each resource within Joplin, and move your source file to the `Step 2 - Resource Replaced` sub-directory.

Again, your Notes have NOT been updated in any way, the placeholder icon in preview will now show your replacement resource :)
Again, your Notes have NOT been updated in any way. The placeholder icon in preview will now show your replacement resource, as your replacement file has just been created with the same reference id that's in your note.

Also note: your source files are NEVER deleted, they are simply moved to different locations so you know the status of each file/resource.
Also note: your source replacement files are NEVER deleted, they are simply moved to different locations so you know the status of each file/resource.

## Automated use

By enabling the `Run on start and after sync` option, Attaché will be run on Joplin start and following synchronisation for you.

Move your source files into the files path, matching the settings entry.

Either restart Joplin or force synchronisation.

# Configuration Options

| Option | Description | Default |
| --------------- | ----------- | ------- |
| `Files Path` | Where to obtain the files that will replace resources. <br>Filenames MUST be only the target resource id in the format of <resource_id>.<file_extension>, for example b1a7160da73b45ba80b9aeb0bc9d574c.png, others will be ignored. | |
| `Files Path` | Where to obtain the replacement files that will replace existing resources. See Step One above for the two formats replacement filenames can have. All others will be ignored. | |
| `Run on start and after sync` | If checked (i.e. true), Attaché will run immediately after Joplin starts and after each synchronisation. | unchecked (i.e. will NOT run on start or after sync by default) |

# Building the plugin

The plugin is built using Webpack, which creates the compiled code in `/dist`.
A JPL archive will also be created in `/publish`, which can be used to distribute the plugin.

To build the plugin, simply run `npm run dist`.

The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.

# Testing the plugin

To test the plugin, simply run `npm test`.

This project is setup to use Jest for testing purposes.

# Updating the plugin framework

To update the plugin framework, run `npm run update`.

In general this command tries to do the right thing - in particular it's going to merge the changes in package.json and .gitignore instead of overwriting. It will also leave "/src" as well as README.md untouched.

The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.

# Changelog

See [CHANGELOG.md](CHANGELOG.md)

# Links
# Developers: Links
Would you like to contribute to this or build your own plugin?

- [Joplin - Getting started with plugin development](https://joplinapp.org/api/get_started/plugins/)
- [Joplin - Plugin API reference](https://joplinapp.org/api/references/plugin_api/classes/joplin.html)
Expand Down
39 changes: 37 additions & 2 deletions __tests__/replaceResources.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,42 @@ describe("Replace Resources", function () {
expect(fs.existsSync(filePathExt)).toBe(false);
});

test(`5-Attachment format DOES match resource + sync config enabled + run on start and after sync enabled`, async () => {
test(`5-Attachment name format DOES match resource + sync config enabled + title is null/undefined`, async () => {
console.debug(`#######################TEST-5-Attachment name format DOES match resource + sync config enabled + title is null/undefined#######################`);
const filePathExt = path.join(testBaseDir, attachmentNameFormatFilename);
fs.writeFileSync(filePathExt, "file");
expect(fs.existsSync(filePathExt)).toBe(true);

const mockgetResource = getResourceByFilename as jest.MockedFunction<typeof getResourceByFilename>;
let resourceReturned: resourceByFileName = {
id: resourceIdFormat,
title: '',
user_created_time: createdTime,
};
let itemsReturned = new Array<resourceByFileName>(resourceReturned);
let resultsReturned: apiSearchResult = {
items: itemsReturned,
};
mockgetResource.mockResolvedValue(resultsReturned);

const mockdeleteResource = deleteResource as jest.MockedFunction<typeof deleteResource>;
mockdeleteResource.mockResolvedValue(true);
const mocksyncConfigured = syncConfigured as jest.MockedFunction<typeof syncConfigured>;
mocksyncConfigured.mockResolvedValue(true);

await deleteResources();
expect(getResourceById).toHaveBeenCalledTimes(0);
expect(getResourceByFilename).toHaveBeenCalledTimes(1);
expect(deleteResource).toHaveBeenCalledTimes(1);
expect(syncConfigured).toHaveBeenCalledTimes(1);
expect(executeSync).toHaveBeenCalledTimes(1);
await createResources();
expect(postResource).toHaveBeenCalledTimes(1);
expect(putResource).toHaveBeenCalledTimes(1);
expect(fs.existsSync(filePathExt)).toBe(false);
});

test(`6-Attachment format DOES match resource + sync config enabled + run on start and after sync enabled`, async () => {
console.debug(`#######################TEST-5-Attachment format DOES match resource + sync config enabled + run on start and after sync enabled#######################`);
const filePathExt = path.join(testBaseDir, attachmentNameFormatFilename);
fs.writeFileSync(filePathExt, "file");
Expand Down Expand Up @@ -227,7 +262,7 @@ describe("Replace Resources", function () {
expect(fs.existsSync(filePathExt)).toBe(false);
});

test(`6-ensure replace completes subsequent times without manual removal of files from step 2 directory`, async () => {
test(`7-ensure replace completes subsequent times without manual removal of files from step 2 directory`, async () => {
console.debug(`#######################TEST-6-ensure replace completes subsequent times without manual removal of files from step 2 directory#######################`);
let filePathExt = path.join(testBaseDir, attachmentNameFormatFilename);
fs.writeFileSync(filePathExt, "file");
Expand Down
Loading

0 comments on commit 852cab3

Please sign in to comment.