Skip to content

Commit

Permalink
Fix description length validation and tag limiting
Browse files Browse the repository at this point in the history
The validation functions would get passed the raw description as entered
by the user and would make some half-hearted effort to parse them into
something sensible, but this completely breaks down in the face of
shortcuts like {default}, username shortcuts that get turned into long
links etc. Now those functions get the actually parsed description
passed to them, the only unresolved shortcut in them being the `{tags}`
one, since the length of that is variable and up to the validation
function to deal with and tell the user if tags didn't fit.

Since mvdicarlo#286, tags insertion is also pretty much busted entirely, since it
runs at the wrong time, so it may insert too many tags and then cause an
error down the line because the resulting description is too long. That
insertion logic has now been moved to the end of the description
processing, where it belongs.
  • Loading branch information
askmeaboutlo0m committed Jul 22, 2024
1 parent c096b06 commit 498eef8
Show file tree
Hide file tree
Showing 38 changed files with 150 additions and 116 deletions.
19 changes: 13 additions & 6 deletions electron-app/src/server/submission/parser/parser.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
Submission,
FileSubmission,
FileRecord,
SubmissionPart,
} from 'postybirb-commons';
import { ScalingOptions } from 'src/server/websites/interfaces/scaling-options.interface';
import { PostData } from '../post/interfaces/post-data.interface';
Expand Down Expand Up @@ -42,7 +43,12 @@ export class ParserService {
private readonly fileManipulator: FileManipulationService,
websitesService: WebsitesService,
) {
this.descriptionParser = new DescriptionParser(customShortcuts, websitesService, settings, this);
this.descriptionParser = new DescriptionParser(
customShortcuts,
websitesService,
settings,
this,
);
}

public async parse(
Expand Down Expand Up @@ -86,17 +92,18 @@ export class ParserService {

public async parseDescription(
website: Website,
defaultPart: SubmissionPartEntity<DefaultOptions>,
websitePart: SubmissionPartEntity<DefaultOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
websitePart: SubmissionPart<DefaultOptions>,
type: SubmissionType,
generateTags: boolean = true,
): Promise<string> {
return this.descriptionParser.parse(website, defaultPart, websitePart, type);
return this.descriptionParser.parse(website, defaultPart, websitePart, type, generateTags);
}

public async parseTags(
website: Website,
defaultPart: SubmissionPartEntity<DefaultOptions>,
websitePart: SubmissionPartEntity<DefaultOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
websitePart: SubmissionPart<DefaultOptions>,
): Promise<string[]> {
let tags = _.uniq<string>(FormContent.getTags(defaultPart.data.tags, websitePart.data.tags));
if (tags.length) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { DefaultOptions, SubmissionType, UsernameShortcut } from 'postybirb-commons';
import {
DefaultOptions,
SubmissionPart,
SubmissionType,
UsernameShortcut,
} from 'postybirb-commons';
import { CustomShortcutService } from 'src/server/custom-shortcut/custom-shortcut.service';
import { HTMLFormatParser } from 'src/server/description-parsing/html/html.parser';
import { AdInsertParser } from 'src/server/description-parsing/miscellaneous/ad.parser';
Expand Down Expand Up @@ -43,18 +48,18 @@ export class DescriptionParser {

public async parse(
website: Website,
defaultPart: SubmissionPartEntity<DefaultOptions>,
websitePart: SubmissionPartEntity<DefaultOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
websitePart: SubmissionPart<DefaultOptions>,
type: SubmissionType,
generateTags: boolean = true,
): Promise<string> {
let description = FormContent.getDescription(
defaultPart.data.description,
websitePart.data.description,
).trim();

if (description.length) {
// Insert {default}, {title}, {tags}, {cw} shortcuts
let tags = await this.parserService.parseTags(website, defaultPart, websitePart);
// Insert {default}, {title}, {cw} shortcuts
description = this.insertDefaultShortcuts(description, [
{
name: 'default',
Expand All @@ -64,10 +69,6 @@ export class DescriptionParser {
name: 'title',
content: defaultPart.data.title ?? websitePart.data.title ?? '',
},
{
name: 'tags',
content: website.generateTagsString(tags, description, websitePart),
},
{
name: 'cw',
content: FormContent.getSpoilerText(defaultPart.data, websitePart.data),
Expand Down Expand Up @@ -108,6 +109,21 @@ export class DescriptionParser {
}

description = website.postParseDescription(description, type);

// Insert {tags} shortcut if desired. Happens at the end, since tags will
// get cut off if they're too long instead of failing the submission. In
// case we're validating, we leave the shortcut standing, since the
// validation code will act upon its presence.
if (generateTags) {
const tags = await this.parserService.parseTags(website, defaultPart, websitePart);
description = this.insertDefaultShortcuts(description, [
{
name: 'tags',
content: website.generateTagsString(tags, description, websitePart),
},
]);
}

return description.trim();
}

Expand Down
2 changes: 1 addition & 1 deletion electron-app/src/server/submission/submission.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ export class SubmissionService {
let hasProblems: boolean = false;
const parts = await this.partService.getPartsForSubmission(submission._id, true);
const problems: Problems = parts.length
? this.validatorService.validateParts(submission, parts)
? await this.validatorService.validateParts(submission, parts)
: {};
for (const p of Object.values(problems)) {
if (p.problems.length) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Module } from '@nestjs/common';
import { ValidatorService } from './validator.service';
import { WebsitesModule } from 'src/server/websites/websites.module';
import { ParserModule } from '../parser/parser.module';

@Module({
imports: [WebsitesModule],
imports: [WebsitesModule, ParserModule],
providers: [ValidatorService],
exports: [ValidatorService],
})
Expand Down
40 changes: 30 additions & 10 deletions electron-app/src/server/submission/validator/validator.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@ import { SubmissionType } from 'postybirb-commons';
import { ValidationParts } from './interfaces/validation-parts.interface';
import { Website } from 'src/server/websites/website.base';
import FileSubmissionEntity from '../file-submission/models/file-submission.entity';
import { ParserService } from '../parser/parser.service';

@Injectable()
export class ValidatorService {
constructor(private readonly websiteProvider: WebsiteProvider) {}
constructor(
private readonly websiteProvider: WebsiteProvider,
private readonly parserService: ParserService,
) {}

validateParts(submission: Submission, parts: Array<SubmissionPart<any>>): Problems {
async validateParts(
submission: Submission,
parts: Array<SubmissionPart<any>>,
): Promise<Problems> {
const defaultPart: SubmissionPart<DefaultOptions> = parts.find(p => p.isDefault);
const websiteProblems: Problems = {};
parts
.filter(p => !p.isDefault)
.forEach(p => {
for (const p of parts) {
if (!p.isDefault) {
websiteProblems[p.accountId] = {
...this.validatePart(submission, p, defaultPart),
...(await this.validatePart(submission, p, defaultPart)),
website: p.website,
accountId: p.accountId,
};
});
}
}

return {
[defaultPart.accountId]: {
Expand All @@ -37,22 +44,35 @@ export class ValidatorService {
};
}

private validatePart(
private async validatePart(
submission: Submission,
part: SubmissionPart<any>,
defaultPart: SubmissionPart<DefaultOptions>,
): ValidationParts {
): Promise<ValidationParts> {
const website: Website = this.websiteProvider.getWebsiteModule(part.website);
const parsedPart = this.parsePart(part, defaultPart);
const description = await this.parserService.parseDescription(
website,
defaultPart,
part,
submission.type,
false,
);
switch (submission.type) {
case SubmissionType.FILE:
return website.validateFileSubmission(
submission as FileSubmissionEntity,
parsedPart,
defaultPart,
description,
);
case SubmissionType.NOTIFICATION:
return website.validateNotificationSubmission(submission, parsedPart, defaultPart);
return website.validateNotificationSubmission(
submission,
parsedPart,
defaultPart,
description,
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export class Artconomy extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<ArtconomyFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down Expand Up @@ -252,11 +253,8 @@ export class Artconomy extends Website {
'relationships depicted',
);
}
const description = this.defaultDescriptionParser(
FormContent.getDescription(defaultPart.data.description, submissionPart.data.description),
)

if (description.length > this.MAX_CHARS) {
if (this.stripTagsShortcut(description).length > this.MAX_CHARS) {
problems.push('Description must be 2000 characters or fewer.')
}

Expand Down
1 change: 1 addition & 0 deletions electron-app/src/server/websites/aryion/aryion.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export class Aryion extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<AryionFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
13 changes: 6 additions & 7 deletions electron-app/src/server/websites/bluesky/bluesky.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ export class Bluesky extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<BlueskyFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand All @@ -404,7 +405,7 @@ export class Bluesky extends Website {

this.validateRating(submissionPart, defaultPart, warnings);

this.validateDescription(problems, warnings, submissionPart, defaultPart);
this.validateDescription(problems, warnings, submissionPart, defaultPart, description);

files.forEach(file => {
const { type, size, name, mimetype } = file;
Expand Down Expand Up @@ -450,11 +451,12 @@ export class Bluesky extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<BlueskyNotificationOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];

this.validateDescription(problems, warnings, submissionPart, defaultPart);
this.validateDescription(problems, warnings, submissionPart, defaultPart, description);
this.validateReplyToUrl(problems, submissionPart.data.replyToUrl);
this.validateRating(submissionPart, defaultPart, warnings);

Expand Down Expand Up @@ -487,12 +489,9 @@ export class Bluesky extends Website {
warnings: string[],
submissionPart: SubmissionPart<BlueskyNotificationOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): void {
const description = this.defaultDescriptionParser(
FormContent.getDescription(defaultPart.data.description, submissionPart.data.description),
);

const rt = new RichText({ text: description });
const rt = new RichText({ text: this.stripTagsShortcut(description) });
const agent = new BskyAgent({ service: 'https://bsky.social' });
rt.detectFacets(agent);

Expand Down
1 change: 1 addition & 0 deletions electron-app/src/server/websites/custom/custom.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export class Custom extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<DefaultFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export class Derpibooru extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<any>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ export class DeviantArt extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<DeviantArtFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
14 changes: 4 additions & 10 deletions electron-app/src/server/websites/discord/discord.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export class Discord extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<DiscordFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand All @@ -160,11 +161,7 @@ export class Discord extends Website {
}
});

const description = this.defaultDescriptionParser(
FormContent.getDescription(defaultPart.data.description, submissionPart.data.description),
);

if (description.length > this.MAX_CHARS) {
if (this.stripTagsShortcut(description).length > this.MAX_CHARS) {
warnings.push('Max description length allowed is 2,000 characters.');
}

Expand All @@ -175,15 +172,12 @@ export class Discord extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<DiscordNotificationOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];

const description = this.defaultDescriptionParser(
FormContent.getDescription(defaultPart.data.description, submissionPart.data.description),
);

if (description.length > this.MAX_CHARS) {
if (this.stripTagsShortcut(description).length > this.MAX_CHARS) {
warnings.push('Max description length allowed is 2,000 characters.');
}

Expand Down
1 change: 1 addition & 0 deletions electron-app/src/server/websites/e621/e621.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export class e621 extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<any>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ export class FurAffinity extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<FurAffinityFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export class Furbooru extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<any>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ export class FurryNetwork extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<FurryNetworkFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down Expand Up @@ -506,6 +507,7 @@ export class FurryNetwork extends Website {
submission: Submission,
submissionPart: SubmissionPart<FurryNetworkNotificationOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems = [];
const warnings = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export class Furtastic extends Website {
submission: FileSubmission,
submissionPart: SubmissionPart<any>,
defaultPart: SubmissionPart<DefaultOptions>,
description: string,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
Expand Down
Loading

0 comments on commit 498eef8

Please sign in to comment.