Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/Connect users #368

Merged
merged 7 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion containers/nginx/default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,8 @@ server {
proxy_cache_bypass $http_upgrade;
client_max_body_size 1000M;
proxy_set_header Referrer-Policy no-referrer;
proxy_buffer_size 32k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 64k;
}
}
}
7 changes: 5 additions & 2 deletions containers/nginx/nginx.dev.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ http {
}
default_type application/octet-stream;
}

location / {
proxy_pass http://projectnext:3000;
proxy_http_version 1.1;
Expand All @@ -21,6 +21,9 @@ http {
proxy_cache_bypass $http_upgrade;
client_max_body_size 1000M;
proxy_set_header Referrer-Policy no-referrer;
proxy_buffer_size 32k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 64k;
}
}
}
}
2 changes: 1 addition & 1 deletion src/app/(auth)/login/page.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
&:hover {
color: ohma.$colors-gray-500;
}
}
}
1 change: 1 addition & 0 deletions src/app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default function LogIn() {
redirect: true,
callbackUrl: searchParams.get('callbackUrl') || '/users/me'
})}>Logg inn med Feide</BorderButton>
<br />
<Link href="/reset-password" className={styles.resetPasswordLink}>Glemt passord?</Link>
<p>Er det første gang du logger inn? Da er det bare å logge inn med feide for å lage en bruker.</p>
</>
Expand Down
4 changes: 2 additions & 2 deletions src/app/(auth)/register-email/EmailregistrationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { useUser } from '@/auth/useUser'
import { useRouter, useSearchParams } from 'next/navigation'
import { useState } from 'react'

export default async function EmailRegistrationForm() {
export default function EmailRegistrationForm() {
const searchParams = useSearchParams()
const callbackUrl = searchParams.get('callbackUrl') || 'users/me'
const callbackUrl = searchParams.get('callbackUrl') || '/users/me'

const [feedback, setFeedback] = useState<string | null>(null)

Expand Down
26 changes: 19 additions & 7 deletions src/app/(auth)/register/RegistrationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ import { SelectString } from '@/components/UI/Select'
import TextInput from '@/components/UI/TextInput'
import { useUser } from '@/auth/useUser'
import { sexConfig } from '@/services/users/ConfigVars'
import { SEX } from '@prisma/client'
import { signIn } from 'next-auth/react'
import { SEX, type User } from '@prisma/client'
import { signIn, signOut } from 'next-auth/react'
import { useSearchParams } from 'next/navigation'

export default function RegistrationForm() {
export default function RegistrationForm({
userData,
shouldLogOut,
}: {
userData: Pick<User, 'mobile' | 'allergies' | 'sex'>,
shouldLogOut?: boolean
}) {
const searchParams = useSearchParams()
const callbackUrl = searchParams.get('callbackUrl') || '/users/me'

Expand All @@ -19,6 +25,12 @@ export default function RegistrationForm() {
shouldRedirect: true,
})

if (shouldLogOut) {
signOut({
redirect: false
})
}

const lastUsername = userAuth.user?.username
let lastPassword: string = ''

Expand All @@ -38,11 +50,11 @@ export default function RegistrationForm() {
callbackUrl
})}
>
<TextInput label="Telefonnummer" name="mobile" />
<TextInput label="Allergier / diett" name="allergies" />
<TextInput type="password" label="Passord" name="password" onChange={(e) => {lastPassword = e.target.value}}/>
<TextInput label="Telefonnummer" name="mobile" defaultValue={userData.mobile ?? ''} />
<TextInput label="Allergier / diett" name="allergies" defaultValue={userData.allergies ?? ''} />
<TextInput type="password" label="Passord" name="password" onChange={(e) => { lastPassword = e.target.value }} />
<TextInput type="password" label="Gjenta passord" name="confirmPassword" />
<SelectString label="Kjønn" name="sex" options={sexOptions}/>
<SelectString label="Kjønn" name="sex" options={sexOptions} defaultValue={userData.sex ?? undefined} />
<Checkbox label="Jeg godtar vilkårene" name="acceptedTerms" />
</Form>
}
26 changes: 11 additions & 15 deletions src/app/(auth)/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,37 @@ export default async function Register({ searchParams }: PropTypes) {
shouldRedirect: false,
})

let userId = user?.id
let shouldLogOut = false

if (typeof searchParams.token === 'string') {
const verify = await verifyUserEmailAction(searchParams.token)
if (!verify.success) {
console.log(verify)
return <p>Token er ugyldig</p>
redirect('./register')
}

if (user && verify.data.id !== user.id) {
// TODO: Logout
console.log('Should logout')
// throw new Error('Email is verified. Cannot continue registrations while another user is logged in.')
shouldLogOut = true
}

console.log(verify)

//TODO: Login the correct user
// See https://github.com/nextauthjs/next-auth/discussions/5334
}

if (!authorized || !user) {
userId = verify.data.id
} else if (!authorized || !user) {
return notFound()
}

//TODO: change to action.
const updatedUser = await safeServerCall(() => readUser({ id: user.id }))
const updatedUser = await safeServerCall(() => readUser({ id: userId }))
if (!updatedUser.success) {
return notFound()
}

if (updatedUser.data.acceptedTerms) {
redirect(searchParams.callbackUrl ?? 'users/me')
redirect(searchParams.callbackUrl ?? '/users/me')
}

if (!updatedUser.data.emailVerified) {
redirect('/register-email')
}

return <RegistrationForm />
return <RegistrationForm userData={updatedUser.data} shouldLogOut={shouldLogOut} />
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@

.OmegaIdElement {
max-width: 400px;

> h2, h4 {
text-align: center;
}

> h2 {
font-weight: bold;
}
}
9 changes: 9 additions & 0 deletions src/app/_components/OmegaId/identification/OmegaIdElement.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client'
import styles from './OmegaIdElement.module.scss'
import { useUser } from '@/auth/useUser'
import { generateOmegaIdAction } from '@/actions/omegaid/generate'
import { readJWTPayload } from '@/jwt/jwtReadUnsecure'
import { compressOmegaId } from '@/services/omegaid/compress'
Expand All @@ -13,6 +14,8 @@ export default function OmegaIdElement({ token }: {
}) {
const [tokenState, setTokenState] = useState(token)

const { user } = useUser()

const { SVG } = useQRCode()

const JWTPayload = readJWTPayload(tokenState)
Expand All @@ -39,9 +42,15 @@ export default function OmegaIdElement({ token }: {
return () => clearInterval(interval)
})

if (!user) return <p>Could not load OmegaID, since the user is not loggedin.</p>

return <div className={styles.OmegaIdElement}>
<h2>Omega ID</h2>
<SVG
text={compressOmegaId(tokenState)}
/>
<h2>{user.firstname} {user.lastname}</h2>
<h4>{user.username}</h4>
<h4>{user.id}</h4>
</div>
}
1 change: 1 addition & 0 deletions src/app/_components/UI/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function SelectConstructor<ValueType extends string | number>(valueConver
(option) => <option
key={option.key ?? uuid()}
value={option.value}
selected={option.value === defaultValue}
>
{option.label ?? option.value}
</option>
Expand Down
49 changes: 33 additions & 16 deletions src/auth/VevenAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import 'server-only'
import { readJWTPayload } from '@/jwt/jwtReadUnsecure'
import { createFeideAccount } from '@/services/auth/feideAccounts/create'
import { readUserOrNullOfFeideAccount } from '@/services/auth/feideAccounts/read'
import { User } from '@/services/users'
import { readUserOrNull } from '@/services/users/read'
import { userFilterSelection } from '@/services/users/ConfigVars'
import type { UserFiltered } from '@/services/users/Types'
import type { PrismaClient } from '@prisma/client'
import type { Adapter, AdapterUser, AdapterAccount } from 'next-auth/adapters'
Expand Down Expand Up @@ -39,6 +39,9 @@ async function generateUsername(prisma: PrismaClient, preferredUsername: string,
username: {
startsWith: preferredUsername
}
},
select: {
username: true
}
})

Expand All @@ -60,8 +63,8 @@ async function generateUsername(prisma: PrismaClient, preferredUsername: string,
}
}

for (let i = overlap + 1; i <= lastlastname.length; i++) {
username = `${username}${lastlastname.slice(overlap, i)}`
for (let i = overlap; i < lastlastname.length; i++) {
username = `${username}${lastlastname[i]}`
if (!existingUsernames.has(username)) {
return username
}
Expand All @@ -85,17 +88,16 @@ export default function VevenAdapter(prisma: PrismaClient): Adapter {

const username = await generateUsername(prisma, user.username, user.lastname)

const createdUser = await User.create.client('NEW').execute({
const createdUser = await prisma.user.create({
data: {
email: user.email,
firstname: user.firstname,
lastname: user.lastname,
username,
emailVerified: null, //(new Date()).toISOString(),
emailVerified: null,
},
params: undefined,
session: null
}, { withAuth: false })
select: userFilterSelection,
})

return convertToAdapterUser(createdUser)
},
Expand All @@ -112,9 +114,24 @@ export default function VevenAdapter(prisma: PrismaClient): Adapter {
console.log('get email')
console.log(email)
const user = await readUserOrNull({ email })
console.log(user)

return user && convertToAdapterUser(user)
if (user) {
return convertToAdapterUser(user)
}

const account = await prisma.feideAccount.findUnique({
where: {
email,
},
include: {
user: {
select: userFilterSelection,
},
},
})
if (!account) return null

return convertToAdapterUser(account.user)
},

async getUserByAccount({ providerAccountId, provider }) {
Expand All @@ -132,16 +149,16 @@ export default function VevenAdapter(prisma: PrismaClient): Adapter {
async updateUser(user) {
console.log('update u')

const updatedUser = await User.update.client('NEW').execute({
params: { id: Number(user.id) },
const updatedUser = await prisma.user.update({
where: {
id: Number(user.id),
},
data: {
email: user.email,
firstname: user.firstname,
lastname: user.lastname,
username: user.username,
},
session: null
}, { withAuth: false })
select: userFilterSelection,
})

return convertToAdapterUser(updatedUser)
},
Expand Down
2 changes: 1 addition & 1 deletion src/lib/feide/ConfigVars.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import 'server-only'

export const feideScope = 'openid email groups-edu userid userinfo-mobile userinfo-name longterm'
export const feideScope = 'openid email groups-edu userid userinfo-mobile userinfo-name'
1 change: 1 addition & 0 deletions src/lib/feide/FeideProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default function FeideProvider<P extends FeideProfile>(
lastname: extendedUserInfo.sn?.join(' '),
}
},
allowDangerousEmailAccountLinking: true, // This will try to link accounts with the same email
options,
}
}
25 changes: 25 additions & 0 deletions src/prisma/prismaservice/src/dobbelOmega/migrateUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ export default async function migrateUsers(
}
}
})

if (limits.users) {
const extraUsers = await Promise.all(['theodokl104', 'martiarm104', 'johanhst103', 'pauliusj103'].map(async uname =>
await vevenPrisma.users.findUnique({
where: {
username_order: {
username: uname.slice(0, -3),
order: Number(uname.slice(-3))
}
},
include: {
StudyProgrammes: {
select: {
years: true
}
}
}
})
))

extraUsers.forEach(user => {
if (user) users_.push(user)
})
}

const users = makeUsernameUnique(makeEmailUnique(users_))

const soelleGroup = await pnPrisma.omegaMembershipGroup.findUniqueOrThrow({
Expand Down
4 changes: 2 additions & 2 deletions src/services/notifications/email/systemMail/verifyEmail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export async function sendVerifyEmail(user: UserFiltered, email: string) {
sub: user.id,
}, emailValidationExpiration)

const link = `${process.env.DOMAIN}/register?token=${jwt}`
const link = `${process.env.NEXTAUTH_URL}/register?token=${jwt}`

await sendSystemMail(user.email, 'Bekreft e-post', <VerifyEmailTemplate user={user} link={link} />)
await sendSystemMail(parse.email, 'Bekreft e-post', <VerifyEmailTemplate user={user} link={link} />)
}
Loading