@studious-lms/server 1.27.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -4
- package/dist/index.js.map +1 -1
- package/dist/instrument.js +9 -4
- package/dist/instrument.js.map +1 -1
- package/dist/lib/fileUpload.d.ts +15 -0
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +43 -2
- package/dist/lib/fileUpload.js.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +2 -2
- package/dist/pipelines/generateVisualization.d.ts +33 -0
- package/dist/pipelines/generateVisualization.d.ts.map +1 -0
- package/dist/pipelines/generateVisualization.js +79 -0
- package/dist/pipelines/generateVisualization.js.map +1 -0
- package/dist/routers/_app.d.ts +891 -53
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/admin.d.ts +297 -0
- package/dist/routers/admin.d.ts.map +1 -1
- package/dist/routers/admin.js +43 -2
- package/dist/routers/admin.js.map +1 -1
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +16 -3
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/module.d.ts +1 -1
- package/dist/routers/visualization.d.ts +124 -0
- package/dist/routers/visualization.d.ts.map +1 -0
- package/dist/routers/visualization.js +41 -0
- package/dist/routers/visualization.js.map +1 -0
- package/dist/services/adminClass.d.ts +153 -0
- package/dist/services/adminClass.d.ts.map +1 -0
- package/dist/services/adminClass.js +196 -0
- package/dist/services/adminClass.js.map +1 -0
- package/dist/services/adminInstitution.d.ts +2 -0
- package/dist/services/adminInstitution.d.ts.map +1 -1
- package/dist/services/adminInstitution.js +11 -4
- package/dist/services/adminInstitution.js.map +1 -1
- package/dist/services/adminMetrics.d.ts +8 -0
- package/dist/services/adminMetrics.d.ts.map +1 -1
- package/dist/services/adminMetrics.js +30 -3
- package/dist/services/adminMetrics.js.map +1 -1
- package/dist/services/adminSpam.d.ts +76 -0
- package/dist/services/adminSpam.d.ts.map +1 -0
- package/dist/services/adminSpam.js +163 -0
- package/dist/services/adminSpam.js.map +1 -0
- package/dist/services/adminSql.d.ts +36 -0
- package/dist/services/adminSql.d.ts.map +1 -0
- package/dist/services/adminSql.js +172 -0
- package/dist/services/adminSql.js.map +1 -0
- package/dist/services/adminTelemetry.d.ts +56 -0
- package/dist/services/adminTelemetry.d.ts.map +1 -0
- package/dist/services/adminTelemetry.js +147 -0
- package/dist/services/adminTelemetry.js.map +1 -0
- package/dist/services/adminUser.d.ts +45 -0
- package/dist/services/adminUser.d.ts.map +1 -1
- package/dist/services/adminUser.js +48 -11
- package/dist/services/adminUser.js.map +1 -1
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +10 -4
- package/dist/services/auth.js.map +1 -1
- package/dist/services/fees.d.ts.map +1 -1
- package/dist/services/fees.js +7 -3
- package/dist/services/fees.js.map +1 -1
- package/dist/services/module.d.ts.map +1 -1
- package/dist/services/module.js +23 -4
- package/dist/services/module.js.map +1 -1
- package/dist/services/visualization.d.ts +72 -0
- package/dist/services/visualization.d.ts.map +1 -0
- package/dist/services/visualization.js +122 -0
- package/dist/services/visualization.js.map +1 -0
- package/dist/utils/sentryTrpc.d.ts +3 -0
- package/dist/utils/sentryTrpc.d.ts.map +1 -0
- package/dist/utils/sentryTrpc.js +26 -0
- package/dist/utils/sentryTrpc.js.map +1 -0
- package/package.json +1 -1
- package/prisma/migrations/20261025120000_add_visualizations/migration.sql +27 -0
- package/prisma/schema.prisma +24 -0
- package/src/index.ts +30 -4
- package/src/instrument.ts +8 -2
- package/src/lib/fileUpload.ts +49 -0
- package/src/pipelines/generateVisualization.ts +107 -0
- package/src/routers/_app.ts +2 -0
- package/src/routers/admin.ts +72 -0
- package/src/routers/class.ts +14 -1
- package/src/routers/visualization.ts +60 -0
- package/src/services/adminClass.ts +222 -0
- package/src/services/adminInstitution.ts +9 -2
- package/src/services/adminMetrics.ts +35 -0
- package/src/services/adminSpam.ts +224 -0
- package/src/services/adminSql.ts +214 -0
- package/src/services/adminTelemetry.ts +194 -0
- package/src/services/adminUser.ts +61 -9
- package/src/services/auth.ts +8 -2
- package/src/services/fees.ts +5 -1
- package/src/services/module.ts +29 -2
- package/src/services/visualization.ts +147 -0
- package/src/utils/sentryTrpc.ts +25 -0
- package/tests/unit/lib/fileUploadSession.test.ts +67 -0
- package/tests/unit/services/adminClass.test.ts +102 -0
- package/tests/unit/services/adminSpam.test.ts +108 -0
- package/tests/unit/services/adminSql.test.ts +56 -0
- package/tests/unit/services/adminTelemetry.test.ts +47 -0
- package/tests/unit/services/adminUser.test.ts +2 -0
- package/tests/unit/services/visualization.test.ts +130 -0
- package/tests/unit/utils/sentryTrpc.test.ts +15 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="952402d2-ba9b-50c7-b9c7-3bb46a71d8a6")}catch(e){}}();
|
|
3
|
+
import { TRPCError } from '@trpc/server';
|
|
4
|
+
import { prisma } from '../lib/prisma.js';
|
|
5
|
+
import { classifyUser } from './adminSpam.js';
|
|
6
|
+
export async function listClassesForAdmin(input) {
|
|
7
|
+
const skip = input.page * input.pageSize;
|
|
8
|
+
const filters = [];
|
|
9
|
+
const q = input.query?.trim();
|
|
10
|
+
if (q) {
|
|
11
|
+
filters.push({
|
|
12
|
+
OR: [
|
|
13
|
+
{ name: { contains: q, mode: 'insensitive' } },
|
|
14
|
+
{ subject: { contains: q, mode: 'insensitive' } },
|
|
15
|
+
{ section: { contains: q, mode: 'insensitive' } },
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (input.schoolId)
|
|
20
|
+
filters.push({ schoolId: input.schoolId });
|
|
21
|
+
if (input.membership === 'populated')
|
|
22
|
+
filters.push({ students: { some: {} } });
|
|
23
|
+
if (input.membership === 'empty')
|
|
24
|
+
filters.push({ students: { none: {} } });
|
|
25
|
+
const where = filters.length ? { AND: filters } : {};
|
|
26
|
+
const orderBy = input.sort === 'students'
|
|
27
|
+
? [{ students: { _count: 'desc' } }, { name: 'asc' }]
|
|
28
|
+
: input.sort === 'assignments'
|
|
29
|
+
? [{ assignments: { _count: 'desc' } }, { name: 'asc' }]
|
|
30
|
+
: [{ name: 'asc' }];
|
|
31
|
+
const [items, total] = await Promise.all([
|
|
32
|
+
prisma.class.findMany({
|
|
33
|
+
where,
|
|
34
|
+
orderBy,
|
|
35
|
+
skip,
|
|
36
|
+
take: input.pageSize,
|
|
37
|
+
select: {
|
|
38
|
+
id: true,
|
|
39
|
+
name: true,
|
|
40
|
+
subject: true,
|
|
41
|
+
section: true,
|
|
42
|
+
school: { select: { id: true, name: true } },
|
|
43
|
+
department: { select: { id: true, name: true } },
|
|
44
|
+
teachers: { select: { id: true, username: true }, take: 3 },
|
|
45
|
+
assignments: {
|
|
46
|
+
orderBy: { createdAt: 'desc' },
|
|
47
|
+
take: 1,
|
|
48
|
+
select: { createdAt: true },
|
|
49
|
+
},
|
|
50
|
+
_count: {
|
|
51
|
+
select: {
|
|
52
|
+
students: true,
|
|
53
|
+
teachers: true,
|
|
54
|
+
assignments: true,
|
|
55
|
+
announcements: true,
|
|
56
|
+
discussions: true,
|
|
57
|
+
worksheets: true,
|
|
58
|
+
events: true,
|
|
59
|
+
modules: true,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
prisma.class.count({ where }),
|
|
65
|
+
]);
|
|
66
|
+
return {
|
|
67
|
+
items: items.map(({ assignments, ...rest }) => ({
|
|
68
|
+
...rest,
|
|
69
|
+
lastAssignmentAt: assignments[0]?.createdAt ?? null,
|
|
70
|
+
})),
|
|
71
|
+
total,
|
|
72
|
+
page: input.page,
|
|
73
|
+
pageSize: input.pageSize,
|
|
74
|
+
pageCount: Math.max(1, Math.ceil(total / input.pageSize)),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const MEMBER_SELECT = {
|
|
78
|
+
id: true,
|
|
79
|
+
username: true,
|
|
80
|
+
email: true,
|
|
81
|
+
verified: true,
|
|
82
|
+
_count: { select: { teacherIn: true, studentIn: true, submissions: true } },
|
|
83
|
+
};
|
|
84
|
+
export async function getClassForAdmin(id) {
|
|
85
|
+
const cls = await prisma.class.findUnique({
|
|
86
|
+
where: { id },
|
|
87
|
+
select: {
|
|
88
|
+
id: true,
|
|
89
|
+
name: true,
|
|
90
|
+
subject: true,
|
|
91
|
+
section: true,
|
|
92
|
+
color: true,
|
|
93
|
+
school: { select: { id: true, name: true } },
|
|
94
|
+
department: { select: { id: true, name: true } },
|
|
95
|
+
teachers: { orderBy: { username: 'asc' }, select: MEMBER_SELECT },
|
|
96
|
+
students: {
|
|
97
|
+
orderBy: { username: 'asc' },
|
|
98
|
+
take: 200,
|
|
99
|
+
select: MEMBER_SELECT,
|
|
100
|
+
},
|
|
101
|
+
assignments: {
|
|
102
|
+
orderBy: { createdAt: 'desc' },
|
|
103
|
+
take: 20,
|
|
104
|
+
select: {
|
|
105
|
+
id: true,
|
|
106
|
+
title: true,
|
|
107
|
+
type: true,
|
|
108
|
+
graded: true,
|
|
109
|
+
dueDate: true,
|
|
110
|
+
createdAt: true,
|
|
111
|
+
teacher: { select: { id: true, username: true } },
|
|
112
|
+
_count: { select: { submissions: true } },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
announcements: {
|
|
116
|
+
orderBy: { createdAt: 'desc' },
|
|
117
|
+
take: 10,
|
|
118
|
+
select: {
|
|
119
|
+
id: true,
|
|
120
|
+
createdAt: true,
|
|
121
|
+
remarks: true,
|
|
122
|
+
teacher: { select: { id: true, username: true } },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
_count: {
|
|
126
|
+
select: {
|
|
127
|
+
students: true,
|
|
128
|
+
teachers: true,
|
|
129
|
+
assignments: true,
|
|
130
|
+
announcements: true,
|
|
131
|
+
discussions: true,
|
|
132
|
+
worksheets: true,
|
|
133
|
+
events: true,
|
|
134
|
+
modules: true,
|
|
135
|
+
sections: true,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
if (!cls) {
|
|
141
|
+
throw new TRPCError({ code: 'NOT_FOUND', message: 'Class not found' });
|
|
142
|
+
}
|
|
143
|
+
// Per-student submission counts scoped to this class, so a roster row shows
|
|
144
|
+
// engagement here rather than platform-wide totals.
|
|
145
|
+
const submissionsByStudent = await prisma.submission.groupBy({
|
|
146
|
+
by: ['studentId'],
|
|
147
|
+
where: { assignment: { classId: id } },
|
|
148
|
+
_count: { _all: true },
|
|
149
|
+
});
|
|
150
|
+
const submissionCount = new Map(submissionsByStudent.map((row) => [row.studentId, row._count._all]));
|
|
151
|
+
const withSignals = (user) => ({
|
|
152
|
+
...user,
|
|
153
|
+
signals: classifyUser(user),
|
|
154
|
+
submissionsInClass: submissionCount.get(user.id) ?? 0,
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
...cls,
|
|
158
|
+
teachers: cls.teachers.map(withSignals),
|
|
159
|
+
students: cls.students.map(withSignals),
|
|
160
|
+
announcements: cls.announcements.map((announcement) => ({
|
|
161
|
+
...announcement,
|
|
162
|
+
remarks: announcement.remarks.length > 160
|
|
163
|
+
? `${announcement.remarks.slice(0, 160)}…`
|
|
164
|
+
: announcement.remarks,
|
|
165
|
+
})),
|
|
166
|
+
suspectedMembers: [...cls.teachers, ...cls.students].filter((user) => classifyUser(user).suspected).length,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/** Classes a single user teaches or studies in, for the user detail page. */
|
|
170
|
+
export async function listClassesForUserForAdmin(userId) {
|
|
171
|
+
const select = {
|
|
172
|
+
id: true,
|
|
173
|
+
name: true,
|
|
174
|
+
subject: true,
|
|
175
|
+
section: true,
|
|
176
|
+
school: { select: { id: true, name: true } },
|
|
177
|
+
_count: { select: { students: true, assignments: true } },
|
|
178
|
+
};
|
|
179
|
+
const [teaching, enrolled] = await Promise.all([
|
|
180
|
+
prisma.class.findMany({
|
|
181
|
+
where: { teachers: { some: { id: userId } } },
|
|
182
|
+
orderBy: { name: 'asc' },
|
|
183
|
+
take: 100,
|
|
184
|
+
select,
|
|
185
|
+
}),
|
|
186
|
+
prisma.class.findMany({
|
|
187
|
+
where: { students: { some: { id: userId } } },
|
|
188
|
+
orderBy: { name: 'asc' },
|
|
189
|
+
take: 100,
|
|
190
|
+
select,
|
|
191
|
+
}),
|
|
192
|
+
]);
|
|
193
|
+
return { teaching, enrolled };
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=adminClass.js.map
|
|
196
|
+
//# debugId=952402d2-ba9b-50c7-b9c7-3bb46a71d8a6
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adminClass.js","sources":["services/adminClass.ts"],"sourceRoot":"/","sourcesContent":["import type { Prisma } from '@prisma/client';\nimport { TRPCError } from '@trpc/server';\nimport { prisma } from '../lib/prisma.js';\nimport { classifyUser } from './adminSpam.js';\n\nexport type AdminClassMembership = 'all' | 'populated' | 'empty';\nexport type AdminClassSort = 'name' | 'students' | 'assignments';\n\nexport async function listClassesForAdmin(input: {\n page: number;\n pageSize: number;\n query?: string;\n schoolId?: string;\n membership?: AdminClassMembership;\n sort?: AdminClassSort;\n}) {\n const skip = input.page * input.pageSize;\n const filters: Prisma.ClassWhereInput[] = [];\n\n const q = input.query?.trim();\n if (q) {\n filters.push({\n OR: [\n { name: { contains: q, mode: 'insensitive' } },\n { subject: { contains: q, mode: 'insensitive' } },\n { section: { contains: q, mode: 'insensitive' } },\n ],\n });\n }\n\n if (input.schoolId) filters.push({ schoolId: input.schoolId });\n if (input.membership === 'populated') filters.push({ students: { some: {} } });\n if (input.membership === 'empty') filters.push({ students: { none: {} } });\n\n const where: Prisma.ClassWhereInput = filters.length ? { AND: filters } : {};\n\n const orderBy: Prisma.ClassOrderByWithRelationInput[] =\n input.sort === 'students'\n ? [{ students: { _count: 'desc' } }, { name: 'asc' }]\n : input.sort === 'assignments'\n ? [{ assignments: { _count: 'desc' } }, { name: 'asc' }]\n : [{ name: 'asc' }];\n\n const [items, total] = await Promise.all([\n prisma.class.findMany({\n where,\n orderBy,\n skip,\n take: input.pageSize,\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n school: { select: { id: true, name: true } },\n department: { select: { id: true, name: true } },\n teachers: { select: { id: true, username: true }, take: 3 },\n assignments: {\n orderBy: { createdAt: 'desc' },\n take: 1,\n select: { createdAt: true },\n },\n _count: {\n select: {\n students: true,\n teachers: true,\n assignments: true,\n announcements: true,\n discussions: true,\n worksheets: true,\n events: true,\n modules: true,\n },\n },\n },\n }),\n prisma.class.count({ where }),\n ]);\n\n return {\n items: items.map(({ assignments, ...rest }) => ({\n ...rest,\n lastAssignmentAt: assignments[0]?.createdAt ?? null,\n })),\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n\nconst MEMBER_SELECT = {\n id: true,\n username: true,\n email: true,\n verified: true,\n _count: { select: { teacherIn: true, studentIn: true, submissions: true } },\n} satisfies Prisma.UserSelect;\n\nexport async function getClassForAdmin(id: string) {\n const cls = await prisma.class.findUnique({\n where: { id },\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n color: true,\n school: { select: { id: true, name: true } },\n department: { select: { id: true, name: true } },\n teachers: { orderBy: { username: 'asc' }, select: MEMBER_SELECT },\n students: {\n orderBy: { username: 'asc' },\n take: 200,\n select: MEMBER_SELECT,\n },\n assignments: {\n orderBy: { createdAt: 'desc' },\n take: 20,\n select: {\n id: true,\n title: true,\n type: true,\n graded: true,\n dueDate: true,\n createdAt: true,\n teacher: { select: { id: true, username: true } },\n _count: { select: { submissions: true } },\n },\n },\n announcements: {\n orderBy: { createdAt: 'desc' },\n take: 10,\n select: {\n id: true,\n createdAt: true,\n remarks: true,\n teacher: { select: { id: true, username: true } },\n },\n },\n _count: {\n select: {\n students: true,\n teachers: true,\n assignments: true,\n announcements: true,\n discussions: true,\n worksheets: true,\n events: true,\n modules: true,\n sections: true,\n },\n },\n },\n });\n\n if (!cls) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'Class not found' });\n }\n\n // Per-student submission counts scoped to this class, so a roster row shows\n // engagement here rather than platform-wide totals.\n const submissionsByStudent = await prisma.submission.groupBy({\n by: ['studentId'],\n where: { assignment: { classId: id } },\n _count: { _all: true },\n });\n const submissionCount = new Map(\n submissionsByStudent.map((row) => [row.studentId, row._count._all]),\n );\n\n const withSignals = (user: (typeof cls.students)[number]) => ({\n ...user,\n signals: classifyUser(user),\n submissionsInClass: submissionCount.get(user.id) ?? 0,\n });\n\n return {\n ...cls,\n teachers: cls.teachers.map(withSignals),\n students: cls.students.map(withSignals),\n announcements: cls.announcements.map((announcement) => ({\n ...announcement,\n remarks:\n announcement.remarks.length > 160\n ? `${announcement.remarks.slice(0, 160)}…`\n : announcement.remarks,\n })),\n suspectedMembers: [...cls.teachers, ...cls.students].filter(\n (user) => classifyUser(user).suspected,\n ).length,\n };\n}\n\n/** Classes a single user teaches or studies in, for the user detail page. */\nexport async function listClassesForUserForAdmin(userId: string) {\n const select = {\n id: true,\n name: true,\n subject: true,\n section: true,\n school: { select: { id: true, name: true } },\n _count: { select: { students: true, assignments: true } },\n } satisfies Prisma.ClassSelect;\n\n const [teaching, enrolled] = await Promise.all([\n prisma.class.findMany({\n where: { teachers: { some: { id: userId } } },\n orderBy: { name: 'asc' },\n take: 100,\n select,\n }),\n prisma.class.findMany({\n where: { students: { some: { id: userId } } },\n orderBy: { name: 'asc' },\n take: 100,\n select,\n }),\n ]);\n\n return { teaching, enrolled };\n}\n"],"names":[],"mappings":"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","debug_id":"952402d2-ba9b-50c7-b9c7-3bb46a71d8a6"}
|
|
@@ -112,6 +112,7 @@ export declare function listSchoolDevelopmentProgramsForAdmin(input: {
|
|
|
112
112
|
query?: string;
|
|
113
113
|
}): Promise<{
|
|
114
114
|
items: {
|
|
115
|
+
signals: import("./adminSpam.js").SpamSignals;
|
|
115
116
|
type: string;
|
|
116
117
|
status: string;
|
|
117
118
|
id: string;
|
|
@@ -142,6 +143,7 @@ export declare function listEarlyAccessRequestsForAdmin(input: {
|
|
|
142
143
|
pageSize: number;
|
|
143
144
|
}): Promise<{
|
|
144
145
|
items: {
|
|
146
|
+
signals: import("./adminSpam.js").SpamSignals;
|
|
145
147
|
id: string;
|
|
146
148
|
createdAt: Date;
|
|
147
149
|
email: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminInstitution.d.ts","sourceRoot":"/","sources":["services/adminInstitution.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"adminInstitution.d.ts","sourceRoot":"/","sources":["services/adminInstitution.ts"],"names":[],"mappings":"AAKA,wBAAsB,mBAAmB,CAAC,KAAK,EAAE;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;;;;;;;;;;;;;;;;;;;;;GAsCA;AAED,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDjD;AAED,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;;;;;;;;;;;;;;;;;;;;;;;;GA0BA;AAED,wBAAsB,qCAAqC,CAAC,KAAK,EAAE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCA;AAED,wBAAsB,+BAA+B,CAAC,KAAK,EAAE;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;;;;;;;;;;;;GAsBA"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="561863c5-04b0-50db-928f-4d6ba72bd149")}catch(e){}}();
|
|
3
3
|
import { TRPCError } from '@trpc/server';
|
|
4
4
|
import { prisma } from '../lib/prisma.js';
|
|
5
|
+
import { classifyEmail } from './adminSpam.js';
|
|
5
6
|
export async function listSchoolsForAdmin(input) {
|
|
6
7
|
const skip = input.page * input.pageSize;
|
|
7
8
|
const where = {};
|
|
@@ -138,7 +139,10 @@ export async function listSchoolDevelopmentProgramsForAdmin(input) {
|
|
|
138
139
|
prisma.schoolDevelopementProgram.count({ where }),
|
|
139
140
|
]);
|
|
140
141
|
return {
|
|
141
|
-
items
|
|
142
|
+
items: items.map((item) => ({
|
|
143
|
+
...item,
|
|
144
|
+
signals: classifyEmail(item.contactEmail),
|
|
145
|
+
})),
|
|
142
146
|
total,
|
|
143
147
|
page: input.page,
|
|
144
148
|
pageSize: input.pageSize,
|
|
@@ -156,7 +160,10 @@ export async function listEarlyAccessRequestsForAdmin(input) {
|
|
|
156
160
|
prisma.earlyAccessRequest.count(),
|
|
157
161
|
]);
|
|
158
162
|
return {
|
|
159
|
-
items
|
|
163
|
+
items: items.map((item) => ({
|
|
164
|
+
...item,
|
|
165
|
+
signals: classifyEmail(item.email),
|
|
166
|
+
})),
|
|
160
167
|
total,
|
|
161
168
|
page: input.page,
|
|
162
169
|
pageSize: input.pageSize,
|
|
@@ -164,4 +171,4 @@ export async function listEarlyAccessRequestsForAdmin(input) {
|
|
|
164
171
|
};
|
|
165
172
|
}
|
|
166
173
|
//# sourceMappingURL=adminInstitution.js.map
|
|
167
|
-
//# debugId=
|
|
174
|
+
//# debugId=561863c5-04b0-50db-928f-4d6ba72bd149
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminInstitution.js","sources":["services/adminInstitution.ts"],"sourceRoot":"/","sourcesContent":["import type { Prisma } from '@prisma/client';\nimport { TRPCError } from '@trpc/server';\nimport { prisma } from '../lib/prisma.js';\n\nexport async function listSchoolsForAdmin(input: {\n page: number;\n pageSize: number;\n query?: string;\n}) {\n const skip = input.page * input.pageSize;\n const where: Prisma.SchoolWhereInput = {};\n const q = input.query?.trim();\n if (q) {\n where.OR = [\n { name: { contains: q, mode: 'insensitive' } },\n { subdomain: { contains: q, mode: 'insensitive' } },\n { description: { contains: q, mode: 'insensitive' } },\n ];\n }\n\n const [items, total] = await Promise.all([\n prisma.school.findMany({\n where,\n orderBy: { createdAt: 'desc' },\n skip,\n take: input.pageSize,\n include: {\n _count: {\n select: {\n memberships: true,\n classes: true,\n departments: true,\n },\n },\n },\n }),\n prisma.school.count({ where }),\n ]);\n\n return {\n items,\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n\nexport async function getSchoolForAdmin(id: string) {\n const school = await prisma.school.findUnique({\n where: { id },\n include: {\n _count: {\n select: { memberships: true, classes: true, departments: true },\n },\n memberships: {\n orderBy: { createdAt: 'desc' },\n take: 100,\n select: {\n id: true,\n role: true,\n status: true,\n createdAt: true,\n user: {\n select: { id: true, username: true, email: true, verified: true },\n },\n },\n },\n classes: {\n orderBy: { name: 'asc' },\n take: 100,\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n color: true,\n department: { select: { id: true, name: true } },\n _count: { select: { students: true, teachers: true } },\n },\n },\n departments: {\n orderBy: { name: 'asc' },\n select: {\n id: true,\n name: true,\n color: true,\n _count: { select: { classes: true, members: true } },\n },\n },\n },\n });\n\n if (!school) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'School not found' });\n }\n return school;\n}\n\nexport async function listDepartmentsForAdmin(input: {\n page: number;\n pageSize: number;\n schoolId?: string;\n}) {\n const skip = input.page * input.pageSize;\n const where: Prisma.DepartmentWhereInput = {};\n if (input.schoolId) where.schoolId = input.schoolId;\n\n const [items, total] = await Promise.all([\n prisma.department.findMany({\n where,\n orderBy: [{ schoolId: 'asc' }, { name: 'asc' }],\n skip,\n take: input.pageSize,\n include: {\n school: { select: { id: true, name: true, subdomain: true } },\n _count: { select: { classes: true, members: true } },\n },\n }),\n prisma.department.count({ where }),\n ]);\n\n return {\n items,\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n\nexport async function listSchoolDevelopmentProgramsForAdmin(input: {\n page: number;\n pageSize: number;\n status?: string;\n query?: string;\n}) {\n const skip = input.page * input.pageSize;\n const where: Prisma.SchoolDevelopementProgramWhereInput = {};\n if (input.status?.trim()) where.status = input.status.trim();\n const q = input.query?.trim();\n if (q) {\n where.OR = [\n { name: { contains: q, mode: 'insensitive' } },\n { city: { contains: q, mode: 'insensitive' } },\n { country: { contains: q, mode: 'insensitive' } },\n { contactEmail: { contains: q, mode: 'insensitive' } },\n ];\n }\n\n const [items, total] = await Promise.all([\n prisma.schoolDevelopementProgram.findMany({\n where,\n orderBy: { submittedAt: 'desc' },\n skip,\n take: input.pageSize,\n }),\n prisma.schoolDevelopementProgram.count({ where }),\n ]);\n\n return {\n items,\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n\nexport async function listEarlyAccessRequestsForAdmin(input: {\n page: number;\n pageSize: number;\n}) {\n const skip = input.page * input.pageSize;\n\n const [items, total] = await Promise.all([\n prisma.earlyAccessRequest.findMany({\n orderBy: { createdAt: 'desc' },\n skip,\n take: input.pageSize,\n }),\n prisma.earlyAccessRequest.count(),\n ]);\n\n return {\n items,\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n"],"names":[],"mappings":"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","debug_id":"5c27592b-412d-5c1e-8999-32503baea449"}
|
|
1
|
+
{"version":3,"file":"adminInstitution.js","sources":["services/adminInstitution.ts"],"sourceRoot":"/","sourcesContent":["import type { Prisma } from '@prisma/client';\nimport { TRPCError } from '@trpc/server';\nimport { prisma } from '../lib/prisma.js';\nimport { classifyEmail } from './adminSpam.js';\n\nexport async function listSchoolsForAdmin(input: {\n page: number;\n pageSize: number;\n query?: string;\n}) {\n const skip = input.page * input.pageSize;\n const where: Prisma.SchoolWhereInput = {};\n const q = input.query?.trim();\n if (q) {\n where.OR = [\n { name: { contains: q, mode: 'insensitive' } },\n { subdomain: { contains: q, mode: 'insensitive' } },\n { description: { contains: q, mode: 'insensitive' } },\n ];\n }\n\n const [items, total] = await Promise.all([\n prisma.school.findMany({\n where,\n orderBy: { createdAt: 'desc' },\n skip,\n take: input.pageSize,\n include: {\n _count: {\n select: {\n memberships: true,\n classes: true,\n departments: true,\n },\n },\n },\n }),\n prisma.school.count({ where }),\n ]);\n\n return {\n items,\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n\nexport async function getSchoolForAdmin(id: string) {\n const school = await prisma.school.findUnique({\n where: { id },\n include: {\n _count: {\n select: { memberships: true, classes: true, departments: true },\n },\n memberships: {\n orderBy: { createdAt: 'desc' },\n take: 100,\n select: {\n id: true,\n role: true,\n status: true,\n createdAt: true,\n user: {\n select: { id: true, username: true, email: true, verified: true },\n },\n },\n },\n classes: {\n orderBy: { name: 'asc' },\n take: 100,\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n color: true,\n department: { select: { id: true, name: true } },\n _count: { select: { students: true, teachers: true } },\n },\n },\n departments: {\n orderBy: { name: 'asc' },\n select: {\n id: true,\n name: true,\n color: true,\n _count: { select: { classes: true, members: true } },\n },\n },\n },\n });\n\n if (!school) {\n throw new TRPCError({ code: 'NOT_FOUND', message: 'School not found' });\n }\n return school;\n}\n\nexport async function listDepartmentsForAdmin(input: {\n page: number;\n pageSize: number;\n schoolId?: string;\n}) {\n const skip = input.page * input.pageSize;\n const where: Prisma.DepartmentWhereInput = {};\n if (input.schoolId) where.schoolId = input.schoolId;\n\n const [items, total] = await Promise.all([\n prisma.department.findMany({\n where,\n orderBy: [{ schoolId: 'asc' }, { name: 'asc' }],\n skip,\n take: input.pageSize,\n include: {\n school: { select: { id: true, name: true, subdomain: true } },\n _count: { select: { classes: true, members: true } },\n },\n }),\n prisma.department.count({ where }),\n ]);\n\n return {\n items,\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n\nexport async function listSchoolDevelopmentProgramsForAdmin(input: {\n page: number;\n pageSize: number;\n status?: string;\n query?: string;\n}) {\n const skip = input.page * input.pageSize;\n const where: Prisma.SchoolDevelopementProgramWhereInput = {};\n if (input.status?.trim()) where.status = input.status.trim();\n const q = input.query?.trim();\n if (q) {\n where.OR = [\n { name: { contains: q, mode: 'insensitive' } },\n { city: { contains: q, mode: 'insensitive' } },\n { country: { contains: q, mode: 'insensitive' } },\n { contactEmail: { contains: q, mode: 'insensitive' } },\n ];\n }\n\n const [items, total] = await Promise.all([\n prisma.schoolDevelopementProgram.findMany({\n where,\n orderBy: { submittedAt: 'desc' },\n skip,\n take: input.pageSize,\n }),\n prisma.schoolDevelopementProgram.count({ where }),\n ]);\n\n return {\n items: items.map((item) => ({\n ...item,\n signals: classifyEmail(item.contactEmail),\n })),\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n\nexport async function listEarlyAccessRequestsForAdmin(input: {\n page: number;\n pageSize: number;\n}) {\n const skip = input.page * input.pageSize;\n\n const [items, total] = await Promise.all([\n prisma.earlyAccessRequest.findMany({\n orderBy: { createdAt: 'desc' },\n skip,\n take: input.pageSize,\n }),\n prisma.earlyAccessRequest.count(),\n ]);\n\n return {\n items: items.map((item) => ({\n ...item,\n signals: classifyEmail(item.email),\n })),\n total,\n page: input.page,\n pageSize: input.pageSize,\n pageCount: Math.max(1, Math.ceil(total / input.pageSize)),\n };\n}\n"],"names":[],"mappings":"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","debug_id":"561863c5-04b0-50db-928f-4d6ba72bd149"}
|
|
@@ -2,6 +2,14 @@ export declare function getOverviewMetricsForAdmin(): Promise<{
|
|
|
2
2
|
schools: number;
|
|
3
3
|
users: number;
|
|
4
4
|
verifiedUsers: number;
|
|
5
|
+
suspectedUsers: number;
|
|
6
|
+
cleanUsers: number;
|
|
7
|
+
signupsLast24h: number;
|
|
8
|
+
signupsLast7d: number;
|
|
9
|
+
activeUsersLast24h: number;
|
|
10
|
+
activeUsersLast7d: number;
|
|
11
|
+
activeClassesLast7d: number;
|
|
12
|
+
submissionsLast24h: number;
|
|
5
13
|
classes: number;
|
|
6
14
|
departments: number;
|
|
7
15
|
runJobs: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminMetrics.d.ts","sourceRoot":"/","sources":["services/adminMetrics.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"adminMetrics.d.ts","sourceRoot":"/","sources":["services/adminMetrics.ts"],"names":[],"mappings":"AAWA,wBAAsB,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;GAqE/C"}
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="dc189276-d8bc-50e0-8846-5b673df29328")}catch(e){}}();
|
|
3
3
|
import { prisma } from '../lib/prisma.js';
|
|
4
|
+
import { suspectedUserWhere } from './adminSpam.js';
|
|
5
|
+
async function countActiveUsersSince(since) {
|
|
6
|
+
const rows = await prisma.session.groupBy({
|
|
7
|
+
by: ['userId'],
|
|
8
|
+
where: { type: 'AUTH', createdAt: { gte: since }, userId: { not: null } },
|
|
9
|
+
});
|
|
10
|
+
return rows.length;
|
|
11
|
+
}
|
|
4
12
|
export async function getOverviewMetricsForAdmin() {
|
|
5
13
|
const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
|
6
|
-
const
|
|
14
|
+
const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
|
15
|
+
const suspected = suspectedUserWhere();
|
|
16
|
+
const [schools, users, verifiedUsers, suspectedUsers, signupsLast24h, signupsLast7d, activeUsersLast24h, activeUsersLast7d, classes, activeClassesLast7d, submissionsLast24h, departments, runJobsByStatus, failedRunJobsLast24h, earlyAccessRequests, pendingDevProgramApplications,] = await Promise.all([
|
|
7
17
|
prisma.school.count(),
|
|
8
18
|
prisma.user.count(),
|
|
9
19
|
prisma.user.count({ where: { verified: true } }),
|
|
20
|
+
prisma.user.count({ where: suspected }),
|
|
21
|
+
prisma.userProfile.count({ where: { createdAt: { gte: dayAgo } } }),
|
|
22
|
+
prisma.userProfile.count({ where: { createdAt: { gte: weekAgo } } }),
|
|
23
|
+
countActiveUsersSince(dayAgo),
|
|
24
|
+
countActiveUsersSince(weekAgo),
|
|
10
25
|
prisma.class.count(),
|
|
26
|
+
prisma.class.count({
|
|
27
|
+
where: { assignments: { some: { createdAt: { gte: weekAgo } } } },
|
|
28
|
+
}),
|
|
29
|
+
prisma.submission.count({ where: { submittedAt: { gte: dayAgo } } }),
|
|
11
30
|
prisma.department.count(),
|
|
12
31
|
prisma.runJob.groupBy({ by: ['status'], _count: { _all: true } }),
|
|
13
32
|
prisma.runJob.count({
|
|
@@ -20,6 +39,14 @@ export async function getOverviewMetricsForAdmin() {
|
|
|
20
39
|
schools,
|
|
21
40
|
users,
|
|
22
41
|
verifiedUsers,
|
|
42
|
+
suspectedUsers,
|
|
43
|
+
cleanUsers: users - suspectedUsers,
|
|
44
|
+
signupsLast24h,
|
|
45
|
+
signupsLast7d,
|
|
46
|
+
activeUsersLast24h,
|
|
47
|
+
activeUsersLast7d,
|
|
48
|
+
activeClassesLast7d,
|
|
49
|
+
submissionsLast24h,
|
|
23
50
|
classes,
|
|
24
51
|
departments,
|
|
25
52
|
runJobs: {
|
|
@@ -34,4 +61,4 @@ export async function getOverviewMetricsForAdmin() {
|
|
|
34
61
|
};
|
|
35
62
|
}
|
|
36
63
|
//# sourceMappingURL=adminMetrics.js.map
|
|
37
|
-
//# debugId=
|
|
64
|
+
//# debugId=dc189276-d8bc-50e0-8846-5b673df29328
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminMetrics.js","sources":["services/adminMetrics.ts"],"sourceRoot":"/","sourcesContent":["import { prisma } from '../lib/prisma.js';\n\nexport async function getOverviewMetricsForAdmin() {\n const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n\n const [\n schools,\n users,\n verifiedUsers,\n classes,\n departments,\n runJobsByStatus,\n failedRunJobsLast24h,\n earlyAccessRequests,\n pendingDevProgramApplications,\n ] = await Promise.all([\n prisma.school.count(),\n prisma.user.count(),\n prisma.user.count({ where: { verified: true } }),\n prisma.class.count(),\n prisma.department.count(),\n prisma.runJob.groupBy({ by: ['status'], _count: { _all: true } }),\n prisma.runJob.count({\n where: { status: 'FAILED', createdAt: { gte: dayAgo } },\n }),\n prisma.earlyAccessRequest.count(),\n prisma.schoolDevelopementProgram.count({ where: { status: 'PENDING' } }),\n ]);\n\n return {\n schools,\n users,\n verifiedUsers,\n classes,\n departments,\n runJobs: {\n byStatus: runJobsByStatus.map((row) => ({\n status: row.status,\n count: row._count._all,\n })),\n failedLast24h: failedRunJobsLast24h,\n },\n earlyAccessRequests,\n pendingDevProgramApplications,\n };\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"adminMetrics.js","sources":["services/adminMetrics.ts"],"sourceRoot":"/","sourcesContent":["import { prisma } from '../lib/prisma.js';\nimport { suspectedUserWhere } from './adminSpam.js';\n\nasync function countActiveUsersSince(since: Date) {\n const rows = await prisma.session.groupBy({\n by: ['userId'],\n where: { type: 'AUTH', createdAt: { gte: since }, userId: { not: null } },\n });\n return rows.length;\n}\n\nexport async function getOverviewMetricsForAdmin() {\n const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);\n const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);\n const suspected = suspectedUserWhere();\n\n const [\n schools,\n users,\n verifiedUsers,\n suspectedUsers,\n signupsLast24h,\n signupsLast7d,\n activeUsersLast24h,\n activeUsersLast7d,\n classes,\n activeClassesLast7d,\n submissionsLast24h,\n departments,\n runJobsByStatus,\n failedRunJobsLast24h,\n earlyAccessRequests,\n pendingDevProgramApplications,\n ] = await Promise.all([\n prisma.school.count(),\n prisma.user.count(),\n prisma.user.count({ where: { verified: true } }),\n prisma.user.count({ where: suspected }),\n prisma.userProfile.count({ where: { createdAt: { gte: dayAgo } } }),\n prisma.userProfile.count({ where: { createdAt: { gte: weekAgo } } }),\n countActiveUsersSince(dayAgo),\n countActiveUsersSince(weekAgo),\n prisma.class.count(),\n prisma.class.count({\n where: { assignments: { some: { createdAt: { gte: weekAgo } } } },\n }),\n prisma.submission.count({ where: { submittedAt: { gte: dayAgo } } }),\n prisma.department.count(),\n prisma.runJob.groupBy({ by: ['status'], _count: { _all: true } }),\n prisma.runJob.count({\n where: { status: 'FAILED', createdAt: { gte: dayAgo } },\n }),\n prisma.earlyAccessRequest.count(),\n prisma.schoolDevelopementProgram.count({ where: { status: 'PENDING' } }),\n ]);\n\n return {\n schools,\n users,\n verifiedUsers,\n suspectedUsers,\n cleanUsers: users - suspectedUsers,\n signupsLast24h,\n signupsLast7d,\n activeUsersLast24h,\n activeUsersLast7d,\n activeClassesLast7d,\n submissionsLast24h,\n classes,\n departments,\n runJobs: {\n byStatus: runJobsByStatus.map((row) => ({\n status: row.status,\n count: row._count._all,\n })),\n failedLast24h: failedRunJobsLast24h,\n },\n earlyAccessRequests,\n pendingDevProgramApplications,\n };\n}\n"],"names":[],"mappings":"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","debug_id":"dc189276-d8bc-50e0-8846-5b673df29328"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Prisma } from '@prisma/client';
|
|
2
|
+
export type SpamReason = 'BLOCKED_DOMAIN' | 'BOT_PATTERN' | 'DISPOSABLE_DOMAIN' | 'NEVER_VERIFIED_INACTIVE';
|
|
3
|
+
export type SpamSignals = {
|
|
4
|
+
suspected: boolean;
|
|
5
|
+
reasons: SpamReason[];
|
|
6
|
+
};
|
|
7
|
+
export declare function spamRules(): {
|
|
8
|
+
blockedDomains: string[];
|
|
9
|
+
botPatterns: string[];
|
|
10
|
+
disposableDomains: string[];
|
|
11
|
+
};
|
|
12
|
+
export type ClassifiableUser = {
|
|
13
|
+
username: string;
|
|
14
|
+
email: string;
|
|
15
|
+
verified: boolean;
|
|
16
|
+
_count?: {
|
|
17
|
+
teacherIn: number;
|
|
18
|
+
studentIn: number;
|
|
19
|
+
submissions?: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export declare function classifyEmail(email: string | null | undefined, username?: string | null): SpamSignals;
|
|
23
|
+
export declare function classifyUser(user: ClassifiableUser): SpamSignals;
|
|
24
|
+
/**
|
|
25
|
+
* Prisma filter matching the rule-based part of {@link classifyUser}. The
|
|
26
|
+
* `NEVER_VERIFIED_INACTIVE` reason is intentionally excluded: brand new real
|
|
27
|
+
* signups look identical to it, so it only annotates rows and never drives
|
|
28
|
+
* list filtering or counts.
|
|
29
|
+
*/
|
|
30
|
+
export declare function suspectedUserWhere(): Prisma.UserWhereInput;
|
|
31
|
+
export declare function notSuspectedUserWhere(): Prisma.UserWhereInput;
|
|
32
|
+
export declare function countSuspectedUsers(): Promise<number>;
|
|
33
|
+
export declare function listUserEmailDomainsForAdmin(input: {
|
|
34
|
+
limit: number;
|
|
35
|
+
suspectedOnly: boolean;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
items: {
|
|
38
|
+
domain: string;
|
|
39
|
+
total: number;
|
|
40
|
+
verified: number;
|
|
41
|
+
suspected: boolean;
|
|
42
|
+
}[];
|
|
43
|
+
}>;
|
|
44
|
+
export declare function getSpamOverviewForAdmin(): Promise<{
|
|
45
|
+
rules: {
|
|
46
|
+
blockedDomains: string[];
|
|
47
|
+
botPatterns: string[];
|
|
48
|
+
disposableDomains: string[];
|
|
49
|
+
};
|
|
50
|
+
totalUsers: number;
|
|
51
|
+
suspectedUsers: number;
|
|
52
|
+
suspectedVerified: number;
|
|
53
|
+
cleanUsers: number;
|
|
54
|
+
domains: {
|
|
55
|
+
domain: string;
|
|
56
|
+
total: number;
|
|
57
|
+
verified: number;
|
|
58
|
+
suspected: boolean;
|
|
59
|
+
}[];
|
|
60
|
+
recent: {
|
|
61
|
+
signals: SpamSignals;
|
|
62
|
+
id: string;
|
|
63
|
+
username: string;
|
|
64
|
+
email: string;
|
|
65
|
+
verified: boolean;
|
|
66
|
+
profile: {
|
|
67
|
+
createdAt: Date;
|
|
68
|
+
} | null;
|
|
69
|
+
_count: {
|
|
70
|
+
teacherIn: number;
|
|
71
|
+
studentIn: number;
|
|
72
|
+
submissions: number;
|
|
73
|
+
};
|
|
74
|
+
}[];
|
|
75
|
+
}>;
|
|
76
|
+
//# sourceMappingURL=adminSpam.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adminSpam.d.ts","sourceRoot":"/","sources":["services/adminSpam.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAG7C,MAAM,MAAM,UAAU,GAClB,gBAAgB,GAChB,aAAa,GACb,mBAAmB,GACnB,yBAAyB,CAAC;AAE9B,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB,CAAC;AA4BF,wBAAgB,SAAS;;;;EASxB;AAWD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzE,CAAC;AAEF,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,WAAW,CAwBb;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,WAAW,CAchE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,cAAc,CAkB1D;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,cAAc,CAE7D;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE3D;AAID,wBAAsB,4BAA4B,CAAC,KAAK,EAAE;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;CACxB;;;;;;;GA4BA;AAED,wBAAsB,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0C5C"}
|