Skip to content

Commit

Permalink
Added scrubbing of filename components when moving comics [#491]
Browse files Browse the repository at this point in the history
 * Frontend scrubs the renaming rule as it's entered.
 * Backend scrubs the values when received.
  • Loading branch information
mcpierce authored and BRUCELLA2 committed Sep 8, 2020
1 parent 585b4a0 commit 237db3e
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 12 deletions.
Expand Up @@ -25,7 +25,9 @@
<input pInputText
id="cx-renaming-rule"
class="cx-input-field"
formControlName="renamingRule">
formControlName="renamingRule"
(paste)="onPaste($event)"
(input)="onInput()">
</div>
<div class="ui-g-12">
<p>{{"library.move-comics.variables-note"|translate}}</p>
Expand Down
Expand Up @@ -262,4 +262,27 @@ describe('ConsolidateLibraryComponent', () => {
expect(confirmationService.confirm).not.toHaveBeenCalled();
});
});

describe('invalid characters are scrubbed', () => {
it('applies to typed characters', () => {
component.consolidationForm.controls.renamingRule.setValue('[]:\\*?|<>');
component.onInput();
expect(component.consolidationForm.controls.renamingRule.value).toEqual(
'_________'
);
});

it('applies to pasted characters', () => {
const event = new ClipboardEvent('paste', {
clipboardData: new DataTransfer()
});
event.clipboardData.setData('text', '[]:\\*?|<>');
console.log('*** event:', event);
component.onPaste(event);
fixture.detectChanges();
expect(component.consolidationForm.controls.renamingRule.value).toEqual(
'_________'
);
});
});
});
Expand Up @@ -77,7 +77,7 @@ export class ConsolidateLibraryComponent implements OnInit, OnDestroy {
this.userSubscription = this.authenticationAdaptor.user$.subscribe(() => {
this.consolidationForm.controls['deletePhysicalFiles'].setValue(
this.authenticationAdaptor.getPreference(
MOVE_COMICS_DELETE_PHYSICAL_FILE
MOVE_COMICS_DELETE_PHYSICAL_FILE
) === 'true'
);
});
Expand Down Expand Up @@ -120,7 +120,7 @@ export class ConsolidateLibraryComponent implements OnInit, OnDestroy {
.value;
this.authenticationAdaptor.setPreference(
MOVE_COMICS_DELETE_PHYSICAL_FILE,
`${deletePhysicalFiles}`
`${deletePhysicalFiles}`
);
this.authenticationAdaptor.setPreference(
MOVE_COMICS_TARGET_DIRECTORY,
Expand Down Expand Up @@ -155,4 +155,19 @@ export class ConsolidateLibraryComponent implements OnInit, OnDestroy {
});
}
}

onPaste(event: ClipboardEvent): void {
this.filterRenamingRule(event.clipboardData.getData('text'));
}

onInput() {
this.filterRenamingRule(this.consolidationForm.controls.renamingRule.value);
}

private filterRenamingRule(rule: string): void {
console.log('*** rule:', rule);
const re = /[:\\*?|<>\[\]]/gi;
rule = rule.replace(re, '_');
this.consolidationForm.controls.renamingRule.setValue(rule);
}
}
Expand Up @@ -38,7 +38,7 @@ import { BehaviorSubject } from 'rxjs';
import { EffectsModule } from '@ngrx/effects';
import { LoggerModule } from '@angular-ru/logger';

fdescribe('LibraryDisplayAdaptor', () => {
describe('LibraryDisplayAdaptor', () => {
const USER = { ...USER_READER };

let libraryDisplayAdaptor: LibraryDisplayAdaptor;
Expand Down
Expand Up @@ -45,9 +45,12 @@
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Log4j2
public class MoveComicWorkerTask extends AbstractWorkerTask {
static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM yyyy");
private static final String FORBIDDING_RULE_CHARACTERS = "[:\\\\*?|<>]";
private static final String FORBIDDING_PROPERTY_CHARACTERS = "[:\\\\/*?|<>]";
private static final String UNKNOWN_VALUE = "Unknown";

static final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM yyyy");

@Autowired private ComicService comicService;

@Getter @Setter private Comic comic;
Expand Down Expand Up @@ -120,26 +123,30 @@ String getRelativeComicFilename() {
return FilenameUtils.getBaseName(this.comic.getFilename());
}

log.debug("Generating relative filename based on renaming rule: {}", this.renamingRule);
log.debug("Scrubbing renaming rule: {}", this.renamingRule);
final String rule = this.scrub(this.renamingRule, FORBIDDING_RULE_CHARACTERS);

log.debug("Generating relative filename based on renaming rule: {}", rule);

final String publisher =
StringUtils.isEmpty(this.comic.getPublisher()) ? UNKNOWN_VALUE : this.comic.getPublisher();
StringUtils.isEmpty(this.comic.getPublisher())
? UNKNOWN_VALUE
: scrub(this.comic.getPublisher());
final String series =
StringUtils.isEmpty(this.comic.getSeries()) ? UNKNOWN_VALUE : this.comic.getSeries();
StringUtils.isEmpty(this.comic.getSeries()) ? UNKNOWN_VALUE : scrub(this.comic.getSeries());
final String volume =
StringUtils.isEmpty(this.comic.getVolume()) ? UNKNOWN_VALUE : this.comic.getVolume();
final String issueNumber =
StringUtils.isEmpty(this.comic.getIssueNumber())
? UNKNOWN_VALUE
: this.comic.getIssueNumber();
: scrub(this.comic.getIssueNumber());
final String coverDate =
this.comic.getCoverDate() != null
? dateFormat.format(this.comic.getCoverDate())
: "No Cover Date";

final String result =
this.renamingRule
.replace("$PUBLISHER", publisher)
String result =
rule.replace("$PUBLISHER", publisher)
.replace("$SERIES", series)
.replace("$VOLUME", volume)
.replace("$ISSUE", issueNumber)
Expand All @@ -150,6 +157,15 @@ String getRelativeComicFilename() {
return result;
}

private String scrub(final String text) {
return this.scrub(text, FORBIDDING_PROPERTY_CHARACTERS);
}

private String scrub(final String text, final String forbidden) {
log.trace("Pre-sanitized text: {}", text);
return text.replaceAll(forbidden, "_");
}

private void addDirectory(StringBuilder result, String value) {
result.append(File.separator);

Expand Down
Expand Up @@ -106,6 +106,34 @@ public class MoveComicWorkerTaskTest {
TEST_VOLUME,
TEST_ISSUE,
"No Cover Date");
private static final String TEST_PUBLISHER_WITH_UNSUPPORTED_CHARACTERS = "?Publisher*";
private static final String TEST_PUBLISHER_WITH_UNSUPPORTED_CHARACTERS_SCRUBBED = "_Publisher_";
private static final String TEST_SERIES_WITH_UNSUPPORTED_CHARACTERS = "<|Series?>";
private static final String TEST_SERIES_WITH_UNSUPPORTED_CHARACTERS_SCRUBBED = "__Series__";
private static final String TEST_ISSUE_WITH_UNSUPPORTED_CHARACTERS = "\\/717:";
private static final String TEST_ISSUE_WITH_UNSUPPORTED_CHARACTERS_SCRUBBED = "__717_";
private static final String TEST_RELATIVE_NAME_SCRUBBED =
String.format(
"%s/%s/%s/%s v%s #%s (%s)",
TEST_PUBLISHER_WITH_UNSUPPORTED_CHARACTERS_SCRUBBED,
TEST_SERIES_WITH_UNSUPPORTED_CHARACTERS_SCRUBBED,
TEST_VOLUME,
TEST_SERIES_WITH_UNSUPPORTED_CHARACTERS_SCRUBBED,
TEST_VOLUME,
TEST_ISSUE_WITH_UNSUPPORTED_CHARACTERS_SCRUBBED,
TEST_FORMATTED_COVER_DATE);
private static final String TEST_RENAMING_RULE_WITH_UNSUPPORTED_CHARACTERS =
"?*$PUBLISHER/<|?>$SERIES/\\:$VOLUME/$SERIES v$VOLUME #$ISSUE ($COVERDATE)";
private static final String TEST_RELATIVE_NAME_WITH_RULE_WITH_SCRUBBED_CHARACTERS =
String.format(
"__%s/____%s/__%s/%s v%s #%s (%s)",
TEST_PUBLISHER,
TEST_SERIES,
TEST_VOLUME,
TEST_SERIES,
TEST_VOLUME,
TEST_ISSUE,
TEST_FORMATTED_COVER_DATE);

@InjectMocks private MoveComicWorkerTask task;
@Mock private ComicService comicService;
Expand Down Expand Up @@ -140,6 +168,26 @@ public void testGetRelativeComicFilename() {
assertEquals(TEST_RELATIVE_NAME_WITH_RULE, result);
}

@Test
public void testGetRelativeComicFilenameRenamingRuleHasUnsupportedCharacters() {
task.setRenamingRule(TEST_RENAMING_RULE_WITH_UNSUPPORTED_CHARACTERS);

final String result = task.getRelativeComicFilename();

assertEquals(TEST_RELATIVE_NAME_WITH_RULE_WITH_SCRUBBED_CHARACTERS, result);
}

@Test
public void testGetRelativeComicFilenameWithUnsupportedCharacters() {
Mockito.when(comic.getPublisher()).thenReturn(TEST_PUBLISHER_WITH_UNSUPPORTED_CHARACTERS);
Mockito.when(comic.getSeries()).thenReturn(TEST_SERIES_WITH_UNSUPPORTED_CHARACTERS);
Mockito.when(comic.getIssueNumber()).thenReturn(TEST_ISSUE_WITH_UNSUPPORTED_CHARACTERS);

final String result = task.getRelativeComicFilename();

assertEquals(TEST_RELATIVE_NAME_SCRUBBED, result);
}

@Test
public void testGetRelativeComicFilenameNoPublisher() {
Mockito.when(comic.getPublisher()).thenReturn(null);
Expand Down

0 comments on commit 237db3e

Please sign in to comment.