B: Improve typechecks and fix backend API data

This commit is contained in:
Ivan 2025-03-02 19:08:28 +03:00
parent 54472ef0b1
commit 32f83c4122
19 changed files with 90 additions and 68 deletions

View File

@ -203,6 +203,7 @@ class OperationSchemaSerializer(serializers.ModelSerializer):
def to_representation(self, instance: LibraryItem):
result = LibraryItemDetailsSerializer(instance).data
del result['versions']
oss = OperationSchema(instance)
result['items'] = []
for operation in oss.operations().order_by('pk'):

View File

@ -13,10 +13,10 @@ from .basics import (
)
from .data_access import (
CstCreateSerializer,
CstInfoSerializer,
CstListSerializer,
CstMoveSerializer,
CstRenameSerializer,
CstSerializer,
CstSubstituteSerializer,
CstTargetSerializer,
CstUpdateSerializer,

View File

@ -30,13 +30,12 @@ class CstBaseSerializer(serializers.ModelSerializer):
read_only_fields = ('id',)
class CstSerializer(serializers.ModelSerializer):
''' Serializer: Constituenta data. '''
class CstInfoSerializer(serializers.ModelSerializer):
''' Serializer: Constituenta public information. '''
class Meta:
''' serializer metadata. '''
model = Constituenta
exclude = ('order',)
read_only_fields = ('id', 'schema', 'alias', 'cst_type', 'definition_resolved', 'term_resolved')
exclude = ('order', 'schema')
class CstUpdateSerializer(serializers.Serializer):
@ -100,7 +99,7 @@ class RSFormSerializer(serializers.ModelSerializer):
child=serializers.IntegerField()
)
items = serializers.ListField(
child=CstSerializer()
child=CstInfoSerializer()
)
inheritance = serializers.ListField(
child=InheritanceDataSerializer()
@ -136,8 +135,7 @@ class RSFormSerializer(serializers.ModelSerializer):
result['oss'] = []
result['inheritance'] = []
for cst in RSForm(instance).constituents().defer('order').order_by('order'):
result['items'].append(CstSerializer(cst).data)
del result['items'][-1]['schema']
result['items'].append(CstInfoSerializer(cst).data)
for oss in LibraryItem.objects.filter(operations__result=instance).only('alias'):
result['oss'].append({
'id': oss.pk,

View File

@ -92,7 +92,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
return Response(
status=c.HTTP_201_CREATED,
data={
'new_cst': s.CstSerializer(new_cst).data,
'new_cst': s.CstInfoSerializer(new_cst).data,
'schema': s.RSFormParseSerializer(schema.model).data
}
)
@ -102,7 +102,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
tags=['RSForm'],
request=s.CstUpdateSerializer,
responses={
c.HTTP_200_OK: s.CstSerializer,
c.HTTP_200_OK: s.CstInfoSerializer,
c.HTTP_400_BAD_REQUEST: None,
c.HTTP_403_FORBIDDEN: None,
c.HTTP_404_NOT_FOUND: None
@ -122,7 +122,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
PropagationFacade.after_update_cst(schema, cst, data, old_data)
return Response(
status=c.HTTP_200_OK,
data=s.CstSerializer(m.Constituenta.objects.get(pk=request.data['target'])).data
data=s.CstInfoSerializer(m.Constituenta.objects.get(pk=request.data['target'])).data
)
@extend_schema(
@ -202,7 +202,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
return Response(
status=c.HTTP_200_OK,
data={
'new_cst': s.CstSerializer(cst).data,
'new_cst': s.CstInfoSerializer(cst).data,
'schema': s.RSFormParseSerializer(schema.model).data
}
)

View File

@ -117,6 +117,20 @@ class UserSerializer(serializers.ModelSerializer):
return attrs
class UserInfoSerializer(serializers.ModelSerializer):
''' Serializer: User open information. '''
id = serializers.IntegerField(read_only=True)
class Meta:
''' serializer metadata. '''
model = models.User
fields = [
'id',
'first_name',
'last_name',
]
class ChangePasswordSerializer(serializers.Serializer):
''' Serializer: Change password. '''
old_password = serializers.CharField(required=True)

View File

@ -73,7 +73,7 @@ class AuthAPIView(generics.RetrieveAPIView):
class ActiveUsersView(generics.ListAPIView):
''' Endpoint: Get list of active users. '''
permission_classes = (permissions.AllowAny,)
serializer_class = s.UserSerializer
serializer_class = s.UserInfoSerializer
def get_queryset(self):
return m.User.objects.filter(is_active=True)

View File

@ -20,7 +20,8 @@ export default [
ecmaVersion: 'latest',
sourceType: 'module',
globals: { ...globals.browser, ...globals.es2020, ...globals.jest },
project: ['./tsconfig.json', './tsconfig.node.json']
project: ['./tsconfig.json', './tsconfig.node.json'],
projectService: true
}
}
},

View File

@ -15,7 +15,7 @@ export interface ICurrentUser {
/**
* Represents login data, used to authenticate users.
*/
export const schemaUserLogin = z.object({
export const schemaUserLogin = z.strictObject({
username: z.string().nonempty(errorMsg.requiredField),
password: z.string().nonempty(errorMsg.requiredField)
});

View File

@ -51,7 +51,7 @@ export type IVersionUpdateDTO = z.infer<typeof schemaVersionUpdate>;
// ======= SCHEMAS =========
export const schemaLibraryItem = z.object({
export const schemaLibraryItem = z.strictObject({
id: z.coerce.number(),
item_type: z.nativeEnum(LibraryItemType),
title: z.string(),
@ -112,7 +112,7 @@ export const schemaCreateLibraryItem = z
message: errorMsg.requiredField
});
export const schemaUpdateLibraryItem = z.object({
export const schemaUpdateLibraryItem = z.strictObject({
id: z.number(),
item_type: z.nativeEnum(LibraryItemType),
title: z.string().nonempty(errorMsg.requiredField),
@ -122,20 +122,20 @@ export const schemaUpdateLibraryItem = z.object({
read_only: z.boolean()
});
export const schemaVersionInfo = z.object({
export const schemaVersionInfo = z.strictObject({
id: z.coerce.number(),
version: z.string(),
description: z.string(),
time_create: z.string().datetime({ offset: true })
});
export const schemaVersionUpdate = z.object({
export const schemaVersionUpdate = z.strictObject({
id: z.number(),
version: z.string().nonempty(errorMsg.requiredField),
description: z.string()
});
export const schemaVersionCreate = z.object({
export const schemaVersionCreate = z.strictObject({
version: z.string(),
description: z.string(),
items: z.array(z.number())

View File

@ -18,7 +18,7 @@ import { SelectLocationHead } from '../components/SelectLocationHead';
import { LocationHead } from '../models/library';
import { combineLocation, validateLocation } from '../models/libraryAPI';
const schemaLocation = z.object({
const schemaLocation = z.strictObject({
location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation })
});

View File

@ -58,7 +58,7 @@ export type IConstituentaReference = z.infer<typeof schemaConstituentaReference>
// ====== Schemas ======
export const schemaOperation = z.object({
export const schemaOperation = z.strictObject({
id: z.number(),
operation_type: z.nativeEnum(OperationType),
oss: z.number(),
@ -93,15 +93,15 @@ export const schemaOperationSchema = schemaLibraryItem.extend({
substitutions: z.array(schemaCstSubstituteInfo)
});
export const schemaOperationPosition = z.object({
export const schemaOperationPosition = z.strictObject({
id: z.number(),
position_x: z.number(),
position_y: z.number()
});
export const schemaOperationCreate = z.object({
export const schemaOperationCreate = z.strictObject({
positions: z.array(schemaOperationPosition),
item_data: z.object({
item_data: z.strictObject({
alias: z.string().nonempty(),
operation_type: z.nativeEnum(OperationType),
title: z.string(),
@ -114,33 +114,33 @@ export const schemaOperationCreate = z.object({
create_schema: z.boolean()
});
export const schemaOperationCreatedResponse = z.object({
export const schemaOperationCreatedResponse = z.strictObject({
new_operation: schemaOperation,
oss: schemaOperationSchema
});
export const schemaOperationDelete = z.object({
export const schemaOperationDelete = z.strictObject({
target: z.number(),
positions: z.array(schemaOperationPosition),
keep_constituents: z.boolean(),
delete_schema: z.boolean()
});
export const schemaInputUpdate = z.object({
export const schemaInputUpdate = z.strictObject({
target: z.number(),
positions: z.array(schemaOperationPosition),
input: z.number().nullable()
});
export const schemaInputCreatedResponse = z.object({
export const schemaInputCreatedResponse = z.strictObject({
new_schema: schemaLibraryItem,
oss: schemaOperationSchema
});
export const schemaOperationUpdate = z.object({
export const schemaOperationUpdate = z.strictObject({
target: z.number(),
positions: z.array(schemaOperationPosition),
item_data: z.object({
item_data: z.strictObject({
alias: z.string().nonempty(errorMsg.requiredField),
title: z.string(),
comment: z.string()
@ -149,12 +149,12 @@ export const schemaOperationUpdate = z.object({
substitutions: z.array(schemaCstSubstitute)
});
export const schemaCstRelocate = z.object({
export const schemaCstRelocate = z.strictObject({
destination: z.number().nullable(),
items: z.array(z.number()).refine(data => data.length > 0)
});
export const schemaConstituentaReference = z.object({
export const schemaConstituentaReference = z.strictObject({
id: z.number(),
schema: z.number()
});

View File

@ -19,7 +19,7 @@ import { OperationTooltip } from '../../components/OperationTooltip';
import { OssEditState, OssTabID } from './OssEditContext';
import { OssTabs } from './OssTabs';
const paramsSchema = z.object({
const paramsSchema = z.strictObject({
id: z.coerce.number(),
tab: z.preprocess(v => (v ? Number(v) : undefined), z.nativeEnum(OssTabID).default(OssTabID.GRAPH))
});

View File

@ -11,15 +11,15 @@ export type ILexemeResponse = z.infer<typeof schemaLexemeResponse>;
// ====== Schemas =========
export const schemaTextResult = z.object({
export const schemaTextResult = z.strictObject({
result: z.string()
});
export const schemaWordForm = z.object({
export const schemaWordForm = z.strictObject({
text: z.string(),
grams: z.string()
});
export const schemaLexemeResponse = z.object({
export const schemaLexemeResponse = z.strictObject({
items: z.array(schemaWordForm)
});

View File

@ -266,7 +266,7 @@ export enum RSErrorType {
}
// ========= SCHEMAS ========
export const schemaConstituentaBasics = z.object({
export const schemaConstituentaBasics = z.strictObject({
id: z.coerce.number(),
alias: z.string().nonempty(errorMsg.requiredField),
convention: z.string(),
@ -276,16 +276,16 @@ export const schemaConstituentaBasics = z.object({
definition_resolved: z.string(),
term_raw: z.string(),
term_resolved: z.string(),
term_forms: z.array(z.object({ text: z.string(), tags: z.string() }))
term_forms: z.array(z.strictObject({ text: z.string(), tags: z.string() }))
});
export const schemaConstituenta = schemaConstituentaBasics.extend({
parse: z.object({
parse: z.strictObject({
status: z.nativeEnum(ParsingStatus),
valueClass: z.nativeEnum(ValueClass),
typification: z.string(),
syntaxTree: z.string(),
args: z.array(z.object({ alias: z.string(), typification: z.string() }))
args: z.array(z.strictObject({ alias: z.string(), typification: z.string() }))
})
});
@ -297,17 +297,17 @@ export const schemaRSForm = schemaLibraryItem.extend({
items: z.array(schemaConstituenta),
inheritance: z.array(
z.object({
z.strictObject({
child: z.coerce.number(),
child_source: z.coerce.number(),
parent: z.coerce.number(),
parent_source: z.coerce.number()
})
),
oss: z.array(z.object({ id: z.coerce.number(), alias: z.string() }))
oss: z.array(z.strictObject({ id: z.coerce.number(), alias: z.string() }))
});
export const schemaVersionCreatedResponse = z.object({
export const schemaVersionCreatedResponse = z.strictObject({
version: z.number(),
schema: schemaRSForm
});
@ -326,57 +326,57 @@ export const schemaCstCreate = schemaConstituentaBasics
insert_after: z.number().nullable()
});
export const schemaCstCreatedResponse = z.object({
export const schemaCstCreatedResponse = z.strictObject({
new_cst: schemaConstituentaBasics,
schema: schemaRSForm
});
export const schemaCstUpdate = z.object({
export const schemaCstUpdate = z.strictObject({
target: z.number(),
item_data: z.object({
item_data: z.strictObject({
convention: z.string().optional(),
definition_formal: z.string().optional(),
definition_raw: z.string().optional(),
term_raw: z.string().optional(),
term_forms: z.array(z.object({ text: z.string(), tags: z.string() })).optional()
term_forms: z.array(z.strictObject({ text: z.string(), tags: z.string() })).optional()
})
});
export const schemaCstRename = z.object({
export const schemaCstRename = z.strictObject({
target: z.number(),
alias: z.string(),
cst_type: z.nativeEnum(CstType)
});
export const schemaProduceStructureResponse = z.object({
export const schemaProduceStructureResponse = z.strictObject({
cst_list: z.array(z.number()),
schema: schemaRSForm
});
export const schemaCstSubstitute = z.object({
export const schemaCstSubstitute = z.strictObject({
original: z.number(),
substitution: z.number()
});
export const schemaCstSubstitutions = z.object({
export const schemaCstSubstitutions = z.strictObject({
substitutions: z.array(schemaCstSubstitute).min(1, { message: errorMsg.emptySubstitutions })
});
export const schemaInlineSynthesis = z.object({
export const schemaInlineSynthesis = z.strictObject({
receiver: z.number(),
source: z.number().nullable(),
items: z.array(z.number()),
substitutions: z.array(schemaCstSubstitute)
});
export const schemaRSErrorDescription = z.object({
export const schemaRSErrorDescription = z.strictObject({
errorType: z.nativeEnum(RSErrorType),
position: z.number(),
isCritical: z.boolean(),
params: z.array(z.string())
});
export const schemaExpressionParse = z.object({
export const schemaExpressionParse = z.strictObject({
parseResult: z.boolean(),
prefixLen: z.number(),
syntax: z.nativeEnum(Syntax),
@ -385,17 +385,17 @@ export const schemaExpressionParse = z.object({
errors: z.array(schemaRSErrorDescription),
astText: z.string(),
ast: z.array(
z.object({
z.strictObject({
uid: z.number(),
parent: z.number(),
typeID: z.nativeEnum(TokenID),
start: z.number(),
finish: z.number(),
data: z.object({ dataType: z.string(), value: z.unknown().refine(value => value !== undefined) })
data: z.strictObject({ dataType: z.string(), value: z.unknown().refine(value => value !== undefined) })
})
),
args: z.array(
z.object({
z.strictObject({
alias: z.string(),
typification: z.string()
})

View File

@ -36,8 +36,11 @@ export interface IReferenceInputState {
const schemaEditReferenceState = z
.object({
type: z.nativeEnum(ReferenceType),
entity: z.object({ entity: z.string(), grams: z.array(z.object({ value: z.string(), label: z.string() })) }),
syntactic: z.object({ offset: z.coerce.number(), nominal: z.string() })
entity: z.strictObject({
entity: z.string(),
grams: z.array(z.strictObject({ value: z.string(), label: z.string() }))
}),
syntactic: z.strictObject({ offset: z.coerce.number(), nominal: z.string() })
})
.refine(
data =>

View File

@ -268,11 +268,11 @@ export interface ITextPosition {
finish: number;
}
export const schemaReference = z.object({
export const schemaReference = z.strictObject({
type: z.nativeEnum(ReferenceType),
data: z.union([
z.object({ entity: z.string(), form: z.string() }),
z.object({ offset: z.number(), nominal: z.string() })
z.strictObject({ entity: z.string(), form: z.string() }),
z.strictObject({ offset: z.number(), nominal: z.string() })
])
});

View File

@ -19,7 +19,7 @@ import { ConstituentaTooltip } from '../../components/ConstituentaTooltip';
import { RSEditState, RSTabID } from './RSEditContext';
import { RSTabs } from './RSTabs';
const paramsSchema = z.object({
const paramsSchema = z.strictObject({
id: z.coerce.number(),
version: z.coerce
.number()

View File

@ -22,7 +22,7 @@ export type IUserSignupDTO = z.infer<typeof schemaUserSignup>;
export type IUpdateProfileDTO = z.infer<typeof schemaUpdateProfile>;
// ========= SCHEMAS ========
export const schemaUser = z.object({
export const schemaUser = z.strictObject({
id: z.coerce.number(),
username: z.string().nonempty(errorMsg.requiredField),
is_staff: z.boolean(),
@ -47,7 +47,7 @@ export const schemaUserSignup = z
})
.refine(schema => schema.password === schema.password2, { path: ['password2'], message: errorMsg.passwordsMismatch });
export const schemaUpdateProfile = z.object({
export const schemaUpdateProfile = z.strictObject({
email: z.string().email(errorMsg.emailField),
first_name: z.string(),
last_name: z.string()

View File

@ -4,7 +4,12 @@
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "package.json", "playwright.config.ts", "tests"]
"allowSyntheticDefaultImports": true,
"baseUrl": "./src/",
"paths": {
"@/*": ["*"]
}
},
"include": ["vite.config.ts", "package.json", "playwright.config.ts", "tests", "src"]
}