From 34d63f3557b598d043efc041ff461e499c7f0711 Mon Sep 17 00:00:00 2001 From: Prospector <6166773+Prospector@users.noreply.github.com> Date: Thu, 20 Jul 2023 11:19:42 -0700 Subject: [PATCH] Update master with new auth (#1236) * Begin UI for threads and moderation overhaul * Hide close button on non-report threads * Fix review age coloring * Add project count * Remove action buttons from queue page and add queued date to project page * Hook up to actual data * Remove unused icon * Get up to 1000 projects in queue * prettier * more prettier * Changed all the things * lint * rebuild * Add omorphia * Workaround formatjs bug in ThreadSummary.vue * Fix notifications page on prod * Fix a few notifications and threads bugs * lockfile * Fix duplicate button styles * more fixes and polishing * More fixes * Remove legacy pages * More bugfixes * Add some error catching for reports and notifications * More error handling * fix lint * Add inbox links * Remove loading component and rename member header * Rely on threads always existing * Handle if project update notifs are not grouped * oops * Fix chips on notifications page * Import ModalModeration * finish threads * New authentication (#1234) * Initial new auth work * more auth pages * Finish most * more * fix on landing page * Finish everything but PATs + Sessions * fix threads merge bugs * fix cf pages ssr * fix most issues * Finish authentication * Fix merge --------- Co-authored-by: triphora Co-authored-by: Jai A Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com> --- assets/images/utils/discord.svg | 1 + assets/images/utils/gitlab.svg | 9 + assets/images/utils/google.svg | 20 + assets/images/utils/key.svg | 1 + assets/images/utils/microsoft.svg | 1 + assets/images/utils/steam.svg | 4 + assets/styles/components.scss | 2 + components/ui/CopyCode.vue | 8 +- components/ui/EnvironmentIndicator.vue | 85 +-- components/ui/Modal.vue | 7 +- components/ui/ModalCreation.vue | 20 +- components/ui/ModalModeration.vue | 1 - components/ui/ModalReport.vue | 8 +- components/ui/ModalTransfer.vue | 7 +- components/ui/NotificationItem.vue | 15 +- components/ui/ProjectCard.vue | 7 +- components/ui/ProjectMemberHeader.vue | 19 +- components/ui/VersionFilterControl.vue | 5 +- components/ui/report/ReportInfo.vue | 11 +- components/ui/report/ReportView.vue | 25 +- components/ui/report/ReportsList.vue | 21 +- components/ui/search/Categories.vue | 9 +- components/ui/thread/ConversationThread.vue | 17 +- components/ui/thread/ThreadSummary.vue | 6 +- composables/auth.js | 61 +- composables/fetch.js | 18 +- composables/user.js | 56 +- helpers/notifications.js | 11 +- helpers/projects.js | 13 +- helpers/teams.js | 8 +- layouts/default.vue | 103 ++- middleware/auth.js | 4 +- nuxt.config.ts | 5 +- package.json | 2 + pages/[type]/[id].vue | 104 +-- pages/[type]/[id]/gallery.vue | 9 +- pages/[type]/[id]/moderation.vue | 7 +- pages/[type]/[id]/settings/index.vue | 15 +- pages/[type]/[id]/settings/links.vue | 9 +- pages/[type]/[id]/settings/members.vue | 8 +- pages/[type]/[id]/settings/tags.vue | 6 +- pages/[type]/[id]/version/[version].vue | 51 +- pages/auth.vue | 156 ++++ pages/auth/reset-password.vue | 113 +++ pages/auth/sign-in.vue | 195 +++++ pages/auth/sign-up.vue | 144 ++++ pages/auth/verify-email.vue | 78 ++ pages/auth/welcome.vue | 46 ++ pages/dashboard/index.vue | 12 +- pages/dashboard/notifications.vue | 3 + pages/dashboard/projects.vue | 1 - pages/dashboard/report/[id].vue | 2 + pages/dashboard/reports.vue | 3 +- pages/dashboard/revenue/transfers.vue | 3 +- pages/index.vue | 18 +- pages/moderation/index.vue | 6 +- pages/moderation/messages.vue | 8 +- pages/moderation/report/[id].vue | 2 + pages/moderation/reports.vue | 3 +- pages/moderation/review.vue | 57 +- pages/search/[searchProjectType].vue | 59 +- pages/settings.vue | 11 +- pages/settings/account.vue | 764 +++++++++++++++----- pages/settings/index.vue | 24 +- pages/settings/monetization.vue | 1 - pages/settings/pats.vue | 296 ++++++++ pages/settings/sessions.vue | 89 +++ pages/user/[id].vue | 75 +- plugins/1.theme.js | 4 +- plugins/2.state.js | 11 - plugins/shorthands.js | 68 +- pnpm-lock.yaml | 25 + 72 files changed, 2369 insertions(+), 707 deletions(-) create mode 100644 assets/images/utils/discord.svg create mode 100644 assets/images/utils/gitlab.svg create mode 100644 assets/images/utils/google.svg create mode 100644 assets/images/utils/key.svg create mode 100644 assets/images/utils/microsoft.svg create mode 100644 assets/images/utils/steam.svg create mode 100644 pages/auth.vue create mode 100644 pages/auth/reset-password.vue create mode 100644 pages/auth/sign-in.vue create mode 100644 pages/auth/sign-up.vue create mode 100644 pages/auth/verify-email.vue create mode 100644 pages/auth/welcome.vue create mode 100644 pages/settings/pats.vue create mode 100644 pages/settings/sessions.vue delete mode 100644 plugins/2.state.js diff --git a/assets/images/utils/discord.svg b/assets/images/utils/discord.svg new file mode 100644 index 0000000000..22ee27ba2d --- /dev/null +++ b/assets/images/utils/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/utils/gitlab.svg b/assets/images/utils/gitlab.svg new file mode 100644 index 0000000000..c33ed09ec5 --- /dev/null +++ b/assets/images/utils/gitlab.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/assets/images/utils/google.svg b/assets/images/utils/google.svg new file mode 100644 index 0000000000..2471bea3e0 --- /dev/null +++ b/assets/images/utils/google.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/utils/key.svg b/assets/images/utils/key.svg new file mode 100644 index 0000000000..845dcd6b24 --- /dev/null +++ b/assets/images/utils/key.svg @@ -0,0 +1 @@ + diff --git a/assets/images/utils/microsoft.svg b/assets/images/utils/microsoft.svg new file mode 100644 index 0000000000..a4f7611502 --- /dev/null +++ b/assets/images/utils/microsoft.svg @@ -0,0 +1 @@ +MS-SymbolLockup \ No newline at end of file diff --git a/assets/images/utils/steam.svg b/assets/images/utils/steam.svg new file mode 100644 index 0000000000..aecd433989 --- /dev/null +++ b/assets/images/utils/steam.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/assets/styles/components.scss b/assets/styles/components.scss index 33d5f037ad..128db88313 100644 --- a/assets/styles/components.scss +++ b/assets/styles/components.scss @@ -903,6 +903,8 @@ tr.button-transparent { cursor: pointer; width: fit-content; height: fit-content; + transition: opacity 0.5s ease-in-out, filter 0.2s ease-in-out, scale 0.05s ease-in-out, + outline 0.2s ease-in-out; text-decoration: none; diff --git a/components/ui/CopyCode.vue b/components/ui/CopyCode.vue index e923826f6d..5faabfa299 100644 --- a/components/ui/CopyCode.vue +++ b/components/ui/CopyCode.vue @@ -1,6 +1,6 @@ - diff --git a/middleware/auth.js b/middleware/auth.js index 7de2619fce..34061c991c 100644 --- a/middleware/auth.js +++ b/middleware/auth.js @@ -1,7 +1,7 @@ -export default defineNuxtRouteMiddleware(async () => { +export default defineNuxtRouteMiddleware(async (_to, from) => { const auth = await useAuth() if (!auth.value.user) { - return navigateTo(getAuthUrl(), { external: true }) + return navigateTo(`/auth/sign-in?redirect=${encodeURIComponent(from.fullPath)}`) } }) diff --git a/nuxt.config.ts b/nuxt.config.ts index cbd227270e..685c2e2948 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -294,12 +294,15 @@ export default defineNuxtConfig({ }, }, }, - modules: ['@vintl/nuxt'], + modules: ['@vintl/nuxt', '@nuxtjs/turnstile'], vintl: { defaultLocale: 'en-US', storage: 'cookie', parserless: 'only-prod', }, + turnstile: { + siteKey: '0x4AAAAAAAHWfmKCm7cUG869', + }, nitro: { moduleSideEffects: ['@vintl/compact-number/locale-data'], }, diff --git a/package.json b/package.json index 6033f6b109..1fbfd4beab 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "devDependencies": { "@formatjs/cli": "^6.1.2", "@nuxtjs/eslint-config-typescript": "^12.0.0", + "@nuxtjs/turnstile": "^0.5.0", "@types/node": "^20.1.0", "@typescript-eslint/eslint-plugin": "^5.59.8", "@typescript-eslint/parser": "^5.59.8", @@ -44,6 +45,7 @@ "jszip": "^3.10.1", "markdown-it": "^13.0.1", "omorphia": "^0.4.31", + "qrcode.vue": "^3.4.0", "vue-multiselect": "^3.0.0-alpha.2", "xss": "^1.0.14" }, diff --git a/pages/[type]/[id].vue b/pages/[type]/[id].vue index 3c5d6b6980..3bd78af341 100644 --- a/pages/[type]/[id].vue +++ b/pages/[type]/[id].vue @@ -106,6 +106,8 @@ :toggle-collapsed="() => (collapsedChecklist = !collapsedChecklist)" :all-members="allMembers" :update-members="updateMembers" + :auth="auth" + :tags="tags" />
@@ -229,7 +231,7 @@ class="categories" > @@ -287,7 +289,7 @@

-
@@ -161,7 +151,7 @@ />
@@ -169,13 +159,13 @@ Manage projects
@@ -183,7 +173,7 @@

- + You don't have any projects.
Would you like to create one? @@ -242,7 +232,6 @@ import ProjectCard from '~/components/ui/ProjectCard.vue' import Badge from '~/components/ui/Badge.vue' import Promotion from '~/components/ads/Promotion.vue' -import GitHubIcon from '~/assets/images/utils/github.svg' import ReportIcon from '~/assets/images/utils/report.svg' import SunriseIcon from '~/assets/images/utils/sunrise.svg' import DownloadIcon from '~/assets/images/utils/download.svg' @@ -266,23 +255,25 @@ import Avatar from '~/components/ui/Avatar.vue' const data = useNuxtApp() const route = useRoute() +const auth = await useAuth() +const cosmetics = useCosmetics() +const tags = useTags() let user, projects try { ;[{ data: user }, { data: projects }] = await Promise.all([ - useAsyncData(`user/${route.params.id}`, () => - useBaseFetch(`user/${route.params.id}`, data.$defaultHeaders()) - ), + useAsyncData(`user/${route.params.id}`, () => useBaseFetch(`user/${route.params.id}`)), useAsyncData( `user/${route.params.id}/projects`, - () => useBaseFetch(`user/${route.params.id}/projects`, data.$defaultHeaders()), + () => useBaseFetch(`user/${route.params.id}/projects`), { transform: (projects) => { for (const project of projects) { project.categories = project.categories.concat(project.loaders) project.project_type = data.$getProjectTypeForUrl( project.project_type, - project.categories + project.categories, + tags.value ) } @@ -307,12 +298,6 @@ if (!user.value) { }) } -let githubUrl -try { - const githubUser = await $fetch(`https://api.github.com/user/` + user.value.github_id) - githubUrl = ref(githubUser.html_url) -} catch {} - if (user.value.username !== route.params.id) { await navigateTo(`/user/${user.value.username}`, { redirectCode: 301 }) } @@ -369,13 +354,12 @@ async function saveChanges() { try { if (icon.value) { await useBaseFetch( - `user/${data.$auth.user.id}/icon?ext=${ + `user/${auth.value.user.id}/icon?ext=${ icon.value.type.split('/')[icon.value.type.split('/').length - 1] }`, { method: 'PATCH', body: icon.value, - ...data.$defaultHeaders(), } ) } @@ -384,16 +368,15 @@ async function saveChanges() { email: user.value.email, bio: user.value.bio, } - if (user.value.username !== data.$auth.user.username) { + if (user.value.username !== auth.value.user.username) { reqData.username = user.value.username } - await useBaseFetch(`user/${data.$auth.user.id}`, { + await useBaseFetch(`user/${auth.value.user.id}`, { method: 'PATCH', body: reqData, - ...data.$defaultHeaders(), }) - await useAuth(data.$auth.token) + await useAuth(auth.value.token) isEditing.value = false } catch (err) { @@ -409,9 +392,9 @@ async function saveChanges() { } function cycleSearchDisplayMode() { - data.$cosmetics.searchDisplayMode.user = data.$cycleValue( - data.$cosmetics.searchDisplayMode.user, - data.$tag.projectViewModes + cosmetics.value.searchDisplayMode.user = data.$cycleValue( + cosmetics.value.searchDisplayMode.user, + tags.value.projectViewModes ) saveCosmetics() } @@ -504,10 +487,6 @@ export default defineNuxtComponent({ cursor: default; } -.github-button { - display: inline-flex; -} - .inputs { margin-bottom: 1rem; diff --git a/plugins/1.theme.js b/plugins/1.theme.js index 6ed6b4be7f..29fa1cf1c1 100644 --- a/plugins/1.theme.js +++ b/plugins/1.theme.js @@ -1,4 +1,6 @@ -export default defineNuxtPlugin((nuxtApp) => { +export default defineNuxtPlugin(async (nuxtApp) => { + await useAuth() + await useUser() const themeStore = useTheme() nuxtApp.hook('app:mounted', () => { diff --git a/plugins/2.state.js b/plugins/2.state.js deleted file mode 100644 index 85504747c5..0000000000 --- a/plugins/2.state.js +++ /dev/null @@ -1,11 +0,0 @@ -export default defineNuxtPlugin(async (nuxtApp) => { - const authStore = await useAuth() - await useUser() - const cosmeticsStore = useCosmetics() - const tagsStore = useTags() - - nuxtApp.provide('auth', authStore.value) - nuxtApp.provide('cosmetics', cosmeticsStore.value) - nuxtApp.provide('tag', tagsStore.value) - nuxtApp.provide('notify', (notif) => addNotification(notif)) -}) diff --git a/plugins/shorthands.js b/plugins/shorthands.js index 54ba23ada3..b92e269cc8 100644 --- a/plugins/shorthands.js +++ b/plugins/shorthands.js @@ -1,29 +1,10 @@ import { getProjectTypeForUrlShorthand } from '~/helpers/projects.js' export default defineNuxtPlugin((nuxtApp) => { - const tagStore = nuxtApp.$tag - const authStore = nuxtApp.$auth - - nuxtApp.provide('defaultHeaders', () => { - const obj = { headers: {} } - - if (process.server) { - const config = useRuntimeConfig() - if (config.rateLimitKey) { - obj.headers['x-ratelimit-key'] = config.rateLimitKey || '' - } - } - - if (authStore.user) { - obj.headers.Authorization = authStore.token - } - - return obj - }) nuxtApp.provide('formatNumber', formatNumber) nuxtApp.provide('capitalizeString', capitalizeString) nuxtApp.provide('formatMoney', formatMoney) - nuxtApp.provide('formatVersion', (versionsArray) => formatVersions(versionsArray, tagStore)) + nuxtApp.provide('formatVersion', (versionsArray) => formatVersions(versionsArray)) nuxtApp.provide('orElse', (first, otherwise) => first ?? otherwise) nuxtApp.provide('external', () => { const cosmeticsStore = useCosmetics().value @@ -95,15 +76,17 @@ export default defineNuxtPlugin((nuxtApp) => { .sort((a, b) => nuxtApp.$dayjs(b.date_published) - nuxtApp.$dayjs(a.date_published)) }) nuxtApp.provide('getProjectTypeForDisplay', (type, categories) => { + const tagStore = useTags() + if (type === 'mod') { const isPlugin = categories.some((category) => { - return tagStore.loaderData.allPluginLoaders.includes(category) + return tagStore.value.loaderData.allPluginLoaders.includes(category) }) const isMod = categories.some((category) => { - return tagStore.loaderData.modLoaders.includes(category) + return tagStore.value.loaderData.modLoaders.includes(category) }) const isDataPack = categories.some((category) => { - return tagStore.loaderData.dataPackLoaders.includes(category) + return tagStore.value.loaderData.dataPackLoaders.includes(category) }) if (isMod && isPlugin && isDataPack) { @@ -123,25 +106,29 @@ export default defineNuxtPlugin((nuxtApp) => { return type }) - nuxtApp.provide('getProjectTypeForUrl', (type, loaders) => - getProjectTypeForUrlShorthand(nuxtApp, type, loaders) + nuxtApp.provide('getProjectTypeForUrl', (type, loaders, tags) => + getProjectTypeForUrlShorthand(type, loaders, tags) ) nuxtApp.provide('cycleValue', cycleValue) - const sortedCategories = tagStore.categories.slice().sort((a, b) => { - const headerCompare = a.header.localeCompare(b.header) - if (headerCompare !== 0) { - return headerCompare - } - if (a.header === 'resolutions' && b.header === 'resolutions') { - return a.name.replace(/\D/g, '') - b.name.replace(/\D/g, '') - } else if (a.header === 'performance impact' && b.header === 'performance impact') { - const x = ['potato', 'low', 'medium', 'high', 'screenshot'] + nuxtApp.provide('sortedCategories', () => { + const tagStore = useTags() - return x.indexOf(a.name) - x.indexOf(b.name) - } - return 0 + return tagStore.value.categories.slice().sort((a, b) => { + const headerCompare = a.header.localeCompare(b.header) + if (headerCompare !== 0) { + return headerCompare + } + if (a.header === 'resolutions' && b.header === 'resolutions') { + return a.name.replace(/\D/g, '') - b.name.replace(/\D/g, '') + } else if (a.header === 'performance impact' && b.header === 'performance impact') { + const x = ['potato', 'low', 'medium', 'high', 'screenshot'] + + return x.indexOf(a.name) - x.indexOf(b.name) + } + return 0 + }) }) - nuxtApp.provide('sortedCategories', sortedCategories) + nuxtApp.provide('notify', (notif) => addNotification(notif)) }) export const formatNumber = (number, abbreviate = true) => { const x = +number @@ -257,8 +244,9 @@ export const formatProjectStatus = (name) => { return capitalizeString(name) } -export const formatVersions = (versionArray, tag) => { - const allVersions = tag.gameVersions.slice().reverse() +export const formatVersions = (versionArray) => { + const tag = useTags() + const allVersions = tag.value.gameVersions.slice().reverse() const allReleases = allVersions.filter((x) => x.version_type === 'release') const intervals = [] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 070489a30d..970a5f6e09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ dependencies: omorphia: specifier: ^0.4.31 version: 0.4.31 + qrcode.vue: + specifier: ^3.4.0 + version: 3.4.0(vue@3.3.4) vue-multiselect: specifier: ^3.0.0-alpha.2 version: 3.0.0-alpha.2 @@ -48,6 +51,9 @@ devDependencies: '@nuxtjs/eslint-config-typescript': specifier: ^12.0.0 version: 12.0.0(eslint@8.41.0)(typescript@5.0.4) + '@nuxtjs/turnstile': + specifier: ^0.5.0 + version: 0.5.0 '@types/node': specifier: ^20.1.0 version: 20.1.0 @@ -1357,6 +1363,17 @@ packages: - supports-color dev: true + /@nuxtjs/turnstile@0.5.0: + resolution: {integrity: sha512-EmEnYNDRavdmv9HXnInHVR5nSvjDG92s6pOrxd+ugqImkrnIQJttSd4DPq9UNhwUI/wLUL7z3VclVyQwNT2O7Q==} + dependencies: + '@nuxt/kit': 3.6.1 + defu: 6.1.2 + pathe: 1.1.1 + transitivePeerDependencies: + - rollup + - supports-color + dev: true + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -6024,6 +6041,14 @@ packages: engines: {node: '>=6'} dev: true + /qrcode.vue@3.4.0(vue@3.3.4): + resolution: {integrity: sha512-4XeImbv10Fin16Fl2DArCMhGyAdvIg2jb7vDT+hZiIAMg/6H6mz9nUZr/dR8jBcun5VzNzkiwKhiqOGbloinwA==} + peerDependencies: + vue: ^3.0.0 + dependencies: + vue: 3.3.4 + dev: false + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true