diff --git a/__fixtures__/uuid/taxonomy-term.ts b/__fixtures__/uuid/taxonomy-term.ts index 2a313d76f..fbef0e442 100644 --- a/__fixtures__/uuid/taxonomy-term.ts +++ b/__fixtures__/uuid/taxonomy-term.ts @@ -13,7 +13,6 @@ export const taxonomyTermRoot: Model<'TaxonomyTerm'> = { description: null, weight: 1, parentId: null, - taxonomyId: 1, childrenIds: [5], } @@ -28,7 +27,6 @@ export const taxonomyTermSubject: Model<'TaxonomyTerm'> = { description: null, weight: 2, parentId: taxonomyTermRoot.id, - taxonomyId: 3, childrenIds: [16048], } @@ -42,7 +40,6 @@ export const taxonomyTermCurriculumTopic: Model<'TaxonomyTerm'> = { name: 'name', description: 'description', weight: 3, - taxonomyId: 11, parentId: taxonomyTermSubject.id, childrenIds: [1855], } @@ -57,7 +54,6 @@ export const taxonomyTermTopic: Model<'TaxonomyTerm'> = { name: 'Geometrie', description: null, weight: 6, - taxonomyId: 4, parentId: 5, childrenIds: [ 23453, 1454, 1394, 24518, 1380, 24410, 24422, 1381, 1383, 1300, 1413, @@ -74,7 +70,6 @@ export const taxonomyTermTopicFolder: Model<'TaxonomyTerm'> = { name: 'Aufgaben zu einfachen Potenzen', description: '', weight: 1, - taxonomyId: 9, parentId: 1288, childrenIds: [10385, 6925, 6921, 6933, 6917, 7085], } diff --git a/__tests__/__utils__/assertions.ts b/__tests__/__utils__/assertions.ts index 7f0b09f26..ea1908501 100644 --- a/__tests__/__utils__/assertions.ts +++ b/__tests__/__utils__/assertions.ts @@ -236,11 +236,16 @@ export async function assertErrorEvent(args?: { if (args?.errorContext !== undefined) { for (const contextName in args.errorContext) { - const contextValue = event.contexts?.error?.[contextName] + const contextValueString = event.contexts?.error?.[contextName] + const contextValue = destringifyProperties(contextValueString) const targetValue = args.errorContext[contextName] - if (!R.equals(destringifyProperties(contextValue), targetValue)) - return false + if (typeof targetValue === 'object' && targetValue !== null) { + if (!R.equals(R.pick(R.keys(targetValue), contextValue), targetValue)) + return false + } else { + if (contextValue !== targetValue) return false + } } } diff --git a/__tests__/__utils__/query.ts b/__tests__/__utils__/query.ts index 419c2b9fb..1b97ac6a4 100644 --- a/__tests__/__utils__/query.ts +++ b/__tests__/__utils__/query.ts @@ -102,7 +102,6 @@ export const taxonomyTermQuery = new Client().prepareQuery({ name description weight - taxonomyId path { id } diff --git a/__tests__/schema/entity/set-abstract-entity.ts b/__tests__/schema/entity/set-abstract-entity.ts index 8085a1046..ab2ccbc06 100644 --- a/__tests__/schema/entity/set-abstract-entity.ts +++ b/__tests__/schema/entity/set-abstract-entity.ts @@ -47,7 +47,7 @@ beforeEach(async () => { // create taxonomy Term 106082 await databaseForTests.mutate('update uuid set id = 106082 where id = 35607') await databaseForTests.mutate( - 'update term_taxonomy set id = 106082 where id = 35607', + 'update taxonomy set id = 106082 where id = 35607', ) }) diff --git a/__tests__/schema/event-types.ts b/__tests__/schema/event-types.ts index f36a70065..01f2d8573 100644 --- a/__tests__/schema/event-types.ts +++ b/__tests__/schema/event-types.ts @@ -81,7 +81,7 @@ test('adds a notification', async () => { expect( await databaseForTests.fetchAll( - 'select * from notification_event where event_log_id = ?', + 'select * from notification_event where event_id = ?', [lastEvent.id], ), ).not.toHaveLength(0) @@ -100,19 +100,6 @@ test('fails if object does not exist', async () => { ).rejects.toThrow() }) -test('fails if name from parameters is invalid', async () => { - const initialEventsNumber = await getEventsNumber() - - await global.databaseForTests.mutate( - 'delete from event_parameter_name where name = "discussion"', - ) - - await expect(createEvent(basePayload, getContext())).rejects.toThrow() - - const finalEventsNumber = await getEventsNumber() - expect(finalEventsNumber).toEqual(initialEventsNumber) -}) - test('fails if uuid number in parameters does not exist', async () => { await expect( createEvent({ ...basePayload, threadId: 40000 }, getContext()), @@ -309,7 +296,7 @@ function getApiResult(event: Record): Record { async function getEventsNumber() { return ( await global.databaseForTests.fetchOne<{ n: number }>( - 'SELECT count(*) AS n FROM event_log', + 'SELECT count(*) AS n FROM event', ) ).n } diff --git a/__tests__/schema/events.ts b/__tests__/schema/events.ts index c4714faa5..ddf915a99 100644 --- a/__tests__/schema/events.ts +++ b/__tests__/schema/events.ts @@ -92,7 +92,7 @@ describe('query endpoint "events"', () => { test('with filter "objectId"', async () => { await query.withVariables({ first: 1, objectId: 1855 }).shouldReturnData({ events: { - nodes: [{ __typename: 'CreateEntityNotificationEvent', id: 1198 }], + nodes: [{ __typename: 'CheckoutRevisionNotificationEvent', id: 77030 }], }, }) }) diff --git a/__tests__/schema/taxonomy-term/create.ts b/__tests__/schema/taxonomy-term/create.ts index 418aba57a..f4a609daf 100644 --- a/__tests__/schema/taxonomy-term/create.ts +++ b/__tests__/schema/taxonomy-term/create.ts @@ -64,20 +64,6 @@ describe('creates a new taxonomy term', () => { }) }) -test('does not fail when there are duplicated taxonomy entries', async () => { - // In the database layer there was a bug to created multiple duplicated - // taxonomy entries (which is currently not in the DB container) - // This test can be deleted after https://github.com/serlo/db-migrations/issues/346 - - await databaseForTests.mutate( - `insert into taxonomy (type_id, instance_id) values (11, 1)`, - ) - - await mutation.shouldReturnData({ - taxonomyTerm: { create: { success: true } }, - }) -}) - test('cache of parent is updated', async () => { const query = new Client().prepareQuery({ query: gql` diff --git a/__tests__/schema/user/delete-bots.ts b/__tests__/schema/user/delete-bots.ts index 539c478be..162f11cd6 100644 --- a/__tests__/schema/user/delete-bots.ts +++ b/__tests__/schema/user/delete-bots.ts @@ -2,14 +2,14 @@ import { createHash } from 'crypto' import gql from 'graphql-tag' import { HttpResponse, ResponseResolver, http } from 'msw' -import { article, user, user2 } from '../../../__fixtures__' +import { article, user } from '../../../__fixtures__' import { - given, Client, Query, - returnsJson, assertErrorEvent, assertNoErrorEvents, + given, + returnsJson, userQuery, } from '../../__utils__' @@ -137,11 +137,13 @@ describe('community chat', () => { returnsJson({ json: { success: false, errorType: 'unknown' } }), ) - await mutation.withInput({ botIds: [user2.id] }).execute() + await mutation + .withInput({ botIds: input.botIds.slice(1) }) + .shouldReturnData({ user: { deleteBots: { success: true } } }) await assertErrorEvent({ message: 'Cannot delete a user from community.serlo.org', - errorContext: { user: user2 }, + errorContext: { user: { id: input.botIds[1] } }, }) }) }) diff --git a/__tests__/schema/uuid/entity-revision.ts b/__tests__/schema/uuid/entity-revision.ts index 24d2ffa50..d2eb2173d 100644 --- a/__tests__/schema/uuid/entity-revision.ts +++ b/__tests__/schema/uuid/entity-revision.ts @@ -12,7 +12,7 @@ test('Uuid query for an entity revision', async () => { repository: { id: 35295 }, title: '"falsche Freunde"', content: - '{"plugin":"rows","state":[{"plugin":"text","state":[{"type":"p","children":[{"text":"wip"}]}],"id":"8abdb955-fa42-442d-87a8-91bfae603101"}],"id":"e5dd1162-7e55-4b1c-aacd-acb267c290ee"}', + '{"plugin":"rows","state":[{"plugin":"text","state":[{"type":"p","children":[{"text":"wip"}]}],"id":"7165fed8-d729-45fd-a28c-8ea7c2622953"}],"id":"3b4326f6-88c6-4da8-9bea-f0eb4aa5407a"}', changes: '', metaTitle: '', metaDescription: '', diff --git a/__tests__/schema/uuid/taxonomy-term.ts b/__tests__/schema/uuid/taxonomy-term.ts index 5c9e680fc..aa87997c3 100644 --- a/__tests__/schema/uuid/taxonomy-term.ts +++ b/__tests__/schema/uuid/taxonomy-term.ts @@ -13,7 +13,6 @@ test('TaxonomyTerm root', async () => { name: 'Root', description: null, weight: 0, - taxonomyId: 1, path: [], parent: null, children: { @@ -55,7 +54,6 @@ test('TaxonomyTerm subject', async () => { name: 'Chemie', description: '', weight: 17, - taxonomyId: 3, path: [], parent: { id: 3 }, children: { @@ -87,7 +85,6 @@ test('TaxonomyTerm exerciseFolder', async () => { name: 'Example topic folder', description: '', weight: 1, - taxonomyId: 19, path: [{ id: 23590 }, { id: 23593 }, { id: 35559 }, { id: 35560 }], parent: { id: 35560, diff --git a/docker-compose.yml b/docker-compose.yml index f37ba2e8b..1d9d8716e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: ports: - '6379:6379' mysql: - image: eu.gcr.io/serlo-shared/serlo-mysql-database:prerelease-merge-course-pages-into-courses.2 + image: eu.gcr.io/serlo-shared/serlo-mysql-database:prerelease-entityfield-coursepage-event-taxonomy platform: linux/x86_64 pull_policy: always ports: diff --git a/packages/server/src/model/decoder.ts b/packages/server/src/model/decoder.ts index f953e837f..fad9b596f 100644 --- a/packages/server/src/model/decoder.ts +++ b/packages/server/src/model/decoder.ts @@ -187,7 +187,6 @@ export const TaxonomyTermDecoder = t.exact( weight: t.number, childrenIds: t.array(t.number), parentId: t.union([t.number, t.null]), - taxonomyId: t.number, }), t.partial({ description: t.union([t.string, t.null]), diff --git a/packages/server/src/schema/events/event.ts b/packages/server/src/schema/events/event.ts index b98a62a6b..3ed0d3621 100644 --- a/packages/server/src/schema/events/event.ts +++ b/packages/server/src/schema/events/event.ts @@ -39,47 +39,30 @@ export async function createEvent( try { const { insertId: eventId } = await database.mutate( ` - INSERT INTO event_log (actor_id, event_id, uuid_id, instance_id) - SELECT ?, event.id, ?, instance.id - FROM event, instance - WHERE event.name = ? and instance.subdomain = ? + INSERT INTO event + (actor_id, event_type_id, uuid_id, instance_id, + uuid_parameter, uuid_parameter2, string_parameter) + SELECT ?, event_type.id, ?, instance.id, ?, ?, ? + FROM event_type, instance + WHERE event_type.name = ? and instance.subdomain = ? `, - [actorId, objectId, type, instance], + [ + actorId, + objectId, + 'uuidParameter' in abstractEventPayload + ? abstractEventPayload.uuidParameter + : null, + 'uuidParameter2' in abstractEventPayload + ? abstractEventPayload.uuidParameter2 + : null, + 'stringParameter' in abstractEventPayload + ? abstractEventPayload.stringParameter + : null, + type, + instance, + ], ) - const { stringParameters, uuidParameters } = abstractEventPayload - const parameters = { ...stringParameters, ...uuidParameters } - - for (const [parameter, value] of Object.entries(parameters)) { - const { insertId: parameterId } = await database.mutate( - ` - INSERT INTO event_parameter (log_id, name_id) - SELECT ?, id - FROM event_parameter_name - WHERE name = ? - `, - [eventId, parameter], - ) - - if (typeof value === 'string') { - await database.mutate( - ` - INSERT INTO event_parameter_string (value, event_parameter_id) - VALUES (?, ?) - `, - [value, parameterId], - ) - } else { - await database.mutate( - ` - INSERT INTO event_parameter_uuid (uuid_id, event_parameter_id) - VALUES (?, ?) - `, - [value, parameterId], - ) - } - } - const event = { ...abstractEventPayload, id: eventId } await createNotifications(event, { database }) @@ -96,7 +79,11 @@ async function createNotifications( ) { const { objectId, actorId } = event - const objectIds = [objectId, ...Object.values(event.uuidParameters)] + const objectIds = [ + objectId, + ...('uuidParameter' in event ? [event.uuidParameter] : []), + ...('uuidParameter2' in event ? [event.uuidParameter2] : []), + ] const subscribers = [] for (const objectId of objectIds) { @@ -131,7 +118,7 @@ async function createNotifications( await database.mutate( ` - INSERT INTO notification_event (notification_id, event_log_id) + INSERT INTO notification_event (notification_id, event_id) SELECT LAST_INSERT_ID(), ? `, [event.id], @@ -161,14 +148,14 @@ export function toGraphQLModel( return { ...base, __typename: NotificationEventType.CreateComment, - threadId: event.uuidParameters.discussion, + threadId: event.uuidParameter, commentId: event.objectId, } } else if (event.type === EventType.CreateThread) { return { ...base, __typename: NotificationEventType.CreateThread, - objectId: event.uuidParameters.on, + objectId: event.uuidParameter, threadId: event.objectId, } } else if (event.type === EventType.CreateEntity) { @@ -194,13 +181,13 @@ export function toGraphQLModel( ? NotificationEventType.CreateEntityLink : NotificationEventType.RemoveEntityLink, childId: event.objectId, - parentId: event.uuidParameters.parent, + parentId: event.uuidParameter, } } else if (event.type === EventType.CreateEntityRevision) { return { ...base, __typename: NotificationEventType.CreateEntityRevision, - entityId: event.uuidParameters.repository, + entityId: event.uuidParameter, entityRevisionId: event.objectId, } } else if ( @@ -213,9 +200,9 @@ export function toGraphQLModel( event.type === EventType.CheckoutRevision ? NotificationEventType.CheckoutRevision : NotificationEventType.RejectRevision, - repositoryId: event.uuidParameters.repository, + repositoryId: event.uuidParameter, revisionId: event.objectId, - reason: event.stringParameters.reason, + reason: event.stringParameter, } } else if ( event.type === EventType.CreateTaxonomyLink || @@ -228,7 +215,7 @@ export function toGraphQLModel( ? NotificationEventType.CreateTaxonomyLink : NotificationEventType.RemoveTaxonomyLink, parentId: event.objectId, - childId: event.uuidParameters.object, + childId: event.uuidParameter, } } else if ( event.type === EventType.CreateTaxonomyTerm || @@ -247,8 +234,8 @@ export function toGraphQLModel( ...base, __typename: NotificationEventType.SetTaxonomyParent, childId: event.objectId, - previousParentId: event.uuidParameters.from, - parentId: event.uuidParameters.to, + previousParentId: event.uuidParameter, + parentId: event.uuidParameter2, } } else { return { @@ -262,11 +249,7 @@ export function toGraphQLModel( function toDatabaseRepresentation( event: PayloadForNewEvent, ): PayloadForNewAbstractEvent { - const base = { - ...R.pick(['actorId', 'instance'], event), - uuidParameters: {}, - stringParameters: {}, - } + const base = R.pick(['actorId', 'instance'], event) if (event.__typename === NotificationEventType.SetThreadState) { return { @@ -279,14 +262,14 @@ function toDatabaseRepresentation( ...base, type: EventType.CreateComment, objectId: event.commentId, - uuidParameters: { discussion: event.threadId }, + uuidParameter: event.threadId, } } else if (event.__typename === NotificationEventType.CreateThread) { return { ...base, type: EventType.CreateThread, objectId: event.threadId, - uuidParameters: { on: event.objectId }, + uuidParameter: event.objectId, } } else if (event.__typename === NotificationEventType.CreateEntity) { return { ...base, type: EventType.CreateEntity, objectId: event.entityId } @@ -307,14 +290,14 @@ function toDatabaseRepresentation( ? EventType.CreateEntityLink : EventType.RemoveEntityLink, objectId: event.childId, - uuidParameters: { parent: event.parentId }, + uuidParameter: event.parentId, } } else if (event.__typename === NotificationEventType.CreateEntityRevision) { return { ...base, type: EventType.CreateEntityRevision, objectId: event.entityRevisionId, - uuidParameters: { repository: event.entityId }, + uuidParameter: event.entityId, } } else if ( event.__typename === NotificationEventType.CheckoutRevision || @@ -327,8 +310,8 @@ function toDatabaseRepresentation( ? EventType.CheckoutRevision : EventType.RejectRevision, objectId: event.revisionId, - uuidParameters: { repository: event.repositoryId }, - stringParameters: { reason: event.reason }, + uuidParameter: event.repositoryId, + stringParameter: event.reason, } } else if ( event.__typename === NotificationEventType.CreateTaxonomyLink || @@ -341,7 +324,7 @@ function toDatabaseRepresentation( ? EventType.CreateTaxonomyLink : EventType.RemoveTaxonomyLink, objectId: event.parentId, - uuidParameters: { object: event.childId }, + uuidParameter: event.childId, } } else if ( event.__typename === NotificationEventType.CreateTaxonomyTerm || @@ -360,7 +343,8 @@ function toDatabaseRepresentation( ...base, type: EventType.SetTaxonomyParent, objectId: event.childId, - uuidParameters: { from: event.previousParentId, to: event.parentId }, + uuidParameter: event.previousParentId, + uuidParameter2: event.parentId, } } else { return { @@ -438,96 +422,78 @@ type PayloadForNewEvent = const DatabaseEventRepresentations = { ArchiveThread: getDatabaseRepresentationDecoder({ type: EventType.ArchiveThread, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), RestoreThread: getDatabaseRepresentationDecoder({ type: EventType.RestoreThread, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), CreateComment: getDatabaseRepresentationDecoder({ type: EventType.CreateComment, - uuidParameters: t.type({ discussion: t.number }), - stringParameters: t.type({}), + parameters: t.type({ uuidParameter: t.number }), }), CreateThread: getDatabaseRepresentationDecoder({ type: EventType.CreateThread, - uuidParameters: t.type({ on: t.number }), - stringParameters: t.type({}), + parameters: t.type({ uuidParameter: t.number }), }), CreateEntity: getDatabaseRepresentationDecoder({ type: EventType.CreateEntity, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), SetLicense: getDatabaseRepresentationDecoder({ type: EventType.SetLicense, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), CreateEntityLink: getDatabaseRepresentationDecoder({ type: EventType.CreateEntityLink, - uuidParameters: t.type({ parent: t.number }), - stringParameters: t.type({}), + parameters: t.type({ uuidParameter: t.number }), }), RemoveEntityLink: getDatabaseRepresentationDecoder({ type: EventType.RemoveEntityLink, - uuidParameters: t.type({ parent: t.number }), - stringParameters: t.type({}), + parameters: t.type({ uuidParameter: t.number }), }), CreateEntityRevision: getDatabaseRepresentationDecoder({ type: EventType.CreateEntityRevision, - uuidParameters: t.type({ repository: t.number }), - stringParameters: t.type({}), + parameters: t.type({ uuidParameter: t.number }), }), CheckoutRevision: getDatabaseRepresentationDecoder({ type: EventType.CheckoutRevision, - uuidParameters: t.type({ repository: t.number }), - stringParameters: t.type({ reason: t.string }), + parameters: t.type({ uuidParameter: t.number, stringParameter: t.string }), }), RejectRevision: getDatabaseRepresentationDecoder({ type: EventType.RejectRevision, - uuidParameters: t.type({ repository: t.number }), - stringParameters: t.type({ reason: t.string }), + parameters: t.type({ uuidParameter: t.number, stringParameter: t.string }), }), CreateTaxonomyLink: getDatabaseRepresentationDecoder({ type: EventType.CreateTaxonomyLink, - uuidParameters: t.type({ object: t.number }), - stringParameters: t.type({}), + parameters: t.type({ uuidParameter: t.number }), }), RemoveTaxonomyLink: getDatabaseRepresentationDecoder({ type: EventType.RemoveTaxonomyLink, - uuidParameters: t.type({ object: t.number }), - stringParameters: t.type({}), + parameters: t.type({ uuidParameter: t.number }), }), CreateTaxonomyTerm: getDatabaseRepresentationDecoder({ type: EventType.CreateTaxonomyTerm, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), SetTaxonomyTerm: getDatabaseRepresentationDecoder({ type: EventType.SetTaxonomyTerm, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), SetTaxonomyParent: getDatabaseRepresentationDecoder({ type: EventType.SetTaxonomyParent, - uuidParameters: t.type({ - from: t.union([t.number, t.null]), - to: t.union([t.number, t.null]), + parameters: t.type({ + uuidParameter: t.union([t.number, t.null]), + uuidParameter2: t.union([t.number, t.null]), }), - stringParameters: t.type({}), }), TrashUuid: getDatabaseRepresentationDecoder({ type: EventType.TrashUuid, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), RestoreUuid: getDatabaseRepresentationDecoder({ type: EventType.RestoreUuid, - uuidParameters: t.type({}), - stringParameters: t.type({}), + parameters: t.type({}), }), } as const @@ -555,25 +521,21 @@ export const DatabaseEventRepresentation: t.Type = function getDatabaseRepresentationDecoder< Type extends EventType, - UuidParameters extends Record, - StringParameters extends Record, ->({ - type, - uuidParameters, - stringParameters, -}: { - type: Type - uuidParameters: t.Type - stringParameters: t.Type -}) { - return t.type({ - id: t.number, - type: t.literal(type), - actorId: t.number, - date: DateDecoder, - objectId: t.number, - instance: InstanceDecoder, - uuidParameters: uuidParameters, - stringParameters: stringParameters, - }) + Parameters extends { + uuidParameter?: number | null + uuidParameter2?: number | null + stringParameter?: string + }, +>({ type, parameters }: { type: Type; parameters: t.Type }) { + return t.intersection([ + t.type({ + id: t.number, + type: t.literal(type), + actorId: t.number, + date: DateDecoder, + objectId: t.number, + instance: InstanceDecoder, + }), + parameters, + ]) } diff --git a/packages/server/src/schema/events/resolvers.ts b/packages/server/src/schema/events/resolvers.ts index f06badfa7..9921487be 100644 --- a/packages/server/src/schema/events/resolvers.ts +++ b/packages/server/src/schema/events/resolvers.ts @@ -58,33 +58,25 @@ async function resolveEventsFromDB( const rows = await database.fetchAll( ` select - event_log.id as id, - event.name as type, - event_log.actor_id as actorId, + event.id as id, + event_type.name as type, + event.actor_id as actorId, instance.subdomain as instance, - event_log.date as date, - event_log.uuid_id as objectId, - JSON_OBJECTAGG( - COALESCE(event_parameter_name.name, "__unused"), - event_parameter_uuid.uuid_id - ) as uuidParameters, - JSON_OBJECTAGG( - COALESCE(event_parameter_name.name, "__unused"), - event_parameter_string.value - ) as stringParameters - from event_log - join event on event.id = event_log.event_id - join instance on event_log.instance_id = instance.id - left join event_parameter on event_parameter.log_id = event_log.id - left join event_parameter_name on event_parameter.name_id = event_parameter_name.id - left join event_parameter_string on event_parameter_string.event_parameter_id = event_parameter.id - left join event_parameter_uuid on event_parameter_uuid.event_parameter_id = event_parameter.id + event.date as date, + event.uuid_id as objectId, + event.uuid_parameter as uuidParameter, + event.uuid_parameter2 as uuidParameter2, + event.string_parameter as stringParameter + from event + join event_type on event_type.id = event.event_type_id + join instance on event.instance_id = instance.id where - event_log.id < ? - and (? is null or event_log.uuid_id = ?) - and (? is null or event_log.actor_id = ?) + event.id < ? + and (? is null or event.uuid_id = ? or event.uuid_parameter = ? + or event.uuid_parameter2 = ?) + and (? is null or event.actor_id = ?) and (? is null or instance.subdomain = ?) - group by event_log.id + group by event.id order by id desc limit ? `, @@ -93,6 +85,8 @@ async function resolveEventsFromDB( after ?? 2147483647, objectId ?? null, objectId ?? null, + objectId ?? null, + objectId ?? null, actorId ?? null, actorId ?? null, instance ?? null, diff --git a/packages/server/src/schema/metadata/resolvers.ts b/packages/server/src/schema/metadata/resolvers.ts index 61cb5ad76..110700b73 100644 --- a/packages/server/src/schema/metadata/resolvers.ts +++ b/packages/server/src/schema/metadata/resolvers.ts @@ -85,7 +85,7 @@ export const resolvers: Resolvers = { originalAuthorUrl: string | null instance: string taxonomyTermIds: number[] - termNames: Record + taxonomyNames: Record authors: Record authorEdits: Record } @@ -94,11 +94,11 @@ export const resolvers: Resolvers = { ` WITH RECURSIVE subject_mapping AS ( SELECT - subject.id AS term_taxonomy_id, + subject.id AS taxonomy_id, subject.id AS subject_id, root.id AS root_id - FROM term_taxonomy root - JOIN term_taxonomy subject ON subject.parent_id = root.id + FROM taxonomy root + JOIN taxonomy subject ON subject.parent_id = root.id WHERE root.parent_id IS NULL OR root.id IN (106081, 146728) @@ -108,8 +108,8 @@ export const resolvers: Resolvers = { child.id, subject_mapping.subject_id, subject_mapping.root_id - FROM term_taxonomy child - JOIN subject_mapping ON subject_mapping.term_taxonomy_id = child.parent_id + FROM taxonomy child + JOIN subject_mapping ON subject_mapping.taxonomy_id = child.parent_id -- "Fächer im Aufbau" taxonomy is on the level of normal Serlo subjects, therefore we need a level below it. -- "Partner" taxonomy is below the subject "Mathematik", but we only want the entities with the specific partner as the subject. WHERE child.parent_id NOT IN (87993, 106081, 146728) @@ -128,8 +128,8 @@ export const resolvers: Resolvers = { license.url AS licenseUrl, license.original_author_url as originalAuthorUrl, instance.subdomain AS instance, - JSON_ARRAYAGG(term_taxonomy.id) AS taxonomyTermIds, - JSON_OBJECTAGG(term_taxonomy.id, term.name) AS termNames, + JSON_ARRAYAGG(taxonomy.id) AS taxonomyTermIds, + JSON_OBJECTAGG(taxonomy.id, taxonomy.name) AS taxonomyNames, JSON_OBJECTAGG(user.id, user.username) AS authors, JSON_OBJECTAGG(all_revisions_of_entity.id, user.id) AS authorEdits FROM entity @@ -139,11 +139,10 @@ export const resolvers: Resolvers = { JOIN license on license.id = entity.license_id JOIN entity_revision ON entity.current_revision_id = entity_revision.id JOIN term_taxonomy_entity on term_taxonomy_entity.entity_id = entity.id - JOIN term_taxonomy on term_taxonomy_entity.term_taxonomy_id = term_taxonomy.id - JOIN term on term_taxonomy.term_id = term.id + JOIN taxonomy on term_taxonomy_entity.term_taxonomy_id = taxonomy.id JOIN entity_revision all_revisions_of_entity ON all_revisions_of_entity.repository_id = entity.id JOIN user ON all_revisions_of_entity.author_id = user.id - JOIN subject_mapping on subject_mapping.term_taxonomy_id = term_taxonomy_entity.term_taxonomy_id + JOIN subject_mapping on subject_mapping.taxonomy_id = term_taxonomy_entity.term_taxonomy_id WHERE entity.id > ? AND (? is NULL OR instance.subdomain = ?) AND (? is NULL OR entity_revision.date > ?) @@ -311,7 +310,7 @@ export const resolvers: Resolvers = { } } const termName = - R.sortBy(([id]) => parseInt(id), Object.entries(row.termNames)) + R.sortBy(([id]) => parseInt(id), Object.entries(row.taxonomyNames)) .map((x) => x[1]) .at(0) ?? '' const fromI18n: string = row.instance === 'de' ? 'aus' : 'from' diff --git a/packages/server/src/schema/notifications/resolvers.ts b/packages/server/src/schema/notifications/resolvers.ts index 7508508c0..c4a1c8ab5 100644 --- a/packages/server/src/schema/notifications/resolvers.ts +++ b/packages/server/src/schema/notifications/resolvers.ts @@ -47,31 +47,22 @@ export const NotificationsResolver = createCachedResolver({ notification.seen, notification.email_sent as emailSent, notification.email, - event_log.id as eventId, - event.name as type, - event_log.actor_id as actorId, + event.id as eventId, + event_type.name as type, + event.actor_id as actorId, instance.subdomain as instance, - event_log.date as date, - event_log.uuid_id as objectId, - JSON_OBJECTAGG( - COALESCE(event_parameter_name.name, "__unused"), - event_parameter_uuid.uuid_id - ) as uuidParameters, - JSON_OBJECTAGG( - COALESCE(event_parameter_name.name, "__unused"), - event_parameter_string.value - ) as stringParameters + event.date as date, + event.uuid_id as objectId, + event.uuid_parameter as uuidParameter, + event.uuid_parameter2 as uuidParameter2, + event.string_parameter as stringParameter from notification join notification_event ON notification.id = notification_event.notification_id - join event_log on event_log.id = notification_event.event_log_id - join event on event.id = event_log.event_id - join instance on event_log.instance_id = instance.id - left join event_parameter on event_parameter.log_id = event_log.id - left join event_parameter_name on event_parameter.name_id = event_parameter_name.id - left join event_parameter_string on event_parameter_string.event_parameter_id = event_parameter.id - left join event_parameter_uuid on event_parameter_uuid.event_parameter_id = event_parameter.id + join event on event.id = notification_event.event_id + join event_type on event_type.id = event.event_type_id + join instance on event.instance_id = instance.id where notification.user_id = ? - group by notification.id, event_log.id + group by notification.id, event.id order by notification.date desc, notification.id desc `, [userId], diff --git a/packages/server/src/schema/subject/resolvers.ts b/packages/server/src/schema/subject/resolvers.ts index a34de9778..9463c3ac2 100644 --- a/packages/server/src/schema/subject/resolvers.ts +++ b/packages/server/src/schema/subject/resolvers.ts @@ -30,13 +30,11 @@ export const SubjectsResolver = createCachedResolver({ SELECT subject.id as taxonomyTermId, subject_instance.subdomain as instance - FROM term_taxonomy AS subject - JOIN term_taxonomy AS root ON root.id = subject.parent_id + FROM taxonomy AS subject + JOIN taxonomy AS root ON root.id = subject.parent_id JOIN uuid as subject_uuid ON subject_uuid.id = subject.id - JOIN taxonomy AS subject_taxonomy ON subject_taxonomy.id = subject.taxonomy_id - JOIN type AS subject_type ON subject_type.id = subject_taxonomy.type_id - JOIN term AS subject_term ON subject_term.id = subject.term_id - JOIN instance AS subject_instance ON subject_instance.id = subject_term.instance_id + JOIN type AS subject_type ON subject_type.id = subject.type_id + JOIN instance AS subject_instance ON subject_instance.id = subject.instance_id WHERE (root.parent_id IS NULL OR root.id = 106081 @@ -119,29 +117,29 @@ export const SubjectResolver = createCachedResolver({ return await database.fetchOptional( ` - SELECT t.name as name, t1.id as id - FROM term_taxonomy t0 - JOIN term_taxonomy t1 ON t1.parent_id = t0.id - LEFT JOIN term_taxonomy t2 ON t2.parent_id = t1.id - LEFT JOIN term_taxonomy t3 ON t3.parent_id = t2.id - LEFT JOIN term_taxonomy t4 ON t4.parent_id = t3.id - LEFT JOIN term_taxonomy t5 ON t5.parent_id = t4.id - LEFT JOIN term_taxonomy t6 ON t6.parent_id = t5.id - LEFT JOIN term_taxonomy t7 ON t7.parent_id = t6.id - LEFT JOIN term_taxonomy t8 ON t8.parent_id = t7.id - LEFT JOIN term_taxonomy t9 ON t9.parent_id = t8.id - LEFT JOIN term_taxonomy t10 ON t10.parent_id = t9.id - LEFT JOIN term_taxonomy t11 ON t11.parent_id = t10.id - LEFT JOIN term_taxonomy t12 ON t12.parent_id = t11.id - LEFT JOIN term_taxonomy t13 ON t13.parent_id = t12.id - LEFT JOIN term_taxonomy t14 ON t14.parent_id = t13.id - LEFT JOIN term_taxonomy t15 ON t15.parent_id = t14.id - LEFT JOIN term_taxonomy t16 ON t16.parent_id = t15.id - LEFT JOIN term_taxonomy t17 ON t17.parent_id = t16.id - LEFT JOIN term_taxonomy t18 ON t18.parent_id = t17.id - LEFT JOIN term_taxonomy t19 ON t19.parent_id = t18.id - LEFT JOIN term_taxonomy t20 ON t20.parent_id = t19.id - JOIN term t on t1.term_id = t.id + SELECT + t1.name as name, t1.id as id + FROM taxonomy t0 + JOIN taxonomy t1 ON t1.parent_id = t0.id + LEFT JOIN taxonomy t2 ON t2.parent_id = t1.id + LEFT JOIN taxonomy t3 ON t3.parent_id = t2.id + LEFT JOIN taxonomy t4 ON t4.parent_id = t3.id + LEFT JOIN taxonomy t5 ON t5.parent_id = t4.id + LEFT JOIN taxonomy t6 ON t6.parent_id = t5.id + LEFT JOIN taxonomy t7 ON t7.parent_id = t6.id + LEFT JOIN taxonomy t8 ON t8.parent_id = t7.id + LEFT JOIN taxonomy t9 ON t9.parent_id = t8.id + LEFT JOIN taxonomy t10 ON t10.parent_id = t9.id + LEFT JOIN taxonomy t11 ON t11.parent_id = t10.id + LEFT JOIN taxonomy t12 ON t12.parent_id = t11.id + LEFT JOIN taxonomy t13 ON t13.parent_id = t12.id + LEFT JOIN taxonomy t14 ON t14.parent_id = t13.id + LEFT JOIN taxonomy t15 ON t15.parent_id = t14.id + LEFT JOIN taxonomy t16 ON t16.parent_id = t15.id + LEFT JOIN taxonomy t17 ON t17.parent_id = t16.id + LEFT JOIN taxonomy t18 ON t18.parent_id = t17.id + LEFT JOIN taxonomy t19 ON t19.parent_id = t18.id + LEFT JOIN taxonomy t20 ON t20.parent_id = t19.id WHERE ( t0.id = 146728 OR diff --git a/packages/server/src/schema/thread/resolvers.ts b/packages/server/src/schema/thread/resolvers.ts index f46b8583a..32bea80cb 100644 --- a/packages/server/src/schema/thread/resolvers.ts +++ b/packages/server/src/schema/thread/resolvers.ts @@ -68,13 +68,13 @@ export const resolvers: Resolvers = { ` WITH RECURSIVE descendants AS ( SELECT id, parent_id - FROM term_taxonomy + FROM taxonomy WHERE (? is null OR id = ?) UNION SELECT tt.id, tt.parent_id - FROM term_taxonomy tt + FROM taxonomy tt JOIN descendants d ON tt.parent_id = d.id ), subject_entities AS ( SELECT id as entity_id FROM descendants diff --git a/packages/server/src/schema/uuid/abstract-uuid/resolvers.ts b/packages/server/src/schema/uuid/abstract-uuid/resolvers.ts index 37611ed03..fd60b8090 100644 --- a/packages/server/src/schema/uuid/abstract-uuid/resolvers.ts +++ b/packages/server/src/schema/uuid/abstract-uuid/resolvers.ts @@ -235,7 +235,6 @@ const BaseTaxonomy = t.intersection([ taxonomyName: t.string, taxonomyDescription: t.union([t.null, t.string]), taxonomyWeight: t.union([t.null, t.number]), - taxonomyId: t.number, taxonomyParentId: t.union([t.null, t.number]), taxonomyChildrenIds: WeightedNumberList, taxonomyEntityChildrenIds: WeightedNumberList, @@ -313,11 +312,10 @@ async function resolveUuidFromDatabase( taxonomy_type.name AS taxonomyType, taxonomy_instance.subdomain AS taxonomyInstance, - term.name AS taxonomyName, - term_taxonomy.description AS taxonomyDescription, - term_taxonomy.weight AS taxonomyWeight, - taxonomy.id AS taxonomyId, - term_taxonomy.parent_id AS taxonomyParentId, + taxonomy.name AS taxonomyName, + taxonomy.description AS taxonomyDescription, + taxonomy.weight AS taxonomyWeight, + taxonomy.parent_id AS taxonomyParentId, JSON_OBJECTAGG( COALESCE(taxonomy_child.id, "__no_key"), taxonomy_child.weight @@ -351,13 +349,11 @@ async function resolveUuidFromDatabase( left join entity revision_entity on revision_entity.id = revision.repository_id left join type revision_type on revision_entity.type_id = revision_type.id - LEFT JOIN term_taxonomy ON term_taxonomy.id = uuid.id - LEFT JOIN taxonomy ON taxonomy.id = term_taxonomy.taxonomy_id + LEFT JOIN taxonomy ON taxonomy.id = uuid.id LEFT JOIN type taxonomy_type ON taxonomy_type.id = taxonomy.type_id LEFT JOIN instance taxonomy_instance ON taxonomy_instance.id = taxonomy.instance_id - LEFT JOIN term ON term.id = term_taxonomy.term_id - LEFT JOIN term_taxonomy taxonomy_child ON taxonomy_child.parent_id = term_taxonomy.id - LEFT JOIN term_taxonomy_entity ON term_taxonomy_entity.term_taxonomy_id = term_taxonomy.id + LEFT JOIN taxonomy taxonomy_child ON taxonomy_child.parent_id = taxonomy.id + LEFT JOIN term_taxonomy_entity ON term_taxonomy_entity.term_taxonomy_id = taxonomy.id LEFT JOIN user ON user.id = uuid.id LEFT JOIN role_user ON user.id = role_user.user_id @@ -515,7 +511,6 @@ async function resolveUuidFromDatabase( name: baseUuid.taxonomyName, description: baseUuid.taxonomyDescription, weight: baseUuid.taxonomyWeight ?? 0, - taxonomyId: baseUuid.taxonomyId, parentId: baseUuid.taxonomyParentId, childrenIds, } diff --git a/packages/server/src/schema/uuid/taxonomy-term/resolvers.ts b/packages/server/src/schema/uuid/taxonomy-term/resolvers.ts index 52931a8e5..a3cff3f66 100644 --- a/packages/server/src/schema/uuid/taxonomy-term/resolvers.ts +++ b/packages/server/src/schema/uuid/taxonomy-term/resolvers.ts @@ -126,51 +126,31 @@ export const resolvers: Resolvers = { throw new InternalServerError('no uuid entry could be created') } - const { insertId: termId } = await database.mutate( - ` - insert into term (instance_id, name) - select term_parent.instance_id, ? - from term term_parent - join term_taxonomy taxonomy_parent on taxonomy_parent.term_id = term_parent.id - where taxonomy_parent.id = ? - limit 1 - `, - [name, parentId], - ) - - if (termId <= 0) { - throw new UserInputError( - `parent taxonomy ${parentId} does not exists`, - ) - } - const { currentHeaviest } = await database.fetchOne<{ currentHeaviest: number }>( ` - SELECT IFNULL(MAX(tt.weight), 0) AS currentHeaviest - FROM term_taxonomy tt - WHERE tt.parent_id = ? - `, + SELECT IFNULL(MAX(taxonomy.weight), 0) AS currentHeaviest + FROM taxonomy + WHERE taxonomy.parent_id = ? + `, [parentId], ) await database.mutate( ` - insert into term_taxonomy (id, taxonomy_id, term_id, parent_id, description, weight) - select ?, taxonomy.id, ?, ?, ?, ? - from taxonomy - join type on taxonomy.type_id = type.id - join instance on taxonomy.instance_id = instance.id + insert into taxonomy + (id, type_id, instance_id, parent_id, description, weight, name) + select ?, type.id, instance.id, ?, ?, ?, ? + from type, instance where type.name = ? and instance.subdomain = ? - limit 1 - `, + `, [ taxonomyId, - termId, parentId, description, currentHeaviest + 1, + name, taxonomyType, parent.instance, ], @@ -402,7 +382,7 @@ export const resolvers: Resolvers = { // we do not need to distinguish between them await database.mutate( - 'update term_taxonomy set weight = ? where parent_id = ? and id = ?', + 'update taxonomy set weight = ? where parent_id = ? and id = ?', [position, taxonomyTermId, childId], ) @@ -459,11 +439,9 @@ export const resolvers: Resolvers = { await database.mutate( ` - UPDATE term - JOIN term_taxonomy ON term.id = term_taxonomy.term_id - SET term.name = ?, - term_taxonomy.description = ? - WHERE term_taxonomy.id = ?; + UPDATE taxonomy + SET name = ?, description = ? + WHERE taxonomy.id = ?; `, [input.name, input.description, input.id], ) diff --git a/packages/server/src/schema/uuid/taxonomy-term/types.graphql b/packages/server/src/schema/uuid/taxonomy-term/types.graphql index 426e4bca8..d57c884fa 100644 --- a/packages/server/src/schema/uuid/taxonomy-term/types.graphql +++ b/packages/server/src/schema/uuid/taxonomy-term/types.graphql @@ -23,7 +23,6 @@ type TaxonomyTerm implements AbstractUuid & InstanceAware & ThreadAware { weight: Int! parent: TaxonomyTerm path: [TaxonomyTerm]! - taxonomyId: Int! children(after: String, first: Int): AbstractUuidConnection! } diff --git a/packages/server/src/schema/uuid/user/resolvers.ts b/packages/server/src/schema/uuid/user/resolvers.ts index 13b204b02..ef5dfd8ce 100644 --- a/packages/server/src/schema/uuid/user/resolvers.ts +++ b/packages/server/src/schema/uuid/user/resolvers.ts @@ -56,10 +56,10 @@ export const ActiveUserIdsResolver = createCachedResolver< ` SELECT u.id FROM user u - JOIN event_log e ON u.id = e.actor_id - WHERE e.event_id = 5 AND e.date > DATE_SUB(?, Interval 90 day) + JOIN event e ON u.id = e.actor_id + WHERE e.event_type_id = 5 AND e.date > DATE_SUB(?, Interval 90 day) GROUP BY u.id - HAVING count(e.event_id) > 10 + HAVING count(e.event_type_id) > 10 `, [new Date(timer.now()).toISOString()], ) @@ -457,10 +457,10 @@ export const resolvers: Resolvers = { 'UPDATE entity_revision SET author_id = ? WHERE author_id = ?', [idUserDeleted, id], ), - database.mutate( - 'UPDATE event_log SET actor_id = ? WHERE actor_id = ?', - [idUserDeleted, id], - ), + database.mutate('UPDATE event SET actor_id = ? WHERE actor_id = ?', [ + idUserDeleted, + id, + ]), database.mutate( 'UPDATE page_revision SET author_id = ? WHERE author_id = ?', [idUserDeleted, id], diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts index ee31ffe01..19396a732 100644 --- a/packages/server/src/types.ts +++ b/packages/server/src/types.ts @@ -1407,7 +1407,6 @@ export type TaxonomyTerm = AbstractUuid & InstanceAware & ThreadAware & { name: Scalars['String']['output']; parent?: Maybe; path: Array>; - taxonomyId: Scalars['Int']['output']; threads: ThreadConnection; title: Scalars['String']['output']; trashed: Scalars['Boolean']['output']; @@ -3113,7 +3112,6 @@ export type TaxonomyTermResolvers; parent?: Resolver, ParentType, ContextType>; path?: Resolver>, ParentType, ContextType>; - taxonomyId?: Resolver; threads?: Resolver>; title?: Resolver; trashed?: Resolver;