Merge branch 'frontend_community_message_keep_open' into frontend_disable_cross_group_link_tx

This commit is contained in:
einhornimmond 2025-05-19 14:47:26 +02:00
commit 3d037e9b97
6 changed files with 68 additions and 99 deletions

View File

@ -6,19 +6,7 @@ import {
} from 'database'
import { Decimal } from 'decimal.js-light'
import { GraphQLResolveInfo } from 'graphql'
import {
Arg,
Args,
Authorized,
Ctx,
FieldResolver,
Info,
Int,
Mutation,
Query,
Resolver,
Root,
} from 'type-graphql'
import { Arg, Args, Authorized, Ctx, Info, Int, Mutation, Query, Resolver } from 'type-graphql'
import { EntityManager, IsNull, getConnection } from 'typeorm'
import { AdminCreateContributionArgs } from '@arg/AdminCreateContributionArgs'
@ -34,7 +22,6 @@ import { Contribution, ContributionListResult } from '@model/Contribution'
import { Decay } from '@model/Decay'
import { OpenCreation } from '@model/OpenCreation'
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
import { User } from '@model/User'
import { RIGHTS } from '@/auth/RIGHTS'
import {
@ -61,12 +48,11 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
import { calculateDecay } from '@/util/decay'
import { fullName } from '@/util/utilities'
import { ContributionMessage } from '@model/ContributionMessage'
import { start } from 'repl'
import { ContributionMessageType } from '../enum/ContributionMessageType'
import { loadAllContributions, loadUserContributions } from './util/contributions'
import { getOpenCreations, getUserCreation, validateContribution } from './util/creations'
import { extractGraphQLFields, extractGraphQLFieldsForSelect } from './util/extractGraphQLFields'
import { findContributionMessages } from './util/findContributionMessages'
import { extractGraphQLFields } from './util/extractGraphQLFields'
import { findContributions } from './util/findContributions'
import { getLastTransaction } from './util/getLastTransaction'
import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector'
@ -140,20 +126,14 @@ export class ContributionResolver {
const res = await contribution.softRemove()
return !!res
}
@Authorized([RIGHTS.LIST_CONTRIBUTIONS])
@Query(() => ContributionListResult)
async listContributions(
@Ctx() context: Context,
@Arg('pagination') pagination: Paginated,
@Arg('messagePagination', { nullable: true }) messagePagination?: Paginated,
): Promise<ContributionListResult> {
const user = getUser(context)
const [dbContributions, count] = await loadUserContributions(
user.id,
pagination,
messagePagination,
)
const [dbContributions, count] = await loadUserContributions(user.id, pagination)
// show contributions in progress first
const inProgressContributions = dbContributions.filter(
@ -163,18 +143,9 @@ export class ContributionResolver {
(contribution) => contribution.contributionStatus !== ContributionStatus.IN_PROGRESS,
)
return new ContributionListResult(
const result = new ContributionListResult(
count,
[...inProgressContributions, ...notInProgressContributions].map((contribution) => {
// we currently expect not much contribution messages for needing pagination
// but if we get more than expected, we should get warned
if ((contribution.messages?.length || 0) > (messagePagination?.pageSize || 10)) {
logger.warn('more contribution messages as expected, consider pagination', {
contributionId: contribution.id,
expected: messagePagination?.pageSize || 10,
actual: contribution.messages?.length || 0,
})
}
// filter out moderator messages for this call
contribution.messages = contribution.messages?.filter(
(message) =>
@ -183,6 +154,7 @@ export class ContributionResolver {
return contribution
}),
)
return result
}
@Authorized([RIGHTS.LIST_CONTRIBUTIONS])
@ -625,50 +597,4 @@ export class ContributionResolver {
return !!res
}
// Field resolvers
@Authorized([RIGHTS.USER])
@FieldResolver(() => User, { nullable: true })
async user(
@Root() contribution: DbContribution,
@Info() info: GraphQLResolveInfo,
): Promise<User | null> {
let user: DbUser | null = contribution.user
if (!user) {
const queryBuilder = DbUser.createQueryBuilder('user')
queryBuilder.where('user.id = :userId', { userId: contribution.userId })
extractGraphQLFieldsForSelect(info, queryBuilder, 'user')
user = await queryBuilder.getOne()
}
if (user) {
return new User(user)
}
return null
}
@Authorized([RIGHTS.LIST_ALL_CONTRIBUTION_MESSAGES])
@FieldResolver(() => [ContributionMessage], { nullable: true })
async messages(
@Root() contribution: UnconfirmedContribution,
@Arg('pagination', () => Paginated) pagination: Paginated,
): Promise<ContributionMessage[] | null> {
if (contribution.messagesCount === 0) {
return null
}
const [contributionMessages] = await findContributionMessages({
contributionId: contribution.id,
pagination,
})
// we currently expect not much contribution messages for needing pagination
// but if we get more than expected, we should get warned
if (contributionMessages.length > pagination.pageSize) {
logger.warn('more contribution messages as expected, consider pagination', {
contributionId: contribution.id,
expected: pagination.pageSize,
actual: contributionMessages.length,
})
}
return contributionMessages.map((message) => new ContributionMessage(message))
}
}

View File

@ -1,6 +1,7 @@
import { Order } from '@/graphql/enum/Order'
import { Paginated } from '@arg/Paginated'
import { Contribution as DbContribution } from 'database'
import { FindManyOptions } from 'typeorm'
import { FindManyOptions, In } from 'typeorm'
// TODO: combine with Pagination class for all queries to use
function buildPaginationOptions(paginated: Paginated): FindManyOptions<DbContribution> {
@ -19,17 +20,41 @@ function buildPaginationOptions(paginated: Paginated): FindManyOptions<DbContrib
export const loadUserContributions = async (
userId: number,
paginated: Paginated,
messagePagination?: Paginated,
): Promise<[DbContribution[], number]> => {
const { order } = paginated
const { order: messageOrder } = messagePagination || { order: 'ASC' }
// manual, faster and simpler queries as auto generated from typeorm
const countPromise = DbContribution.count({
select: { id: true },
where: { userId },
withDeleted: true,
})
// we collect all contributions, ignoring if user exist or not
const contributionIds = await DbContribution.find({
select: { id: true },
where: { userId },
withDeleted: true,
order: { createdAt: order, id: order },
...buildPaginationOptions(paginated),
})
const contributionsPromise = DbContribution.find({
relations: { messages: { user: true } },
withDeleted: true,
order: { createdAt: order, id: order, messages: { createdAt: Order.ASC } },
where: { id: In(contributionIds.map((c) => c.id)) },
})
return [await contributionsPromise, await countPromise]
// original code
// note: typeorm will create similar queries as above, but more complex and slower
/*
return DbContribution.findAndCount({
where: { userId },
withDeleted: true,
relations: { messages: { user: true } },
order: { createdAt: order, id: order, messages: { createdAt: messageOrder } },
order: { createdAt: order, id: order, messages: { createdAt: Order.ASC } },
...buildPaginationOptions(paginated),
})
*/
}
/*
@ -40,9 +65,29 @@ export const loadAllContributions = async (
paginated: Paginated,
): Promise<[DbContribution[], number]> => {
const { order } = paginated
// manual, faster queries as auto generated from typeorm
const countPromise = DbContribution.count({ select: { id: true } })
// console.log('loadAllContributions', { count })
const contributionIds = await DbContribution.find({
select: { id: true },
order: { createdAt: order, id: order },
...buildPaginationOptions(paginated),
})
const contributionsPromise = DbContribution.find({
relations: { user: { emailContact: true } },
order: { createdAt: order, id: order },
where: { id: In(contributionIds.map((c) => c.id)) },
})
return [await contributionsPromise, await countPromise]
// original code
// note: typeorm will create similar queries as above, but more complex and slower
/*
return DbContribution.findAndCount({
relations: { user: { emailContact: true } },
order: { createdAt: order, id: order },
...buildPaginationOptions(paginated),
})
*/
}

View File

@ -39,7 +39,7 @@ export class Connection {
logging: true,
logger: new FileLogger('all', {
// workaround to let previous path working, because with esbuild the script root path has changed
logPath: '../' + CONFIG.TYPEORM_LOGGING_RELATIVE_PATH,
logPath: (CONFIG.PRODUCTION ? '../' : '') + CONFIG.TYPEORM_LOGGING_RELATIVE_PATH,
}),
extra: {
charset: 'utf8mb4_unicode_ci',

View File

@ -52,24 +52,19 @@ const pollInterval = CONFIG.AUTO_POLL_INTERVAL || undefined
const emit = defineEmits(['update-contribution-form'])
// refs
const currentPage = ref(1)
const currentPage = ref(Number(route.params.page) || 1)
const openMessagesListId = ref(null)
// queries
const { result, loading, refetch, onResult } = useQuery(
listContributions,
{
() => ({
pagination: {
currentPage: currentPage.value,
pageSize,
order: 'DESC',
},
messagePagination: {
currentPage: 1,
pageSize: 10,
order: 'ASC',
},
},
}),
{
fetchPolicy: 'cache-and-network',
pollInterval,

View File

@ -29,23 +29,26 @@ import { useQuery } from '@vue/apollo-composable'
import CONFIG from '@/config'
import PaginatorRouteParamsPage from '@/components/PaginatorRouteParamsPage.vue'
import { PAGE_SIZE } from '@/constants'
import { useRoute } from 'vue-router'
const route = useRoute()
// constants
const pollInterval = CONFIG.AUTO_POLL_INTERVAL || undefined
const pageSize = PAGE_SIZE
// computed
const currentPage = ref(1)
const currentPage = ref(Number(route.params.page) || 1)
const { result, loading } = useQuery(
listAllContributions,
{
() => ({
pagination: {
currentPage: currentPage.value,
pageSize,
order: 'DESC',
},
},
}),
{
fetchPolicy: 'cache-and-network',
pollInterval,

View File

@ -31,8 +31,8 @@ fragment contributionMessageFields on ContributionMessage {
userId
}
query listContributions ($pagination: Paginated!, $messagePagination: Paginated!) {
listContributions(pagination: $pagination, messagePagination: $messagePagination) {
query listContributions ($pagination: Paginated!) {
listContributions(pagination: $pagination) {
contributionCount
contributionList {
id
@ -41,7 +41,7 @@ query listContributions ($pagination: Paginated!, $messagePagination: Paginated!
contributionDate
contributionStatus
messagesCount
messages(pagination: $messagePagination) {
messages {
...contributionMessageFields
}
updatedBy