diff --git a/package-lock.json b/package-lock.json index f6c020c..626ab37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -984,7 +984,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -3028,7 +3027,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -3050,7 +3048,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.2.0.tgz", "integrity": "sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ==", "license": "Apache-2.0", - "peer": true, "engines": { "node": "^18.19.0 || >=20.6.0" }, @@ -3063,7 +3060,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -3079,7 +3075,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.208.0.tgz", "integrity": "sha512-Eju0L4qWcQS+oXxi6pgh7zvE2byogAkcsVv0OjHF/97iOz1N/aKE6etSGowYkie+YA1uo6DNwdSxaaNnLvcRlA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/api-logs": "0.208.0", "import-in-the-middle": "^2.0.0", @@ -3467,7 +3462,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/semantic-conventions": "^1.29.0" @@ -3484,7 +3478,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", @@ -3502,7 +3495,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.38.0.tgz", "integrity": "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=14" } @@ -5309,7 +5301,6 @@ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.47.0.tgz", "integrity": "sha512-mznN01MBXtr4T7X/E3ENkhF6GzqxTxL6/whG3OzCzUu8G8KYRNiCdoxLMVWAHJx/mDMPP3XAeKCMZHF/Xd/CDw==", "license": "MIT", - "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", @@ -5348,7 +5339,6 @@ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.1.tgz", "integrity": "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==", "license": "MIT", - "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "debug": "^4.4.1", @@ -5855,7 +5845,6 @@ "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", @@ -6111,7 +6100,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6388,7 +6376,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -7002,7 +6989,6 @@ "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -7099,7 +7085,6 @@ "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9399,7 +9384,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", @@ -9521,7 +9505,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -9694,7 +9677,6 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -9711,7 +9693,6 @@ "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" @@ -10017,7 +9998,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -10595,7 +10575,6 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.40.1.tgz", "integrity": "sha512-0R3t2oiLxJNJb2buz61MNfPdkjeyj2qTCM7TtIv/4ZfF12zD7Ig8iIo+C8febroy+9S4QJ7qfijtearSdO/1ww==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -10688,8 +10667,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tapable": { "version": "2.3.0", @@ -10854,7 +10832,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10913,7 +10890,6 @@ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.21.tgz", "integrity": "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==", "license": "MIT", - "peer": true, "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", @@ -11064,7 +11040,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -11640,7 +11615,6 @@ "integrity": "sha512-HwaJmXO3M1r4S8x2ea2vy8Rw/y/38HRQuK/gNDRQ7w9cJXn6xSl1sIIqKCffULSUjul3wV3I3Nd/GfbmsRReEA==", "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "bin": { "workerd": "bin/workerd" }, diff --git a/src/lib/utils.ts b/src/lib/utils.ts index d3d0eef..046ed1e 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -78,3 +78,14 @@ export function calculateMarketPrice( return Math.round(-m * shopScoreRemainder + maxPrice); } } + +export function getProjectLinkType( + editorFileType: string | null, + editorUrl: string | null, + uploadedFileUrl: string | null +): string { + if (editorFileType === 'url' && editorUrl?.includes('cad.onshape.com')) return 'onshape'; + if (editorFileType === 'url' && editorUrl?.includes('autodesk360.com')) return 'fusion-link'; + if (editorFileType === 'upload' && uploadedFileUrl?.endsWith('.f3d')) return 'fusion-file'; + return 'unknown'; +} diff --git a/src/routes/dashboard/admin/admin/users/[id]/+page.server.ts b/src/routes/dashboard/admin/admin/users/[id]/+page.server.ts index a83e6f3..a2f6901 100644 --- a/src/routes/dashboard/admin/admin/users/[id]/+page.server.ts +++ b/src/routes/dashboard/admin/admin/users/[id]/+page.server.ts @@ -214,6 +214,50 @@ export const actions = { }; }, + changeTrust: async ({ locals, request, params }) => { + if (!locals.user) { + throw error(500); + } + if (!locals.user.hasAdmin) { + throw error(403, { message: 'oi get out' }); + } + + const id: number = parseInt(params.id); + + const data = await request.formData(); + const trust = data.get('trust'); + + if (!trust || !['green', 'blue', 'yellow', 'red'].includes(trust.toString())) { + return fail(400, { + changeTrust: { + invalidTrust: true + } + }); + } + + // Log out user if trust is set to red + if (trust === 'red') { + await db.delete(session).where(eq(session.userId, id)); + } + + await db + .update(user) + .set({ + trust: trust.toString() as 'green' | 'blue' | 'yellow' | 'red' + }) + .where(eq(user.id, id)); + + const [queriedUser] = await db.select().from(user).where(eq(user.id, id)); + + if (!queriedUser) { + throw error(404, { message: 'user not found' }); + } + + return { + queriedUser + }; + }, + impersonate: async (event) => { const { locals, params } = event; diff --git a/src/routes/dashboard/admin/admin/users/[id]/+page.svelte b/src/routes/dashboard/admin/admin/users/[id]/+page.svelte index bc69958..3e49332 100644 --- a/src/routes/dashboard/admin/admin/users/[id]/+page.svelte +++ b/src/routes/dashboard/admin/admin/users/[id]/+page.svelte @@ -14,6 +14,7 @@ let impersonatePending = $state(false); let logoutPending = $state(false); let fetchPIIPending = $state(false); + let changeTrustPending = $state(false); @@ -239,6 +240,37 @@ +

Trust Level

+
+
{ + changeTrustPending = true; + return async ({ update }) => { + await update({ reset: false }); + changeTrustPending = false; + }; + }} + > + + {#if form?.changeTrust?.invalidTrust} +

Invalid trust level

+ {/if} + +
+
+

yummy stuff

{#if form?.fetchPII?.success} diff --git a/src/routes/dashboard/admin/review/+page.server.ts b/src/routes/dashboard/admin/review/+page.server.ts index b769daf..f37785c 100644 --- a/src/routes/dashboard/admin/review/+page.server.ts +++ b/src/routes/dashboard/admin/review/+page.server.ts @@ -3,6 +3,7 @@ import { project, user, devlog, t1Review } from '$lib/server/db/schema.js'; import { error } from '@sveltejs/kit'; import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm'; import type { Actions } from './$types'; +import { getProjectLinkType } from '$lib/utils'; export async function load({ locals }) { if (!locals.user) { @@ -12,7 +13,7 @@ export async function load({ locals }) { throw error(403, { message: 'oi get out' }); } - const projects = await getProjects(['submitted'], [], []); + const projects = await getProjects(['submitted'], [], [], []); const allProjects = await db .select({ @@ -82,14 +83,17 @@ export const actions = { return parseInt(userId.toString()); }); - const projects = await getProjects(statusFilter, projectFilter, userFilter); + const typeFilter = data.getAll('type') as string[]; + + const projects = await getProjects(statusFilter, projectFilter, userFilter, typeFilter); return { projects, fields: { status: statusFilter, project: projectFilter, - user: userFilter + user: userFilter, + type: typeFilter } }; } @@ -98,44 +102,63 @@ export const actions = { async function getProjects( statusFilter: (typeof project.status._.data)[], projectFilter: number[], - userFilter: number[] + userFilter: number[], + typeFilter: string[] ) { - return await db - .select({ - project: { - id: project.id, - name: project.name, - description: project.description, - url: project.url, - createdAt: project.createdAt, - status: project.status - }, - user: { - id: user.id, - name: user.name - }, - timeSpent: sql`COALESCE(SUM(${devlog.timeSpent}), 0)`, - devlogCount: sql`COALESCE(COUNT(${devlog.id}), 0)` - }) - .from(project) - .leftJoin(devlog, and(eq(project.id, devlog.projectId), eq(devlog.deleted, false))) - .leftJoin(user, eq(user.id, project.userId)) - .where( - and( - eq(project.deleted, false), - statusFilter.length > 0 ? inArray(project.status, statusFilter) : undefined, - projectFilter.length > 0 ? inArray(project.id, projectFilter) : undefined, - userFilter.length > 0 ? inArray(project.userId, userFilter) : undefined + return ( + await db + .select({ + project: { + id: project.id, + name: project.name, + description: project.description, + url: project.url, + editorFileType: project.editorFileType, + editorUrl: project.editorUrl, + uploadedFileUrl: project.uploadedFileUrl, + status: project.status, + createdAt: project.createdAt + }, + user: { + id: user.id, + name: user.name + }, + timeSpent: sql`COALESCE(SUM(${devlog.timeSpent}), 0)`, + devlogCount: sql`COALESCE(COUNT(${devlog.id}), 0)` + }) + .from(project) + .leftJoin(devlog, and(eq(project.id, devlog.projectId), eq(devlog.deleted, false))) + .leftJoin(user, eq(user.id, project.userId)) + .where( + and( + eq(project.deleted, false), + statusFilter.length > 0 ? inArray(project.status, statusFilter) : undefined, + projectFilter.length > 0 ? inArray(project.id, projectFilter) : undefined, + userFilter.length > 0 ? inArray(project.userId, userFilter) : undefined + ) ) - ) - .groupBy( - project.id, - project.name, - project.description, - project.url, - project.createdAt, - project.status, - user.id, - user.name - ); + .groupBy( + project.id, + project.name, + project.description, + project.url, + project.editorFileType, + project.editorUrl, + project.uploadedFileUrl, + project.createdAt, + project.status, + user.id, + user.name + ) + ).filter((item) => + typeFilter.length > 0 + ? typeFilter.includes( + getProjectLinkType( + item.project.editorFileType, + item.project.editorUrl, + item.project.uploadedFileUrl + ) + ) + : true + ); } diff --git a/src/routes/dashboard/admin/review/+page.svelte b/src/routes/dashboard/admin/review/+page.svelte index 558e14f..4da2eb7 100644 --- a/src/routes/dashboard/admin/review/+page.svelte +++ b/src/routes/dashboard/admin/review/+page.svelte @@ -1,7 +1,7 @@