Skip to content

Commit ad0e37f

Browse files
authored
chore: clean up some todos (#321)
* chore: co-locate translation files * chore: tag conversion fix + remove app insights (needs log rotation now) * feat: tag conversion todos
1 parent 1fd51a6 commit ad0e37f

File tree

24 files changed

+138
-1102
lines changed

24 files changed

+138
-1102
lines changed

apps/client-server/src/app/file-converter/converters/text-file-converter.ts

-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ type ConversionWeights = {
2525
[outputMimeType in SupportedOutputMimeTypes]: number;
2626
};
2727

28-
// TODO - use this within the post service to convert alt files to acceptable format
29-
// TODO - use overall conversion check within the validator service to see if we can convert the file, this may be useful for the end user
3028
/**
3129
* A class that converts text files to other text formats.
3230
* Largely for use when converting AltFiles (text/html) to other desirable formats.

apps/client-server/src/app/post/post-manager.service.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { IsTestEnvironment } from '../utils/test.util';
3434
import { ValidationService } from '../validation/validation.service';
3535
import {
3636
ImplementedFileWebsite,
37-
isFileWebsite
37+
isFileWebsite,
3838
} from '../websites/models/website-modifiers/file-website';
3939
import { MessageWebsite } from '../websites/models/website-modifiers/message-website';
4040
import { Website } from '../websites/website';
@@ -110,16 +110,18 @@ export class PostManagerService {
110110
* i.e. the submission is deleted.
111111
* @param {SubmissionId} id
112112
*/
113-
public async cancelIfRunning(id: SubmissionId) {
113+
public async cancelIfRunning(id: SubmissionId): Promise<boolean> {
114114
if (this.currentPost) {
115115
if (!this.currentPost.parent) {
116116
const loaded = await wrap(this.currentPost).init(true, ['parent']);
117117
if (loaded.parent.id === id) {
118118
this.logger.info(`Cancelling current post`);
119119
this.cancelToken.cancel();
120+
return true;
120121
}
121122
}
122123
}
124+
return false;
123125
}
124126

125127
/**
@@ -396,7 +398,9 @@ export class PostManagerService {
396398

397399
// Split files into batches based on instance file batch size
398400
const batches = chunk(orderedFiles, fileBatchSize);
401+
let batchIndex = 0;
399402
for (const batch of batches) {
403+
batchIndex += 1;
400404
this.cancelToken.throwIfCancelled();
401405

402406
// Resize files if necessary
@@ -416,10 +420,10 @@ export class PostManagerService {
416420
// Post
417421
this.cancelToken.throwIfCancelled();
418422
this.logger.info(`Posting file batch to ${instance.id}`);
419-
// TODO - Do something with nextBatchNumber
420423
const result = await instance.onPostFileSubmission(
421424
data,
422425
processedFiles,
426+
batchIndex,
423427
this.cancelToken,
424428
);
425429

apps/client-server/src/app/post/post.service.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,11 @@ export class PostService extends PostyBirbService<PostRecord> {
124124
parent: { $in: request.ids },
125125
});
126126

127-
// TODO - reconsider what happens to a cancelled post since it seems to have strange behavior.
128-
// Is it best to not remove it if it is already in a post state and just mark it as cancelled?
129-
130127
// Only remove those that are not marked as done as to protect the archived posts.
131-
const incomplete = existing.filter(
132-
(e: PostRecord) => e.completedAt === undefined,
133-
);
128+
// Ignore the running posts as they are in progress and will be handled naturally through throws.
129+
const incomplete = existing
130+
.filter((e: PostRecord) => e.completedAt === undefined)
131+
.filter((e: PostRecord) => e.state === PostRecordState.PENDING);
134132

135133
request.ids.forEach((id) => this.postManagerService.cancelIfRunning(id));
136134
await Promise.all(incomplete.map((i) => this.remove(i.id)));

apps/client-server/src/app/submission/submission.controller.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ export class SubmissionController extends PostyBirbController<Submission> {
5656
const mapper = (res) => res.toJSON();
5757
if ((files || []).length) {
5858
const results = [];
59-
// TODO - need to reconsider how to queue submission creation up.
59+
// !NOTE: Currently this shouldn't be able to happen with the current UI, but may need to be addressed in the future.
60+
// Efforts have been made to prevent this from happening, with the removal of using entity.create({}) but it may still be possible.
6061
// There appears to be an issue where if trying to create many submissions in parallel
6162
// the database will attempt to create them all at once and fail on a race condition.
6263
// not sure if this is a database issue or a typeorm issue.
63-
// eslint-disable-next-line no-restricted-syntax
6464
for (const file of files) {
6565
const createFileSubmission = new CreateSubmissionDto();
6666
Object.assign(createFileSubmission, createSubmissionDto);

apps/client-server/src/app/tag-converters/tag-converters.service.spec.ts

+11
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,15 @@ describe('TagConvertersService', () => {
102102
await service.remove(record.id);
103103
expect(await service.findAll()).toHaveLength(0);
104104
});
105+
106+
it('should convert tags', async () => {
107+
const dto = createTagConverterDto('test', { default: 'converted' });
108+
109+
await service.create(dto);
110+
const result = await service.convert(
111+
{ decoratedProps: { metadata: { name: 'default' } } } as any,
112+
['test', 'test2'],
113+
);
114+
expect(result).toEqual(['converted', 'test2']);
115+
});
105116
});

apps/client-server/src/app/tag-converters/tag-converters.service.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export class TagConvertersService extends PostyBirbService<TagConverter> {
3939
return this.repository.update(id, update);
4040
}
4141

42-
// TODO - write tests for this
4342
/**
4443
* Converts a list of tags using user defined conversion table.
4544
*
@@ -56,7 +55,7 @@ export class TagConvertersService extends PostyBirbService<TagConverter> {
5655
}
5756
return (
5857
converter.convertTo[instance.decoratedProps.metadata.name] ??
59-
converter.convertTo.default ??
58+
converter.convertTo.default ?? // NOTE: This is not currently used, but it's here for future proofing
6059
tag
6160
);
6261
});

apps/client-server/src/app/validation/validators/description-validators.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export async function validateDescriptionMaxLength({
1919
const maxLength =
2020
descriptionSupport.maxDescriptionLength ?? Number.MAX_SAFE_INTEGER;
2121
if (description.length > maxLength) {
22-
result.errors.push({
22+
result.warnings.push({
2323
id: 'validation.description.max-length',
2424
field: 'description',
2525
values: {

apps/client-server/src/app/websites/implementations/default/default.website.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { DescriptionType, DynamicObject, ILoginState } from '@postybirb/types';
22
import { SupportsDescription } from '../../decorators/supports-description.decorator';
33
import { SupportsTags } from '../../decorators/supports-tags.decorator';
4+
import { WebsiteMetadata } from '../../decorators/website-metadata.decorator';
45
import { Website } from '../../website';
56

67
// This is a stub used for filling in for places where we have a null account
78
// but need to have a website instance.
89
@SupportsTags()
910
@SupportsDescription(DescriptionType.PLAINTEXT)
11+
@WebsiteMetadata({ name: 'default', displayName: 'Default' })
1012
export default class DefaultWebsite extends Website<DynamicObject> {
1113
protected BASE_URL: string;
1214

apps/client-server/src/app/websites/implementations/discord/discord.website.ts

+2-13
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { DiscordMessageSubmission } from './models/discord-message-submission';
3535
acceptedFileSizes: {},
3636
fileBatchSize: 10,
3737
})
38-
@SupportsDescription(DescriptionType.MARKDOWN)
38+
@SupportsDescription(DescriptionType.MARKDOWN, 2_000)
3939
export default class Discord
4040
extends Website<DiscordAccountData>
4141
implements
@@ -77,6 +77,7 @@ export default class Discord
7777
onPostFileSubmission(
7878
postData: PostData<FileSubmission, IWebsiteFormFields>,
7979
files: PostingFile[],
80+
batchIndex: number,
8081
cancellationToken: CancellableToken,
8182
): Promise<PostResponse> {
8283
throw new Error('Method not implemented.');
@@ -104,18 +105,6 @@ export default class Discord
104105
const result: SimpleValidationResult<DiscordMessageSubmission> = {
105106
warnings: [],
106107
};
107-
108-
// TODO - update validation
109-
// if (postData.options.description.description.trim().length > 2_000) {
110-
// result.warnings.push({
111-
// id: 'validation.description.max-length',
112-
// field: 'description',
113-
// values: {
114-
// maxLength: 2_000,
115-
// },
116-
// });
117-
// }
118-
119108
return result;
120109
}
121110
}

apps/client-server/src/app/websites/implementations/fur-affinity/fur-affinity.website.ts

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export default class FurAffinity
8888
onPostFileSubmission(
8989
postData: PostData<FileSubmission, FurAffinityFileSubmission>,
9090
files: PostingFile[],
91+
batchIndex: number,
9192
cancellationToken: CancellableToken,
9293
): Promise<PostResponse> {
9394
throw new Error('Method not implemented.');

apps/client-server/src/app/websites/implementations/test/test.website.ts

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export default class TestWebsite
7777
onPostFileSubmission(
7878
postData: PostData<FileSubmission, IWebsiteFormFields>,
7979
files: PostingFile[],
80+
batchIndex: number,
8081
cancellationToken: CancellableToken,
8182
): Promise<PostResponse> {
8283
throw new Error('Method not implemented.');

apps/client-server/src/app/websites/models/website-modifiers/file-website.ts

+10
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,19 @@ export interface FileWebsite<T extends IWebsiteFormFields> {
2929

3030
calculateImageResize(file: ISubmissionFile): ImageResizeProps | undefined;
3131

32+
/**
33+
* Handles the submission of a file to the website.
34+
*
35+
* @param {PostData<FileSubmission, T>} postData
36+
* @param {PostingFile[]} files - The files to post
37+
* @param {number} batchIndex - The index of the batch (if batching is required)
38+
* @param {CancellableToken} cancellationToken
39+
* @return {*} {Promise<PostResponse>}
40+
*/
3241
onPostFileSubmission(
3342
postData: PostData<FileSubmission, T>,
3443
files: PostingFile[],
44+
batchIndex: number,
3545
cancellationToken: CancellableToken,
3646
): Promise<PostResponse>;
3747

apps/postybirb-ui/src/components/form/fields/field-label.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { useLingui } from '@lingui/react';
33
import { Input } from '@mantine/core';
44
import type { FieldAggregateType } from '@postybirb/form-builder';
55
import { PropsWithChildren } from 'react';
6+
import { FieldLabelTranslations } from '../../translations/field-translations';
67
import { ValidationTranslation } from '../../translations/validation-translation';
78
import { UseValidationResult } from '../hooks/use-validations';
8-
import { fieldLabelTranslations } from './field-translations';
99
import { FormFieldProps } from './form-field.type';
1010

1111
type FieldLabelProps = FormFieldProps & {
@@ -16,7 +16,7 @@ export function getTranslatedLabel(
1616
field: FieldAggregateType,
1717
converter: (msg: MessageDescriptor) => string,
1818
): string {
19-
const translationLabel = fieldLabelTranslations[field.label];
19+
const translationLabel = FieldLabelTranslations[field.label];
2020

2121
if (!translationLabel) {
2222
// eslint-disable-next-line lingui/no-unlocalized-strings, no-console

apps/postybirb-ui/src/components/form/fields/field.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,5 @@ export function Field(props: FormFieldProps): JSX.Element | null {
5252
formField = <div>Unknown field type: {field.formField}</div>;
5353
}
5454

55-
// TODO - Happily merge external translation and the shared translations.
5655
return formField;
5756
}

apps/postybirb-ui/src/components/form/fields/tag-field.tsx

+64-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import { Trans } from '@lingui/macro';
2-
import { Box, Checkbox, Pill, TagsInput, Text } from '@mantine/core';
2+
import {
3+
Badge,
4+
Box,
5+
Checkbox,
6+
Group,
7+
Pill,
8+
TagsInput,
9+
Text,
10+
} from '@mantine/core';
311
import { TagFieldType } from '@postybirb/form-builder';
4-
import { Tag, TagGroupDto, TagValue } from '@postybirb/types';
12+
import { Tag, TagConverterDto, TagGroupDto, TagValue } from '@postybirb/types';
13+
import { IconArrowRight } from '@tabler/icons-react';
514
import { flatten, uniq } from 'lodash';
15+
import { useWebsites } from '../../../hooks/account/use-websites';
16+
import { TagConverterStore } from '../../../stores/tag-converter-store';
617
import { TagGroupStore } from '../../../stores/tag-group-store';
718
import { useStore } from '../../../stores/use-store';
819
import { useDefaultOption } from '../hooks/use-default-option';
@@ -16,16 +27,45 @@ function containsAllTagsInGroup(tags: Tag[], group: TagGroupDto): boolean {
1627
return group.tags.every((tag) => tags.includes(tag));
1728
}
1829

19-
// TODO - figure out some way to support indicating a tag converter is being used
30+
function getTagConversion(
31+
website: string,
32+
tagConverters: TagConverterDto[],
33+
tag: Tag,
34+
): Tag {
35+
const matchingConverter = tagConverters.find(
36+
(converter) => converter.tag === tag,
37+
);
38+
if (!matchingConverter) {
39+
return tag;
40+
}
41+
42+
return (
43+
matchingConverter.convertTo[website] ??
44+
matchingConverter.convertTo.default ??
45+
tag
46+
);
47+
}
48+
2049
export function TagField(props: FormFieldProps<TagFieldType>): JSX.Element {
2150
const { field, form, propKey, option } = props;
2251
const { state: tagGroups } = useStore(TagGroupStore);
2352
const defaultOption = useDefaultOption<TagValue>(props);
2453
const validations = useValidations(props);
25-
54+
const { state: tagConverters } = useStore(TagConverterStore);
55+
const { accounts } = useWebsites();
56+
const account = accounts.find((acc) => acc.id === option.account);
2657
const overrideProps = form.getInputProps(`${propKey}.overrideDefault`);
2758
const tagsProps = form.getInputProps(`${propKey}.tags`);
2859
const tagValue = tagsProps.defaultValue as Tag[];
60+
const allTags = [...tagValue, ...(defaultOption?.tags || [])];
61+
const convertedTags = (
62+
account
63+
? allTags.map((tag) => [
64+
tag,
65+
getTagConversion(account.website, tagConverters, tag),
66+
])
67+
: []
68+
).filter(([tag, converted]) => converted !== tag);
2969

3070
const tagGroupsOptions = tagGroups.map((tagGroup) => ({
3171
label: `${TAG_GROUP_LABEL}${JSON.stringify(tagGroup)}`,
@@ -48,7 +88,7 @@ export function TagField(props: FormFieldProps<TagFieldType>): JSX.Element {
4888

4989
const totalTags: number = overrideProps.defaultValue
5090
? tagValue.length
51-
: [...tagValue, ...(defaultOption?.tags || [])].length;
91+
: allTags.length;
5292

5393
return (
5494
<Box>
@@ -63,6 +103,25 @@ export function TagField(props: FormFieldProps<TagFieldType>): JSX.Element {
63103
}
64104
/>
65105
)}
106+
{convertedTags.length > 0 && (
107+
<Box>
108+
<Text display="inline-block" size="sm" c="green">
109+
<Trans>Converted:</Trans>
110+
</Text>
111+
<Group display="inline-block" ml="4">
112+
{convertedTags.map(([tag, convertedTag]) => (
113+
<Badge size="xs" variant="light">
114+
{tag}{' '}
115+
<IconArrowRight
116+
size="0.75rem"
117+
style={{ verticalAlign: 'middle' }}
118+
/>{' '}
119+
{convertedTag}
120+
</Badge>
121+
))}
122+
</Group>
123+
</Box>
124+
)}
66125
<TagsInput
67126
inputWrapperOrder={['label', 'input', 'description', 'error']}
68127
clearable

apps/postybirb-ui/src/components/submissions/submission-edit-form/submission-file-manager/submission-file-card/file-validations.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { IconAlertCircle, IconAlertTriangle } from '@tabler/icons-react';
88
import { useMemo } from 'react';
99
import { useWebsites } from '../../../../../hooks/account/use-websites';
1010
import { SubmissionDto } from '../../../../../models/dtos/submission.dto';
11-
import { ValidationTranslation } from '../../../../translations/translation';
11+
import { ValidationTranslation } from '../../../../translations/validation-translation';
1212

1313
type FileValidationsProps = {
1414
submission: SubmissionDto;

0 commit comments

Comments
 (0)