Skip to content

Commit

Permalink
Merge pull request #14 from mirea-ninja/main
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeryVerkhoturov authored Sep 15, 2023
2 parents f1571f4 + 3f3ea80 commit b3e3b54
Show file tree
Hide file tree
Showing 15 changed files with 916 additions and 90 deletions.
705 changes: 705 additions & 0 deletions public/assets/mirea.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/form/sidebar-search-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default function SidebarSearchInput({
id='search'
className='block w-full cursor-pointer rounded-2xl border-gray-400 bg-transparent py-2 pl-8 pr-12 placeholder-gray-500 caret-gray-400 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm'
placeholder='Быстрый поиск'
disabled
readOnly
/>
<div className='absolute inset-y-0 right-0 flex items-center pr-2.5'>
<kbd className='inline-flex max-h-6 items-center rounded border border-gray-400 px-1.5 font-sans text-sm font-medium'>
Expand Down
16 changes: 10 additions & 6 deletions src/components/layout/command-palette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ export default function CommandPalette({ open, setOpen }: CommandPaletteProps) {
},
)

const fetchPost = (postId: number, reason: PostItemReason) => {
const fetchPost = (slug: string, reason: PostItemReason) => {
return () => {
setOpen(false)
void router.push(reason === PostItemReason.FOUND ? `/finds/${postId}` : `/losses/${postId}`)
void router.push(reason === PostItemReason.FOUND ? `/finds/${slug}` : `/losses/${slug}`)
}
}

Expand All @@ -65,13 +65,13 @@ export default function CommandPalette({ open, setOpen }: CommandPaletteProps) {

const onSelectedOptionEnter = (
open: boolean,
selectedOption: { id: number; reason: PostItemReason } | null,
selectedOption: { id: number; slug: string; reason: PostItemReason } | null,
) => {
return (event: KeyboardEventHandler<HTMLInputElement>) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (open && selectedOption && event.key === 'Enter') {
fetchPost(selectedOption.id, selectedOption.reason)()
fetchPost(selectedOption.slug, selectedOption.reason)()
}
}
}
Expand Down Expand Up @@ -117,7 +117,11 @@ export default function CommandPalette({ open, setOpen }: CommandPaletteProps) {
onKeyDown={(e: any) =>
onSelectedOptionEnter(
open,
activeOption as { id: number; reason: PostItemReason } | null,
activeOption as {
id: number
slug: string
reason: PostItemReason
} | null,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
)(e)
}
Expand Down Expand Up @@ -156,7 +160,7 @@ export default function CommandPalette({ open, setOpen }: CommandPaletteProps) {
<Combobox.Option
key={item.id}
value={item}
onClick={fetchPost(item.id, item.reason)}
onClick={fetchPost(item.slug, item.reason)}
className={({ active }) =>
classNames(
'cursor-default select-none px-4 py-2',
Expand Down
4 changes: 2 additions & 2 deletions src/components/layout/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ export default function Layout(props: LayoutProps) {
<Image
priority
className='h-8 w-8'
src='/assets/ninja-logo-black.svg'
alt='Mirea Ninja'
src='/assets/mirea.svg'
alt='РТУ МИРЭА'
width={10}
height={10}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default function Logo() {
<Image
priority
className='h-8 w-8'
src='/assets/ninja-logo-black.svg'
alt='Mirea Ninja'
src='/assets/mirea.svg'
alt='РТУ МИРЭА'
width={10}
height={10}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,13 @@ const SocialNetworkDialogButton = ({
<ConnectDialog network={network} open={open} setOpen={setOpen} />
<div className='flex flex-row items-center justify-between space-x-8 md:justify-start'>
<div className='flex flex-row items-center space-x-2'>
<Image src={`/icons/${network}.svg`} alt={network} width={24} height={24} color='blue' />
<Image
src={`/icons/${network.toLowerCase()}.svg`}
alt={network}
width={24}
height={24}
color='blue'
/>
<span>{socialNetworkName}</span>
</div>
{isLinked ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ export default function EditProfileSlideOver(props: EditProfileSlideOverProps) {
)
}
>
<div className='pb-6'>
<div className='h-24 bg-blue-700 sm:h-20 lg:h-28' />
<div className='mt-4 px-4 py-5 sm:mt-0'>
<EditProfileSlideOverAvatar user={user} />
</div>
<EditProfileSlideOverBody user={user} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/profile/profile-body/profile-body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function ProfileBody() {
if (router.query.open === 'socials') {
editProfile.open()
}
}, [editProfile, router.query.open])
}, [router.query.open])

const profileInfo: { name: string; value: ReactNode }[] = user
? [
Expand Down
6 changes: 3 additions & 3 deletions src/components/seo/default-seo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ type DefaultSeoProps = Partial<Pick<React.ComponentProps<typeof NextSeo>, 'title
export default function DefaultSeo(props: DefaultSeoProps) {
return (
<NextSeo
title={props.title ?? 'Бюро находок Mirea Ninja'}
title={props.title ?? 'Бюро находок РТУ МИРЭА'}
description={props.description ?? 'Приложение для агрегации находок и объявлений пропаж'}
canonical='https://finds.mirea.ninja/'
canonical='https://finds.mirea.ru/'
openGraph={{
url: env.NEXT_PUBLIC_NEXTAUTH_URL,
title: 'Бюро находок Mirea Ninja',
title: 'Бюро находок РТУ МИРЭА',
description: 'Приложение для агрегации находок и объявлений пропаж',
images: [
{
Expand Down
52 changes: 37 additions & 15 deletions src/components/sign-in.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,52 @@
import Image from 'next/image'
import { signIn } from 'next-auth/react'
import { signIn, getProviders } from 'next-auth/react'
import Logo from '@/components/logo'
import { useRouter } from 'next/router'
import { useQuery } from '@tanstack/react-query'
import React from 'react'

const getProviderImage = (provider: string) => {
switch (provider) {
case 'mirea':
return '/assets/providers/mirea.svg'
case 'google':
return '/assets/providers/google.svg'
case 'github':
return '/assets/providers/github.svg'
default:
return '/assets/providers/mirea.svg'
}
}

export default function SignIn() {
const router = useRouter()
const callbackUrl = router.query.callbackUrl ? (router.query.callbackUrl as string) : '/'
const error = router.query.error

const providers: { id: string; name: string; image: string }[] = [
{
id: 'mirea',
name: 'ЛКC',
image: '/assets/providers/mirea.svg',
},
{
id: 'google',
name: 'Google',
image: '/assets/providers/google.svg',
const [providers, setProviders] = React.useState<{ id: string; name: string; image: string }[]>(
[],
)

useQuery(
['providers'],
async () => {
const providers = await getProviders()
return providers
},
{
id: 'github',
name: 'GitHub',
image: '/assets/providers/github.svg',
onSuccess: (providers) => {
if (!providers) return

setProviders(
Object.values(providers).map((provider) => ({
id: provider.id,
name: provider.name,
image: getProviderImage(provider.id),
})),
)
},
},
]
)

return (
<main className='h-screen bg-white'>
Expand Down
22 changes: 16 additions & 6 deletions src/env.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ export const env = createEnv({
REDIS_URL: z.string().url(),
NEXTAUTH_SECRET: z.string().min(1),
NEXTAUTH_URL: z.string().url(),
MIREA_CLIENT_ID: z.string().min(1),
MIREA_CLIENT_SECRET: z.string().min(1),
GOOGLE_CLIENT_ID: z.string().min(1),
GOOGLE_CLIENT_SECRET: z.string().min(1),
GITHUB_CLIENT_ID: z.string().min(1),
GITHUB_CLIENT_SECRET: z.string().min(1),

MIREA_CLIENT_ID: z.string().nullish(),
MIREA_CLIENT_SECRET: z.string().nullish(),

MIREA_LKS_CLIENT_ID: z.string().nullish(),
MIREA_LKS_CLIENT_SECRET: z.string().nullish(),

GOOGLE_CLIENT_ID: z.string().nullish(),
GOOGLE_CLIENT_SECRET: z.string().nullish(),

GITHUB_CLIENT_ID: z.string().nullish(),
GITHUB_CLIENT_SECRET: z.string().nullish(),

CALLBACK_URL: z.string().url(),
CALLBACK_SECRET_URL_STRING: z.string().min(1).max(32),
Expand Down Expand Up @@ -86,6 +92,10 @@ export const env = createEnv({

MIREA_CLIENT_ID: process.env.MIREA_CLIENT_ID,
MIREA_CLIENT_SECRET: process.env.MIREA_CLIENT_SECRET,

MIREA_LKS_CLIENT_ID: process.env.MIREA_LKS_CLIENT_ID,
MIREA_LKS_CLIENT_SECRET: process.env.MIREA_LKS_CLIENT_SECRET,

GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID,
Expand Down
2 changes: 2 additions & 0 deletions src/server/api/routers/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ async function searchPosts(query: string, reason: PostItemReason) {
name: true,
description: true,
reason: true,
slug: true,
},
where: {
status,
Expand All @@ -376,6 +377,7 @@ async function searchPosts(query: string, reason: PostItemReason) {
name: true,
description: true,
reason: true,
slug: true,
},
where: {
status,
Expand Down
5 changes: 2 additions & 3 deletions src/server/auth-providers/mirea-ninja-lks-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ type MireaNinjaLKSProviderConfig = Required<Pick<OAuthConfig<any>, 'clientId' |

export default function MireaNinjaLksProvider(options: MireaNinjaLKSProviderConfig): Provider {
return {
id: 'mirea',
name: 'Mirea',
id: 'lks',
name: 'LKS',
type: 'oauth',
version: '2.0',
accessTokenUrl: 'https://auth-app.mirea.ru/oauth/token',
Expand Down Expand Up @@ -51,7 +51,6 @@ export default function MireaNinjaLksProvider(options: MireaNinjaLKSProviderConf
image: 'https://lk.mirea.ru' + profile.arUser.PHOTO,
isBlocked: false,
blockReason: null,
secretSocialNetworksAuthPayload: '',
}
},
clientId: options.clientId,
Expand Down
53 changes: 53 additions & 0 deletions src/server/auth-providers/mirea-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { OAuthConfig, Provider } from 'next-auth/providers'
import { nicknameValidation } from '@/lib/nickname-validation'
import { Role } from '@prisma/client'

interface UserInfo {
username: string
email: string
name: string
lastname: string
middlename: string
uid: string
}

type MireaProviderConfig = Required<Pick<OAuthConfig<any>, 'clientId' | 'clientSecret'>>

export default function MireaProvider(options: MireaProviderConfig): Provider {
return {
id: 'mirea',
name: 'RTU MIREA',
type: 'oauth',
version: '2.0',
accessTokenUrl: 'https://login.mirea.ru/oauth2/v1/token/',
requestTokenUrl: 'https://login.mirea.ru/oauth2/v1/token/',
authorization: {
url: 'https://login.mirea.ru/oauth2/v1/authorize/',
params: { scope: 'basic' },
},
token: {
url: 'https://login.mirea.ru/oauth2/v1/token/',
},
userinfo: {
url: 'https://login.mirea.ru/resources/v1/userinfo',
},
checks: ['state'],
async profile(profile: UserInfo) {
const name = [profile.name, profile.lastname].join(' ')
return {
id: profile.uid,
name,
nickname: await nicknameValidation(name),
email: profile.email,
emailVerified: new Date(),
userInfo: null,
role: Role.USER,
image: null,
isBlocked: false,
blockReason: null,
}
},
clientId: options.clientId,
clientSecret: options.clientSecret,
}
}
Loading

0 comments on commit b3e3b54

Please sign in to comment.