Skip to content

Commit 422656f

Browse files
committed
2 parents 747df8c + 3542442 commit 422656f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3474
-2266
lines changed

.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ INTERNAL_COMMAND_TOKEN="some-made-up-token"
1515
GITHUB_CLIENT_ID="MOCK_GITHUB_CLIENT_ID"
1616
GITHUB_CLIENT_SECRET="MOCK_GITHUB_CLIENT_SECRET"
1717
GITHUB_TOKEN="MOCK_GITHUB_TOKEN"
18+
GITHUB_REDIRECT_URI="https://example.com/auth/github/callback"
1819

1920
# set this to false to prevent search engines from indexing the website
2021
# default to allow indexing for seo safety
2122
ALLOW_INDEXING="true"
23+
24+
# Tigris Object Storage (S3-compatible) Configuration
25+
AWS_ACCESS_KEY_ID="mock-access-key"
26+
AWS_SECRET_ACCESS_KEY="mock-secret-key"
27+
AWS_REGION="auto"
28+
AWS_ENDPOINT_URL_S3="https://fly.storage.tigris.dev"
29+
BUCKET_NAME="mock-bucket"

.github/workflows/deploy.yml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@ jobs:
3030
- name: 📥 Download deps
3131
uses: bahmutov/npm-install@v1
3232

33+
- name: 🏄 Copy test env vars
34+
run: cp .env.example .env
35+
3336
- name: 🖼 Build icons
3437
run: npm run build:icons
3538

39+
- name: 🛠 Setup Database
40+
run: npx prisma migrate deploy && npx prisma generate --sql
41+
3642
- name: 🔬 Lint
3743
run: npm run lint
3844

@@ -51,9 +57,15 @@ jobs:
5157
- name: 📥 Download deps
5258
uses: bahmutov/npm-install@v1
5359

60+
- name: 🏄 Copy test env vars
61+
run: cp .env.example .env
62+
5463
- name: 🖼 Build icons
5564
run: npm run build:icons
5665

66+
- name: 🛠 Setup Database
67+
run: npx prisma migrate deploy && npx prisma generate --sql
68+
5769
- name: 🔎 Type check
5870
run: npm run typecheck --if-present
5971

@@ -78,6 +90,9 @@ jobs:
7890
- name: 🖼 Build icons
7991
run: npm run build:icons
8092

93+
- name: 🛠 Setup Database
94+
run: npx prisma migrate deploy && npx prisma generate --sql
95+
8196
- name: ⚡ Run vitest
8297
run: npm run test -- --coverage
8398

@@ -104,7 +119,7 @@ jobs:
104119
run: npm run test:e2e:install
105120

106121
- name: 🛠 Setup Database
107-
run: npx prisma migrate deploy
122+
run: npx prisma migrate deploy && npx prisma generate --sql
108123

109124
- name: 🏦 Cache Database
110125
id: db-cache

.github/workflows/version.yml

Lines changed: 0 additions & 54 deletions
This file was deleted.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ node_modules
1414
/playwright-report/
1515
/playwright/.cache/
1616
/tests/fixtures/email/
17+
/tests/fixtures/uploaded/
18+
/tests/fixtures/openimg/
1719
/coverage
1820

1921
/other/cache.db

app/components/user-dropdown.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Img } from 'openimg/react'
12
import { useRef } from 'react'
23
import { Link, Form } from 'react-router'
34
import { getUserImgSrc } from '#app/utils/misc.tsx'
@@ -25,10 +26,12 @@ export function UserDropdown() {
2526
onClick={(e) => e.preventDefault()}
2627
className="flex items-center gap-2"
2728
>
28-
<img
29+
<Img
2930
className="h-8 w-8 rounded-full object-cover"
3031
alt={user.name ?? user.username}
31-
src={getUserImgSrc(user.image?.id)}
32+
src={getUserImgSrc(user.image?.objectKey)}
33+
width={256}
34+
height={256}
3235
/>
3336
<span className="text-body-sm font-bold">
3437
{user.name ?? user.username}

app/root.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { OpenImgContextProvider } from 'openimg/react'
12
import {
23
data,
34
Link,
@@ -33,7 +34,7 @@ import { prisma } from './utils/db.server.ts'
3334
import { getEnv } from './utils/env.server.ts'
3435
import { pipeHeaders } from './utils/headers.server.ts'
3536
import { honeypot } from './utils/honeypot.server.ts'
36-
import { combineHeaders, getDomainUrl } from './utils/misc.tsx'
37+
import { combineHeaders, getDomainUrl, getImgSrc } from './utils/misc.tsx'
3738
import { useNonce } from './utils/nonce-provider.ts'
3839
import { type Theme, getTheme } from './utils/theme.server.ts'
3940
import { makeTimings, time } from './utils/timing.server.ts'
@@ -83,7 +84,7 @@ export async function loader({ request }: Route.LoaderArgs) {
8384
id: true,
8485
name: true,
8586
username: true,
86-
image: { select: { id: true } },
87+
image: { select: { objectKey: true } },
8788
roles: {
8889
select: {
8990
name: true,
@@ -194,7 +195,10 @@ function App() {
194195
useToast(data.toast)
195196

196197
return (
197-
<>
198+
<OpenImgContextProvider
199+
optimizerEndpoint="/resources/images"
200+
getSrc={getImgSrc}
201+
>
198202
<div className="flex min-h-screen flex-col justify-between">
199203
<header className="container py-6">
200204
<nav className="flex flex-wrap items-center justify-between gap-4 sm:flex-nowrap md:gap-8">
@@ -215,7 +219,7 @@ function App() {
215219
</nav>
216220
</header>
217221

218-
<div className="flex-1">
222+
<div className="flex-1 flex flex-col">
219223
<Outlet />
220224
</div>
221225

@@ -226,7 +230,7 @@ function App() {
226230
</div>
227231
<EpicToaster closeButton position="top-center" theme={theme} />
228232
<EpicProgress />
229-
</>
233+
</OpenImgContextProvider>
230234
)
231235
}
232236

app/routes/_auth+/auth.$provider.callback.test.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { invariant } from '@epic-web/invariant'
22
import { faker } from '@faker-js/faker'
3+
import { SetCookie } from '@mjackson/headers'
34
import { http } from 'msw'
45
import { afterEach, expect, test } from 'vitest'
56
import { twoFAVerificationType } from '#app/routes/settings+/profile.two-factor.tsx'
67
import { getSessionExpirationDate, sessionKey } from '#app/utils/auth.server.ts'
7-
import { connectionSessionStorage } from '#app/utils/connections.server.ts'
88
import { GITHUB_PROVIDER_NAME } from '#app/utils/connections.tsx'
99
import { prisma } from '#app/utils/db.server.ts'
1010
import { authSessionStorage } from '#app/utils/session.server.ts'
@@ -35,7 +35,7 @@ test('when auth fails, send the user to login with a toast', async () => {
3535
consoleError.mockImplementation(() => {})
3636
server.use(
3737
http.post('https://github.com/login/oauth/access_token', async () => {
38-
return new Response('error', { status: 400 })
38+
return new Response(null, { status: 400 })
3939
}),
4040
)
4141
const request = await setupRequest()
@@ -219,19 +219,25 @@ async function setupRequest({
219219
const state = faker.string.uuid()
220220
url.searchParams.set('state', state)
221221
url.searchParams.set('code', code)
222-
const connectionSession = await connectionSessionStorage.getSession()
223-
connectionSession.set('oauth2:state', state)
224222
const authSession = await authSessionStorage.getSession()
225223
if (sessionId) authSession.set(sessionKey, sessionId)
226224
const setSessionCookieHeader =
227225
await authSessionStorage.commitSession(authSession)
228-
const setConnectionSessionCookieHeader =
229-
await connectionSessionStorage.commitSession(connectionSession)
226+
const searchParams = new URLSearchParams({ code, state })
227+
let authCookie = new SetCookie({
228+
name: 'github',
229+
value: searchParams.toString(),
230+
path: '/',
231+
sameSite: 'Lax',
232+
httpOnly: true,
233+
maxAge: 60 * 10,
234+
secure: process.env.NODE_ENV === 'production' || undefined,
235+
})
230236
const request = new Request(url.toString(), {
231237
method: 'GET',
232238
headers: {
233239
cookie: [
234-
convertSetCookieToCookie(setConnectionSessionCookieHeader),
240+
authCookie.toString(),
235241
convertSetCookieToCookie(setSessionCookieHeader),
236242
].join('; '),
237243
},

app/routes/_auth+/auth.$provider.callback.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export async function loader({ request, params }: Route.LoaderArgs) {
3838
const label = providerLabels[providerName]
3939

4040
const authResult = await authenticator
41-
.authenticate(providerName, request, { throwOnError: true })
41+
.authenticate(providerName, request)
4242
.then(
4343
(data) =>
4444
({
@@ -70,7 +70,10 @@ export async function loader({ request, params }: Route.LoaderArgs) {
7070
const existingConnection = await prisma.connection.findUnique({
7171
select: { userId: true },
7272
where: {
73-
providerName_providerId: { providerName, providerId: profile.id },
73+
providerName_providerId: {
74+
providerName,
75+
providerId: String(profile.id),
76+
},
7477
},
7578
})
7679

@@ -103,7 +106,7 @@ export async function loader({ request, params }: Route.LoaderArgs) {
103106
await prisma.connection.create({
104107
data: {
105108
providerName,
106-
providerId: profile.id,
109+
providerId: String(profile.id),
107110
userId,
108111
},
109112
})
@@ -133,7 +136,7 @@ export async function loader({ request, params }: Route.LoaderArgs) {
133136
await prisma.connection.create({
134137
data: {
135138
providerName,
136-
providerId: profile.id,
139+
providerId: String(profile.id),
137140
userId: user.id,
138141
},
139142
})

app/routes/_auth+/onboarding_.$provider.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ import { CheckboxField, ErrorList, Field } from '#app/components/forms.tsx'
1818
import { Spacer } from '#app/components/spacer.tsx'
1919
import { StatusButton } from '#app/components/ui/status-button.tsx'
2020
import {
21-
authenticator,
2221
sessionKey,
2322
signupWithConnection,
2423
requireAnonymous,
2524
} from '#app/utils/auth.server.ts'
26-
import { connectionSessionStorage } from '#app/utils/connections.server'
2725
import { ProviderNameSchema } from '#app/utils/connections.tsx'
2826
import { prisma } from '#app/utils/db.server.ts'
2927
import { useIsPending } from '#app/utils/misc.tsx'
@@ -65,7 +63,7 @@ async function requireData({
6563
.object({
6664
email: z.string(),
6765
providerName: ProviderNameSchema,
68-
providerId: z.string(),
66+
providerId: z.string().or(z.number()),
6967
})
7068
.safeParse({ email, providerName: params.provider, providerId })
7169
if (result.success) {
@@ -78,24 +76,17 @@ async function requireData({
7876

7977
export async function loader({ request, params }: Route.LoaderArgs) {
8078
const { email } = await requireData({ request, params })
81-
const connectionSession = await connectionSessionStorage.getSession(
82-
request.headers.get('cookie'),
83-
)
79+
8480
const verifySession = await verifySessionStorage.getSession(
8581
request.headers.get('cookie'),
8682
)
8783
const prefilledProfile = verifySession.get(prefilledProfileKey)
8884

89-
const formError = connectionSession.get(authenticator.sessionErrorKey)
90-
const hasError = typeof formError === 'string'
91-
9285
return {
9386
email,
9487
status: 'idle',
9588
submission: {
96-
status: hasError ? 'error' : undefined,
9789
initialValue: prefilledProfile ?? {},
98-
error: { '': hasError ? [formError] : [] },
9990
} as SubmissionResult,
10091
}
10192
}
@@ -128,7 +119,7 @@ export async function action({ request, params }: Route.ActionArgs) {
128119
const session = await signupWithConnection({
129120
...data,
130121
email,
131-
providerId,
122+
providerId: String(providerId),
132123
providerName,
133124
})
134125
return { ...data, session }

app/routes/resources+/download-user-data.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { requireUserId } from '#app/utils/auth.server.ts'
22
import { prisma } from '#app/utils/db.server.ts'
3-
import { getDomainUrl } from '#app/utils/misc.tsx'
3+
import { getDomainUrl, getNoteImgSrc, getUserImgSrc } from '#app/utils/misc.tsx'
44
import { type Route } from './+types/download-user-data.ts'
55

66
export async function loader({ request }: Route.LoaderArgs) {
@@ -18,7 +18,7 @@ export async function loader({ request }: Route.LoaderArgs) {
1818
id: true,
1919
createdAt: true,
2020
updatedAt: true,
21-
contentType: true,
21+
objectKey: true,
2222
},
2323
},
2424
notes: {
@@ -28,7 +28,7 @@ export async function loader({ request }: Route.LoaderArgs) {
2828
id: true,
2929
createdAt: true,
3030
updatedAt: true,
31-
contentType: true,
31+
objectKey: true,
3232
},
3333
},
3434
},
@@ -47,14 +47,14 @@ export async function loader({ request }: Route.LoaderArgs) {
4747
image: user.image
4848
? {
4949
...user.image,
50-
url: `${domain}/resources/user-images/${user.image.id}`,
50+
url: domain + getUserImgSrc(user.image.objectKey),
5151
}
5252
: null,
5353
notes: user.notes.map((note) => ({
5454
...note,
5555
images: note.images.map((image) => ({
5656
...image,
57-
url: `${domain}/resources/note-images/${image.id}`,
57+
url: domain + getNoteImgSrc(image.objectKey),
5858
})),
5959
})),
6060
},

0 commit comments

Comments
 (0)