Skip to content

Commit

Permalink
Merge pull request #1128 from serlo/remove-user-endpoints
Browse files Browse the repository at this point in the history
refactor: Remove unused user endpoints like `activeAuthors`
  • Loading branch information
kulla authored Nov 22, 2023
2 parents 6b51cfb + 6d11b18 commit 50a3186
Show file tree
Hide file tree
Showing 5 changed files with 2 additions and 267 deletions.
130 changes: 0 additions & 130 deletions __tests__/schema/uuid/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,11 @@ import {
givenSpreadsheet,
hasInternalServerError,
nextUuid,
returnsJson,
returnsMalformedJson,
given,
Client,
} from '../../__utils__'
import { Model } from '~/internals/graphql'
import { MajorDimension } from '~/model'
import { castToUuid } from '~/model/decoder'
import { Instance } from '~/types'

const client = new Client()
Expand Down Expand Up @@ -559,133 +556,6 @@ describe('User', () => {
})
})

describe('endpoint activeAuthors', () => {
test('returns list of active authors', async () => {
given('ActiveAuthorsQuery').returns([user.id, user2.id])

await expectUserIds({ endpoint: 'activeAuthors', ids: [user.id, user2.id] })
})

test('returns only users', async () => {
given('ActiveAuthorsQuery').returns([user.id, article.id])
given('UuidQuery').for(article)

await expectUserIds({ endpoint: 'activeAuthors', ids: [user.id] })
await assertErrorEvent({ errorContext: { invalidElements: [article] } })
})
})

describe('endpoint activeReviewers', () => {
test('returns list of active reviewers', async () => {
given('ActiveReviewersQuery').returns([user.id, user2.id])

await expectUserIds({
endpoint: 'activeReviewers',
ids: [user.id, user2.id],
})
})

test('returns only users', async () => {
given('ActiveReviewersQuery').returns([user.id, article.id])
given('UuidQuery').for(article)

await expectUserIds({ endpoint: 'activeReviewers', ids: [user.id] })
await assertErrorEvent({ errorContext: { invalidElements: [article] } })
})
})

describe('endpoint activeDonors', () => {
test('returns list of users', async () => {
givenActiveDonors([user, user2])
given('UuidQuery').for(user2)

await expectUserIds({ endpoint: 'activeDonors', ids: [user.id, user2.id] })
})

test('returned list only contains user', async () => {
givenActiveDonors([user, article])
given('UuidQuery').for(article)

await expectUserIds({ endpoint: 'activeDonors', ids: [user.id] })
await assertErrorEvent({ errorContext: { invalidElements: [article] } })
})

describe('parser', () => {
test('removes entries which are no valid uuids', async () => {
givenActiveDonorsSpreadsheet([['Header', '23', 'foo', '-1', '', '1.5']])

await expectUserIds({ endpoint: 'activeDonors', ids: [23] })
await assertErrorEvent({
message: 'invalid entry in activeDonorSpreadsheet',
errorContext: { invalidElements: ['foo', '-1', '', '1.5'] },
})
})

test('cell entries are trimmed of leading and trailing whitespaces', async () => {
givenActiveDonorsSpreadsheet([['Header', ' 10 ', ' 20']])

await expectUserIds({ endpoint: 'activeDonors', ids: [10, 20] })
})

describe('returns empty list', () => {
test('when spreadsheet is empty', async () => {
givenActiveDonorsSpreadsheet([[]])

await expectUserIds({ endpoint: 'activeDonors', ids: [] })
})

test('when spreadsheet api responds with invalid json data', async () => {
givenSpreadheetApi(returnsJson({ json: {} }))

await expectUserIds({ endpoint: 'activeDonors', ids: [] })
await assertErrorEvent()
})

test('when spreadsheet api responds with malformed json', async () => {
givenSpreadheetApi(returnsMalformedJson())

await expectUserIds({ endpoint: 'activeDonors', ids: [] })
await assertErrorEvent()
})

test('when spreadsheet api has an internal server error', async () => {
givenSpreadheetApi(hasInternalServerError())

await expectUserIds({ endpoint: 'activeDonors', ids: [] })
await assertErrorEvent()
})
})
})
})

async function expectUserIds({
endpoint,
ids,
}: {
endpoint: 'activeReviewers' | 'activeAuthors' | 'activeDonors'
ids: number[]
}) {
ids.map(castToUuid).forEach((id) => given('UuidQuery').for({ ...user, id }))
const nodes = ids.map((id) => {
return { __typename: 'User', id }
})

await new Client()
.prepareQuery({
query: gql`
query {
${endpoint} {
nodes {
__typename
id
}
}
}
`,
})
.shouldReturnData({ [endpoint]: { nodes } })
}

function givenActiveDonors(users: Model<'AbstractUuid'>[]) {
const values = [['Header', ...users.map((user) => user.id.toString())]]
givenActiveDonorsSpreadsheet(values)
Expand Down
64 changes: 2 additions & 62 deletions packages/server/src/schema/uuid/user/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,59 +20,27 @@ import {
createNamespace,
generateRole,
isGlobalRole,
LegacyQueries,
Model,
Mutations,
Queries,
TypeResolvers,
} from '~/internals/graphql'
import {
DiscriminatorType,
EntityDecoder,
RevisionDecoder,
UserDecoder,
} from '~/model/decoder'
import { EntityDecoder, RevisionDecoder, UserDecoder } from '~/model/decoder'
import { CellValues, MajorDimension } from '~/model/google-spreadsheet-api'
import {
getPermissionsForRole,
getRolesWithInheritance,
} from '~/schema/authorization/roles'
import { resolveScopedRoles } from '~/schema/authorization/utils'
import { ConnectionPayload } from '~/schema/connection/types'
import { resolveConnection } from '~/schema/connection/utils'
import { resolveEvents } from '~/schema/notification/resolvers'
import { createThreadResolvers } from '~/schema/thread/utils'
import { createUuidResolvers } from '~/schema/uuid/abstract-uuid/utils'
import { Instance, User } from '~/types'

export const resolvers: LegacyQueries<
'activeAuthors' | 'activeReviewers' | 'activeDonors'
> &
TypeResolvers<User> &
export const resolvers: TypeResolvers<User> &
Queries<'user'> &
Mutations<'user'> = {
Query: {
async activeAuthors(_parent, payload, context) {
return resolveUserConnectionFromIds({
ids: await context.dataSources.model.serlo.getActiveAuthorIds(),
payload,
context,
})
},
async activeDonors(_parent, payload, context) {
return resolveUserConnectionFromIds({
ids: await activeDonorIDs(context),
payload,
context,
})
},
async activeReviewers(_parent, payload, context) {
return resolveUserConnectionFromIds({
ids: await context.dataSources.model.serlo.getActiveReviewerIds(),
payload,
context,
})
},
user: createNamespace(),
},
UserQuery: {
Expand Down Expand Up @@ -483,34 +451,6 @@ export const resolvers: LegacyQueries<
},
}

async function resolveUserConnectionFromIds({
ids,
payload,
context,
}: {
ids: number[]
payload: ConnectionPayload
context: Context
}) {
const uuids = await Promise.all(
ids.map(async (id) => context.dataSources.model.serlo.getUuid({ id })),
)
const users = assertAll({
assertion(uuid: Model<'AbstractUuid'> | null): uuid is Model<'User'> {
return uuid !== null && uuid.__typename == DiscriminatorType.User
},
error: new Error('Invalid user found'),
})(uuids)

return resolveConnection({
nodes: users,
payload,
createCursor(node) {
return node.id.toString()
},
})
}

async function activeDonorIDs({ dataSources }: Context) {
return F.pipe(
await dataSources.model.googleSpreadsheetApi.getValues({
Expand Down
18 changes: 0 additions & 18 deletions packages/server/src/schema/uuid/user/types.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,6 @@ type User implements AbstractUuid & ThreadAware {
}

extend type Query {
activeAuthors(
after: String
before: String
first: Int
last: Int
): UserConnection!
activeDonors(
after: String
before: String
first: Int
last: Int
): UserConnection!
activeReviewers(
after: String
before: String
first: Int
last: Int
): UserConnection!
user: UserQuery!
}

Expand Down
30 changes: 0 additions & 30 deletions packages/server/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1783,9 +1783,6 @@ export type PageRevisionCursor = {

export type Query = {
__typename?: 'Query';
activeAuthors: UserConnection;
activeDonors: UserConnection;
activeReviewers: UserConnection;
ai: AiQuery;
authorization: Scalars['JSON']['output'];
entity?: Maybe<EntityQuery>;
Expand All @@ -1804,30 +1801,6 @@ export type Query = {
};


export type QueryActiveAuthorsArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type QueryActiveDonorsArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type QueryActiveReviewersArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type QueryEventsArgs = {
actorId?: InputMaybe<Scalars['Int']['input']>;
after?: InputMaybe<Scalars['String']['input']>;
Expand Down Expand Up @@ -4322,9 +4295,6 @@ export type PageRevisionCursorResolvers<ContextType = Context, ParentType extend
};

export type QueryResolvers<ContextType = Context, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
activeAuthors?: Resolver<ResolversTypes['UserConnection'], ParentType, ContextType, Partial<QueryActiveAuthorsArgs>>;
activeDonors?: Resolver<ResolversTypes['UserConnection'], ParentType, ContextType, Partial<QueryActiveDonorsArgs>>;
activeReviewers?: Resolver<ResolversTypes['UserConnection'], ParentType, ContextType, Partial<QueryActiveReviewersArgs>>;
ai?: Resolver<ResolversTypes['AiQuery'], ParentType, ContextType>;
authorization?: Resolver<ResolversTypes['JSON'], ParentType, ContextType>;
entity?: Resolver<Maybe<ResolversTypes['EntityQuery']>, ParentType, ContextType>;
Expand Down
27 changes: 0 additions & 27 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1779,9 +1779,6 @@ export type PageRevisionCursor = {

export type Query = {
__typename?: 'Query';
activeAuthors: UserConnection;
activeDonors: UserConnection;
activeReviewers: UserConnection;
ai: AiQuery;
authorization: Scalars['JSON']['output'];
entity?: Maybe<EntityQuery>;
Expand All @@ -1800,30 +1797,6 @@ export type Query = {
};


export type QueryActiveAuthorsArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type QueryActiveDonorsArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type QueryActiveReviewersArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};


export type QueryEventsArgs = {
actorId?: InputMaybe<Scalars['Int']['input']>;
after?: InputMaybe<Scalars['String']['input']>;
Expand Down

0 comments on commit 50a3186

Please sign in to comment.