updated all dependencies

pull/8/head
qwertyforce 2022-08-14 21:51:04 +03:00
parent cc87abe6b5
commit dfd6ffe02b
78 changed files with 5649 additions and 14151 deletions

View File

@ -1,13 +0,0 @@
{
"env": {
"development": {
"presets": ["next/babel"]
},
"production": {
"presets": ["next/babel"]
},
"test": {
"presets": [["next/babel", { "preset-env": { "modules": "commonjs" } }]]
}
}
}

View File

@ -4,11 +4,6 @@ module.exports = {
"es2020": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
@ -22,10 +17,15 @@ module.exports = {
"@typescript-eslint"
],
"rules": {
// suppress errors for missing 'import React' in files
"@typescript-eslint/explicit-module-boundary-types": "off",
"react/react-in-jsx-scope": "off",
// allow jsx syntax in js files (for next.js project)
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx",".ts", ".tsx"] }], //should add ".ts" if typescript project
}
// suppress errors for missing 'import React' in files
"@typescript-eslint/explicit-module-boundary-types": "off",
"react/react-in-jsx-scope": "off",
// allow jsx syntax in js files (for next.js project)
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".ts", ".tsx"] }], //should add ".ts" if typescript project
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended"
],
};

2
additional.d.ts vendored
View File

@ -12,7 +12,7 @@ declare global {
declare module 'http' {
interface IncomingMessage {
session: any
session?: any
}
}

1
next-env.d.ts vendored
View File

@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited

View File

@ -33,7 +33,6 @@ module.exports = {
}
return config
},
webpack5: false,
env: { //https://nextjs.org/docs/api-reference/next.config.js/environment-variables
recaptcha_site_key: "6LcqV9QUAAAAAEybBVr0FWnUnFQmOVxGoQ_Muhtb",
api_domain: "http://localhost/public_api",

View File

@ -1,5 +1,5 @@
{
"watch": ["server"],
"exec": "npx ts-node --project tsconfig.server.json server/index.ts",
"exec": "npx ts-node --project tsconfig.server.json src/server/index.ts",
"ext": "js ts"
}

18997
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,67 +2,63 @@
"name": "scenery",
"version": "2.0.0",
"scripts": {
"dev": "nodemon",
"build": "next build && tsc --project tsconfig.server.json",
"dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider nodemon",
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider next build && tsc --project tsconfig.server.json",
"build_pages": "next build",
"build_server": "tsc --project tsconfig.server.json",
"start": "cross-env NODE_ENV=production node dist/server/index.js",
"start": "cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=production node dist/server/index.js",
"start_dev": "cross-env NODE_ENV=development node dist/server/index.js",
"pm2_start_ms": "pm2 start ./ambience/microservices.config.js",
"pm2_start": "pm2 start ./ambience/microservices.config.js && pm2 start"
},
"dependencies": {
"@emotion/cache": "^11.10.1",
"@emotion/react": "^11.10.0",
"@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.0",
"@fastify/cookie": "^7.4.0",
"@fastify/cors": "^8.1.0",
"@fastify/formbody": "^7.0.1",
"@fastify/multipart": "^7.1.0",
"@fastify/session": "^9.0.0",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15",
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.60",
"@ronomon/crypto-async": "^5.0.1",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.10.0",
"@types/bcrypt": "^5.0.0",
"@types/clean-css": "^4.2.5",
"@types/grecaptcha": "^3.0.3",
"@types/node": "^16.4.13",
"@types/nodemailer": "^6.4.4",
"@types/puppeteer": "^5.4.4",
"@types/react": "^17.0.16",
"@types/sharp": "^0.28.5",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/parser": "^4.29.1",
"axios": "^0.21.1",
"@types/grecaptcha": "^3.0.4",
"@types/node": "^18.7.3",
"@types/nodemailer": "^6.4.5",
"@types/react": "^18.0.17",
"@types/sharp": "^0.30.5",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"axios": "^0.27.2",
"bcrypt": "^5.0.1",
"clean-css": "^5.1.5",
"clsx": "^1.1.1",
"compression-webpack-plugin": "^8.0.1",
"connect-mongo": "^4.4.1",
"clsx": "^1.2.1",
"compression-webpack-plugin": "^10.0.0",
"connect-mongo": "^4.6.0",
"cross-env": "^7.0.3",
"dotenv": "^10.0.0",
"eslint": "^7.32.0",
"eslint-config-next": "^11.0.1",
"eslint-plugin-react": "^7.24.0",
"express-session": "^1.17.2",
"fastify": "^3.20.1",
"fastify-cookie": "^5.3.1",
"fastify-cors": "^6.0.2",
"fastify-formbody": "^5.1.0",
"fastify-multipart": "^4.0.7",
"eslint": "^8.22.0",
"eslint-plugin-react": "^7.30.1",
"express-session": "^1.17.3",
"fastify": "^4.4.0",
"fastify-recaptcha": "^1.0.0",
"fastify-session": "github:qwertyforce/fastify-session",
"file-type": "^16.5.3",
"file-type": "^16.5.4",
"form-data": "^4.0.0",
"jest": "^27.0.6",
"json-schema-to-ts": "^1.6.4",
"material-ui-dropzone": "^3.5.0",
"mongodb": "^4.1.1",
"next": "^11.1.0",
"nodemailer": "^6.6.3",
"nodemon": "^2.0.12",
"prop-types": "^15.7.2",
"puppeteer": "^10.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"json-schema-to-ts": "^2.5.5",
"mongodb": "^4.8.1",
"mui-file-dropzone": "^4.0.1",
"next": "^12.2.5",
"nodemailer": "^6.7.8",
"nodemon": "^2.0.19",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-photo-gallery": "github:qwertyforce/react_photo_gallery_build",
"sharp": "^0.28.3",
"typescript": "^4.3.5"
"sharp": "^0.30.7",
"tss-react": "^3.7.1",
"typescript": "^4.7.4"
}
}

View File

@ -1,36 +0,0 @@
import { Fragment, useEffect } from 'react'
import Head from 'next/head'
import { AppProps } from 'next/app'
import { ThemeProvider } from '@material-ui/core/styles'
import CssBaseline from '@material-ui/core/CssBaseline'
import theme from '../components/theme'
import { DataContextProvider } from "../components/DataContext"
import "../components/styles.css"
export default function MyApp(props: AppProps) {
const { Component, pageProps } = props
useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side')
if (jssStyles) {
jssStyles.parentElement?.removeChild(jssStyles)
}
if (typeof window !== "undefined" && localStorage.getItem("useIPFS") === null) {
localStorage.setItem('useIPFS', 'false')
}
}, [])
return (
<Fragment>
<Head>
<title>Scenery</title>
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
</Head>
<ThemeProvider theme={theme}>
<CssBaseline />
<DataContextProvider>
<Component {...pageProps} />
</DataContextProvider>
</ThemeProvider>
</Fragment>
)
}

View File

@ -1,89 +0,0 @@
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { ServerStyleSheets } from '@material-ui/core/styles'
import theme from '../components/theme'
import CleanCSS from "clean-css"
import { Children } from 'react'
const cleanCSS = new CleanCSS({
level: {
1: {},
2: {}
}
})
const minified_css_cache = new Map()
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
{/* PWA primary color */}
<meta name="theme-color" content={theme.palette.primary.main} />
<link rel='preconnect' href='https://fonts.gstatic.com' crossOrigin="anonymous" />
<link rel="preload" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" as="style" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
</Head>
<body>
<Main />
<NextScript />
<script defer src={`https://www.google.com/recaptcha/api.js?render=${process.env.recaptcha_site_key}`}></script>
</body>
</Html>
)
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets()
const originalRenderPage = ctx.renderPage
ctx.renderPage = () =>
originalRenderPage({
// eslint-disable-next-line react/display-name
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
let css = sheets.toString()
if (css && process.env.NODE_ENV === "production") {
const min_css = minified_css_cache.get(css)
if (min_css) {
css = min_css
} else {
const old_css = css
css = cleanCSS.minify(css).styles
minified_css_cache.set(old_css, css)
}
}
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [...Children.toArray(initialProps.styles), <style id="jss-server-side" key="jss-server-side" dangerouslySetInnerHTML={{ __html: css }}></style>],
}
}

View File

@ -1,22 +1,23 @@
import { useContext, useState } from 'react'
import { alpha, makeStyles } from '@material-ui/core/styles'
import AppBar from '@material-ui/core/AppBar'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
import SearchIcon from '@material-ui/icons/Search'
import InputBase from '@material-ui/core/InputBase'
import { KeyboardEvent, useContext, useState } from 'react'
import { alpha } from '@mui/material/styles';
import { makeStyles } from 'tss-react/mui';
import AppBar from '@mui/material/AppBar'
import Toolbar from '@mui/material/Toolbar'
import Typography from '@mui/material/Typography'
import SearchIcon from '@mui/icons-material/Search'
import InputBase from '@mui/material/InputBase'
import Link from './Link'
import HelpOutlineIcon from '@material-ui/icons/HelpOutline'
import ImageSearchIcon from '@material-ui/icons/ImageSearch'
import { IconButton } from '@material-ui/core'
import Switch from '@material-ui/core/Switch'
import HelpOutlineIcon from '@mui/icons-material/HelpOutline'
import ImageSearchIcon from '@mui/icons-material/ImageSearch'
import { IconButton } from '@mui/material'
import Switch from '@mui/material/Switch'
import { useRouter } from 'next/router'
import MoreIcon from '@material-ui/icons/MoreVert'
import MenuItem from '@material-ui/core/MenuItem'
import Menu from '@material-ui/core/Menu'
import MoreIcon from '@mui/icons-material/MoreVert'
import MenuItem from '@mui/material/MenuItem'
import Menu from '@mui/material/Menu'
import { DataContext } from "./DataContext"
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles()((theme:any) => ({
app_bar: {
backgroundColor: "#606ca9"
},
@ -58,7 +59,7 @@ const useStyles = makeStyles((theme) => ({
inputInput: {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('md')]: {
@ -90,12 +91,12 @@ const useStyles = makeStyles((theme) => ({
display: 'none',
}
}
}))
}));
function Search(props: { semanticModeChecked: boolean }) {
const placeholders = ["tag1&&(tag2||tag3)", "a picture of a winter forest"]
const classes = useStyles()
const { classes } = useStyles()
const router = useRouter()
const [tags, setTags] = useState(router.query.q || '')
const searchPlaceholer = placeholders[Number(router.query.semantic || Number(props.semanticModeChecked))]
@ -113,7 +114,7 @@ function Search(props: { semanticModeChecked: boolean }) {
<InputBase
placeholder={searchPlaceholer}
onChange={(e) => setTags(e.target.value)}
onKeyPress={(e) => handleKeyPress(e)}
onKeyPress={(e: KeyboardEvent<HTMLDivElement>) => handleKeyPress(e)}
classes={{
root: classes.inputRoot,
input: classes.inputInput,
@ -127,7 +128,7 @@ function Search(props: { semanticModeChecked: boolean }) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function MobileMenu(props: any) {
const classes = useStyles()
const { classes } = useStyles()
return (
<Menu
anchorEl={props.mobileMoreAnchorEl}
@ -165,7 +166,7 @@ function MobileMenu(props: any) {
export default function DenseAppBar() {
const dataContext = useContext(DataContext)
const classes = useStyles()
const { classes } = useStyles()
const router = useRouter()
const mobileMenuId = 'menu-mobile'
const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = useState<Element | null>(null)
@ -200,10 +201,20 @@ export default function DenseAppBar() {
<Switch color="secondary" checked={semanticModeChecked} onChange={toggleSemanticModeChecked} />
<span>semantic<sub className={classes.sub}>beta</sub></span>
</div>
<IconButton component={Link} color="inherit" aria-label="search_syntax" href={`${process.env.domain}/search_syntax`}>
<IconButton
component={Link}
color="inherit"
aria-label="search_syntax"
href={`${process.env.domain}/search_syntax`}
size="large">
<HelpOutlineIcon />
</IconButton>
<IconButton component={Link} color="inherit" aria-label="reverse_search" href={`${process.env.domain}/reverse_search`}>
<IconButton
component={Link}
color="inherit"
aria-label="reverse_search"
href={`${process.env.domain}/reverse_search`}
size="large">
<ImageSearchIcon />
</IconButton>
</div>
@ -214,7 +225,7 @@ export default function DenseAppBar() {
aria-haspopup="true"
onClick={handleMobileMenuOpen}
color="inherit"
>
size="large">
<MoreIcon />
</IconButton>
</div>
@ -222,5 +233,5 @@ export default function DenseAppBar() {
</AppBar>
<MobileMenu {...{ dataContext, semanticModeChecked, mobileMoreAnchorEl, isMobileMenuOpen, handleMobileMenuClose, toggleSemanticModeChecked }} />
</div>
)
);
}

View File

@ -1,14 +1,14 @@
import { makeStyles } from '@material-ui/core/styles'
import { makeStyles } from 'tss-react/mui';
import Link from './Link'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
footer: {
display: "flex",
justifyContent: "center"
}
}))
}));
export default function Footer() {
const classes = useStyles()
const { classes } = useStyles()
return (
<div>
<div className={classes.footer}>

View File

@ -3,7 +3,7 @@ import PhotoInterface from "./../types/photo"
import Gallery from "react-photo-gallery"
import { DataContext } from "./DataContext"
import Photo from './Photo'
import CircularProgress from '@material-ui/core/CircularProgress'
import CircularProgress from '@mui/material/CircularProgress'
export default function GalleryWrapper(props: { photos: PhotoInterface[] }) {
const [photos, setPhotos] = useState<PhotoInterface[]>([])
@ -23,8 +23,8 @@ export default function GalleryWrapper(props: { photos: PhotoInterface[] }) {
} else {
setPhotos(props.photos)
}
setShowLoading(false)
}
setShowLoading(false)
}, [dataContext])
return (

View File

@ -3,7 +3,7 @@
import clsx from 'clsx'
import { useRouter } from 'next/router'
import NextLink, { LinkProps as NextLinkProps } from 'next/link'
import MuiLink, { LinkProps as MuiLinkProps } from '@material-ui/core/Link'
import MuiLink, { LinkProps as MuiLinkProps } from '@mui/material/Link'
import { forwardRef } from 'react'
type NextComposedProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> &

View File

@ -1,5 +1,5 @@
import { createTheme } from '@material-ui/core/styles'
import { red } from '@material-ui/core/colors'
import { createTheme } from '@mui/material/styles'
import { red } from '@mui/material/colors'
// Create a theme instance.
const theme = createTheme({

View File

@ -10,7 +10,7 @@ const server_config = {
GITHUB_REDIRECT_URI: "http://localhost/auth/github/callback",
gmail_user: "auth.test.reg.email@gmail.com",
gmail_password: "sbuLBh9rAV8XD2",
mongodb_url: "mongodb://localhost/",
mongodb_url: "mongodb://127.0.0.1/",
server_port: "80",
session_secret: "ghuieorifigyfuu9u3i45jtr73490548t7ht",
root_path: path.join(__dirname, "..", ".."),

32
src/pages/_app.tsx Normal file
View File

@ -0,0 +1,32 @@
import { EmotionCache } from "@emotion/react";
import { CacheProvider } from '@emotion/react';
import createCache from "@emotion/cache"
import { ThemeProvider } from "@mui/material/styles"
import CssBaseline from "@mui/material/CssBaseline"
import theme from '../components/theme'
import { useEffect } from "react";
import { DataContextProvider } from "../components/DataContext"
import { AppProps } from 'next/app'
import "../components/styles.css"
let muiCache: EmotionCache | undefined = undefined;
export const createMuiCache = () => muiCache = createCache({ "key": "mui", "prepend": true })
export default function App({ Component, pageProps }: AppProps) {
useEffect(() => {
if (typeof window !== "undefined" && localStorage.getItem("useIPFS") === null) {
localStorage.setItem('useIPFS', 'false')
}
}, [])
return (
<CacheProvider value={muiCache ?? createMuiCache()}>
<ThemeProvider theme={theme}>
<CssBaseline />
<DataContextProvider>
<Component {...pageProps} />
</DataContextProvider>
</ThemeProvider>
</CacheProvider>
)
}

32
src/pages/_document.tsx Normal file
View File

@ -0,0 +1,32 @@
import { withEmotionCache } from "tss-react/nextJs"
import { createMuiCache } from "./_app"
import Document, { Html, Head, Main, NextScript } from 'next/document'
import theme from '../components/theme'
class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
{/* PWA primary color */}
<meta name="theme-color" content={theme.palette.primary.main} />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
</Head>
<body>
<Main />
<NextScript />
<script defer src={`https://www.google.com/recaptcha/api.js?render=${process.env.recaptcha_site_key}`}></script>
</body>
</Html>
)
}
}
export default withEmotionCache({
//If you have a custom document pass it instead
"Document": MyDocument,
//Every emotion cache used in the app should be provided.
//Caches for MUI should use "prepend": true.
"getCaches": ()=> [ createMuiCache() ]
});

View File

@ -1,6 +1,6 @@
import Container from '@material-ui/core/Container'
import Typography from '@material-ui/core/Typography'
import Box from '@material-ui/core/Box'
import Container from '@mui/material/Container'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import AppBar from '../components/AppBar'
export default function About() {

View File

@ -1,23 +1,23 @@
import AppBar from '../components/AppBar'
import db_ops from '../server/helpers/db_ops'
import Button from '@material-ui/core/Button'
import Button from '@mui/material/Button'
import axios from 'axios'
import TextField from '@material-ui/core/TextField'
import Backdrop from '@material-ui/core/Backdrop'
import CircularProgress from '@material-ui/core/CircularProgress'
import TextField from '@mui/material/TextField'
import Backdrop from '@mui/material/Backdrop'
import CircularProgress from '@mui/material/CircularProgress'
import { GetServerSideProps } from 'next'
import { makeStyles } from '@material-ui/core/styles'
import { useState } from 'react'
import { makeStyles } from 'tss-react/mui';
import { KeyboardEvent, useState } from 'react'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
backdrop: {
zIndex: 9999,
color: '#fff',
},
}))
}));
export default function deleteImage() {
const classes = useStyles()
const { classes } = useStyles()
const [open, setOpen] = useState(false)
const [imageID, setImageID] = useState(0)
const handleKeyPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
@ -56,8 +56,8 @@ export default function deleteImage() {
label=" image id"
placeholder="image id"
margin="normal"
onChange={(e) => setImageID(parseInt(e.target.value) || 0)}
onKeyPress={(e) => handleKeyPress(e)}
onChange={(e:any) => setImageID(parseInt(e.target.value) || 0)}
onKeyPress={(e: KeyboardEvent<HTMLDivElement>) => handleKeyPress(e)}
/>
<Button onClick={() => { delete_image() }} variant="contained" color="primary" >Delete image</Button>
</div>
@ -65,7 +65,7 @@ export default function deleteImage() {
}
export const getServerSideProps: GetServerSideProps = async (context) => {
if (context.req?.session?.authed && context.req?.session?.user_id) {
if (context.req?.session?.user_id) {
const user = await db_ops.activated_user.find_user_by_id(context.req.session.user_id)
if (user && user.isAdmin) {
return {

View File

@ -1,7 +1,7 @@
import AppBar from '../../components/AppBar'
import db_ops from '../../server/helpers/db_ops'
import Head from 'next/head'
import Button from '@material-ui/core/Button'
import Button from '@mui/material/Button'
import axios from 'axios'
import { useEffect } from 'react'
import { GetServerSideProps } from 'next'
@ -42,7 +42,7 @@ export default function Image(props: any) {
}
export const getServerSideProps: GetServerSideProps = async (context) => {
if (context.req?.session?.authed && context.req?.session?.user_id) {
if (context.req?.session?.user_id) {
const user = await db_ops.activated_user.find_user_by_id(context.req?.session?.user_id)
if (typeof context.params?.id === "string" && user && user.isAdmin) {
const img = await db_ops.image_ops.find_image_by_id(parseInt(context.params.id))

View File

@ -1,19 +1,19 @@
import AppBar from '../../components/AppBar'
import { DataContext } from "../../components/DataContext"
import { makeStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper'
import Grid from '@material-ui/core/Grid'
import LabelIcon from '@material-ui/icons/Label'
import CalendarTodayIcon from '@material-ui/icons/CalendarToday'
import AspectRatioIcon from '@material-ui/icons/AspectRatio'
import LinkIcon from '@material-ui/icons/Link'
import { makeStyles } from 'tss-react/mui';
import Paper from '@mui/material/Paper'
import Grid from '@mui/material/Grid'
import LabelIcon from '@mui/icons-material/Label'
import CalendarTodayIcon from '@mui/icons-material/CalendarToday'
import AspectRatioIcon from '@mui/icons-material/AspectRatio'
import LinkIcon from '@mui/icons-material/Link'
import { GetServerSideProps } from 'next'
import db_ops from '../../server/helpers/db_ops'
import CreateIcon from '@material-ui/icons/Create'
import Chip from '@material-ui/core/Chip'
import CreateIcon from '@mui/icons-material/Create'
import Chip from '@mui/material/Chip'
import { useContext, useEffect, useState } from 'react'
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles()((theme:any) => ({
root: {
flexGrow: 1,
},
@ -37,7 +37,7 @@ const useStyles = makeStyles((theme) => ({
textAlign: 'center',
color: theme.palette.text.secondary,
},
}))
}));
interface ImageProps {
filename: string,
@ -54,7 +54,7 @@ interface ImageProps {
// upscaled: string,
}
export default function Image(props: ImageProps) {
const classes = useStyles()
const { classes } = useStyles()
const dataContext = useContext(DataContext)
const [photoSrc, setPhotoSrc] = useState("")
useEffect(() => {

View File

@ -1,22 +1,22 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { ChangeEvent, Dispatch, SetStateAction, useState } from 'react'
import Box from '@material-ui/core/Box'
import Box from '@mui/material/Box'
import AppBar from '../components/AppBar'
import { DropzoneAreaBase } from 'material-ui-dropzone'
import Button from '@material-ui/core/Button'
import { DropzoneAreaBase } from 'mui-file-dropzone'
import Button from '@mui/material/Button'
import axios from "axios"
import db_ops from '../server/helpers/db_ops'
import Backdrop from '@material-ui/core/Backdrop'
import CircularProgress from '@material-ui/core/CircularProgress'
import { makeStyles } from '@material-ui/core/styles'
import TextField from '@material-ui/core/TextField'
import Paper from '@material-ui/core/Paper'
import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete'
import Chip from '@material-ui/core/Chip'
import Backdrop from '@mui/material/Backdrop'
import CircularProgress from '@mui/material/CircularProgress'
import { makeStyles } from 'tss-react/mui';
import TextField from '@mui/material/TextField'
import Paper from '@mui/material/Paper'
import Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete'
import Chip from '@mui/material/Chip'
import { GetServerSideProps } from 'next'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
backdrop: {
zIndex: 9999,
color: '#fff',
@ -41,7 +41,7 @@ const useStyles = makeStyles(() => ({
tags_field: {
margin: 10
}
}))
}));
function isValidURL(url: string) {
const RegExp = /^(?:(?:(?:https?):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i
@ -53,7 +53,7 @@ function isValidURL(url: string) {
}
function AutoCompleteTagTextField(props: { all_tags: string[], selectedTags: string[], setSelectedTags: Dispatch<SetStateAction<string[]>> }) {
const classes = useStyles()
const { classes } = useStyles()
const [inputValue, setInputValue] = useState("")
const [openTagsAutocomplete, setOpenTagsAutocomplete] = useState(false)
const filterOptions = createFilterOptions({
@ -93,7 +93,7 @@ function AutoCompleteTagTextField(props: { all_tags: string[], selectedTags: str
filterSelectedOptions
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip variant="outlined" key={option as string} label={option as string} {...getTagProps({ index })} />
<Chip variant="outlined" {...getTagProps({ index })} key={option as string} label={option as string} />
))
}
renderInput={(params) => (
@ -103,7 +103,7 @@ function AutoCompleteTagTextField(props: { all_tags: string[], selectedTags: str
}
export default function Import(props: { err: boolean, all_tags: string[] }) {
const classes = useStyles()
const { classes } = useStyles()
const [URL, setUrl] = useState("")
const [source_URL, setSource_URL] = useState("")
const [selectedTags, setSelectedTags] = useState<string[]>([])
@ -208,7 +208,7 @@ export default function Import(props: { err: boolean, all_tags: string[] }) {
<div className={classes.url_div}>
<TextField
value={source_URL}
onChange={(e) => setSource_URL(e.target.value)}
onChange={(e:any) => setSource_URL(e.target.value)}
type="text"
label="Source url"
className={classes.url_text_field}
@ -220,7 +220,7 @@ export default function Import(props: { err: boolean, all_tags: string[] }) {
<Paper className={classes.upload_interface} elevation={6}>
<h4 style={{ margin: 0, marginBottom: "5px" }}>Image</h4>
<div className={classes.fetch_img_div}>
<TextField onChange={(e) => setUrl(e.target.value)} value={URL}
<TextField onChange={(e:any) => setUrl(e.target.value)} value={URL}
className={classes.url_text_field} label="Image url"
placeholder="https://somesite.com/image.png" variant="outlined" size="small" />
<Button onClick={get_image_by_url} size="small" variant="outlined">Fetch</Button>
@ -251,7 +251,7 @@ export default function Import(props: { err: boolean, all_tags: string[] }) {
)
}
export const getServerSideProps: GetServerSideProps = async (context) => {
if (context.req.session.authed && context.req.session.user_id) {
if (context.req?.session?.user_id) {
const user = await db_ops.activated_user.find_user_by_id(context.req.session.user_id)
if (user?.isAdmin) {
const imgs = await db_ops.image_ops.get_all_images()

View File

@ -1,18 +1,18 @@
import { makeStyles } from '@material-ui/core/styles'
import { makeStyles } from 'tss-react/mui';
import AppBar from '../../components/AppBar'
import db_ops from '../../server/helpers/db_ops'
import Pagination from '@material-ui/lab/Pagination'
import Pagination from '@mui/material/Pagination'
import { GetStaticProps, GetStaticPaths } from 'next'
import { useRouter } from 'next/router'
import Link from '../../components/Link'
import Footer from '../../components/Footer'
import GalleryWrapper from '../../components/GalleryWrapper'
import ErrorPage from 'next/error'
import PaginationItem from "@material-ui/lab/PaginationItem/PaginationItem"
import PaginationItem from '@mui/material/PaginationItem'
import PhotoInterface from '../../types/photo'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
flex_center: {
display: "flex",
justifyContent: 'center'
@ -23,7 +23,7 @@ const useStyles = makeStyles(() => ({
hidden: {
visibility: "hidden"
}
}))
}));
interface LastAddedPageProps {
photos: PhotoInterface[],
@ -34,7 +34,7 @@ interface LastAddedPageProps {
export default function LastAddedPage(props: LastAddedPageProps) {
const classes = useStyles()
const { classes } = useStyles()
const router = useRouter()
if (router.isFallback) {
return <ErrorPage statusCode={404} />
@ -80,19 +80,20 @@ export const getStaticProps: GetStaticProps = async (context) => {
height: image.height
})
}
return {
props: {
photos: photos,
current_page: page,
max_page: Math.ceil(total_num_of_images / images_on_page)
},
revalidate: 1 * 60 //1 min
}
}
}
return {
props: { err: true },
revalidate: 1 * 60 //1 min
return {
props: {
photos: photos,
current_page: page,
max_page: Math.ceil(total_num_of_images / images_on_page)
},
revalidate: 1 * 60 //1 min
}
} else {
return {
props: { err: true },
revalidate: 1 * 60 //1 min
}
}
}

View File

@ -1,20 +1,20 @@
import axios from 'axios'
import { makeStyles } from "@material-ui/core/styles"
import TextField from '@material-ui/core/TextField'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import CardActions from '@material-ui/core/CardActions'
import Button from '@material-ui/core/Button'
import Box from '@material-ui/core/Box'
import { makeStyles } from 'tss-react/mui';
import TextField from '@mui/material/TextField'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import CardActions from '@mui/material/CardActions'
import Button from '@mui/material/Button'
import Box from '@mui/material/Box'
import Link from '../components/Link'
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import Grid from "@material-ui/core/Grid"
import SvgIcon from "@material-ui/core/SvgIcon"
import Grid from "@mui/material/Grid"
import SvgIcon from "@mui/material/SvgIcon"
import { faGoogle, faGithub } from "@fortawesome/free-brands-svg-icons"
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { KeyboardEvent, useEffect, useState } from 'react'
const useStyles = makeStyles(theme => ({
const useStyles = makeStyles()((theme:any) => ({
container: {
display: 'flex',
flexWrap: 'wrap',
@ -34,11 +34,11 @@ const useStyles = makeStyles(theme => ({
Oauth: {
'margin-left': '0px !important'
}
}))
}));
function LoginForm() {
const router = useRouter()
const classes = useStyles()
const { classes } = useStyles()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [isButtonDisabled, setIsButtonDisabled] = useState(true)
@ -102,8 +102,8 @@ function LoginForm() {
label="Email"
placeholder="Email"
margin="normal"
onChange={(e) => setEmail(e.target.value)}
onKeyPress={(e) => handleKeyPress(e)}
onChange={(e:any) => setEmail(e.target.value)}
onKeyPress={(e: KeyboardEvent<HTMLDivElement>) => handleKeyPress(e)}
/>
<TextField
error={error}
@ -114,8 +114,8 @@ function LoginForm() {
placeholder="Password"
margin="normal"
helperText={helperText}
onChange={(e) => setPassword(e.target.value)}
onKeyPress={(e) => handleKeyPress(e)}
onChange={(e:any) => setPassword(e.target.value)}
onKeyPress={(e: KeyboardEvent<HTMLDivElement>) => handleKeyPress(e)}
/>
<Box display="flex" justifyContent="flex-end">
<Button color="primary" component={Link} href="/forgot_pw">
@ -143,7 +143,7 @@ function LoginForm() {
className={classes.Oauth}
container
direction="row"
justify="center"
justifyContent="center"
spacing={1}
alignItems="center"
>
@ -178,7 +178,7 @@ function LoginForm() {
</CardActions>
</Card>
</form>
)
);
}
export default LoginForm

View File

@ -1,20 +1,20 @@
import Container from '@material-ui/core/Container'
import Typography from '@material-ui/core/Typography'
import Box from '@material-ui/core/Box'
import Container from '@mui/material/Container'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import AppBar from '../../components/AppBar'
import { makeStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper'
import { makeStyles } from 'tss-react/mui';
import Paper from '@mui/material/Paper'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
api_route: {
padding: 5,
marginTop: 10,
width: "fit-content!important"
}
}))
}));
export default function Api() {
const classes = useStyles()
const { classes } = useStyles()
return (
<div>
<AppBar />

View File

@ -1,17 +1,17 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useState } from 'react'
import Box from '@material-ui/core/Box'
import Box from '@mui/material/Box'
import AppBar from '../components/AppBar'
import { DropzoneAreaBase } from 'material-ui-dropzone'
import Button from '@material-ui/core/Button'
import { DropzoneAreaBase } from 'mui-file-dropzone'
import Button from '@mui/material/Button'
import axios from "axios"
import { useRouter } from 'next/router'
import Backdrop from '@material-ui/core/Backdrop'
import CircularProgress from '@material-ui/core/CircularProgress'
import { makeStyles } from '@material-ui/core/styles'
import TextField from '@material-ui/core/TextField'
import Backdrop from '@mui/material/Backdrop'
import CircularProgress from '@mui/material/CircularProgress'
import { makeStyles } from 'tss-react/mui';
import TextField from '@mui/material/TextField'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
backdrop: {
zIndex: 9999,
color: '#fff',
@ -25,7 +25,7 @@ const useStyles = makeStyles(() => ({
width: "300px",
marginRight: "10px"
}
}))
}));
function isValidURL(url: string) {
const RegExp = /^(?:(?:(?:https?):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i
if (RegExp.test(url)) {
@ -36,7 +36,7 @@ function isValidURL(url: string) {
}
export default function ReverseSearch() {
const classes = useStyles()
const { classes } = useStyles()
const router = useRouter()
const [URL, setUrl] = useState("")
const [fileObjects, setFileObjects] = useState([])
@ -143,7 +143,7 @@ export default function ReverseSearch() {
</Backdrop>
<Box my={4}>
<div className={classes.url_div}>
<TextField onChange={(e) => setUrl(e.target.value)} value={URL}
<TextField onChange={(e:any) => setUrl(e.target.value)} value={URL}
className={classes.url_text_field} label="url"
placeholder="https://somesite.com/image.png" variant="outlined" size="small" />
<Button onClick={get_image_by_url} size="small" variant="outlined">Fetch</Button>

View File

@ -1,21 +1,21 @@
import { makeStyles } from '@material-ui/core/styles'
import { makeStyles } from 'tss-react/mui';
import AppBar from '../components/AppBar'
import db_ops from '../server/helpers/db_ops'
import Pagination from '@material-ui/lab/Pagination'
import Pagination from '@mui/material/Pagination'
import Link from '../components/Link'
import GalleryWrapper from '../components/GalleryWrapper'
import PaginationItem from "@material-ui/lab/PaginationItem/PaginationItem"
import PaginationItem from '@mui/material/PaginationItem'
import PhotoInterface from '../types/photo'
import build_ast from "../components/parse"
import image_ops from "../server/helpers/image_ops"
import { GetServerSideProps } from 'next'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
pagination: {
display: "flex",
justifyContent: 'center'
}
}))
}));
interface SearchProps {
err: boolean,
@ -28,7 +28,7 @@ interface SearchProps {
}
export default function Search(props: SearchProps) {
const classes = useStyles()
const { classes } = useStyles()
if (props.err) {
return (
<div>

View File

@ -1,6 +1,6 @@
import Container from '@material-ui/core/Container'
import Typography from '@material-ui/core/Typography'
import Box from '@material-ui/core/Box'
import Container from '@mui/material/Container'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import AppBar from '../components/AppBar'
import Link from './../components/Link'

View File

@ -1,14 +1,14 @@
import { useEffect, useState } from 'react'
import { KeyboardEvent, useEffect, useState } from 'react'
import axios from 'axios'
import { makeStyles } from "@material-ui/core/styles"
import TextField from '@material-ui/core/TextField'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import CardActions from '@material-ui/core/CardActions'
import Button from '@material-ui/core/Button'
import { makeStyles } from 'tss-react/mui';
import TextField from '@mui/material/TextField'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import CardActions from '@mui/material/CardActions'
import Button from '@mui/material/Button'
const useStyles = makeStyles(theme => ({
const useStyles = makeStyles()((theme:any) => ({
container: {
display: 'flex',
flexWrap: 'wrap',
@ -26,10 +26,10 @@ const useStyles = makeStyles(theme => ({
CardActions: {
'flex-wrap': 'wrap'
}
}))
}));
function SignUpForm() {
const classes = useStyles()
const { classes } = useStyles()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [password2, setPassword2] = useState('')
@ -112,8 +112,8 @@ function SignUpForm() {
label="Email"
placeholder="Email"
margin="normal"
onChange={(e) => setEmail(e.target.value)}
onKeyPress={(e) => handleKeyPress(e)}
onChange={(e:any) => setEmail(e.target.value)}
onKeyPress={(e: KeyboardEvent<HTMLDivElement>) => handleKeyPress(e)}
/>
<TextField
error={error}
@ -123,8 +123,8 @@ function SignUpForm() {
label="Password"
placeholder="Password"
margin="normal"
onChange={(e) => setPassword(e.target.value)}
onKeyPress={(e) => handleKeyPress(e)}
onChange={(e:any) => setPassword(e.target.value)}
onKeyPress={(e: KeyboardEvent<HTMLDivElement>) => handleKeyPress(e)}
/>
<TextField
error={error}
@ -135,8 +135,8 @@ function SignUpForm() {
placeholder="Repeat password"
margin="normal"
helperText={helperText}
onChange={(e) => setPassword2(e.target.value)}
onKeyPress={(e) => handleKeyPress(e)}
onChange={(e:any) => setPassword2(e.target.value)}
onKeyPress={(e:any) => handleKeyPress(e)}
/>
</div>
</CardContent>

View File

@ -1,15 +1,15 @@
import db_ops from '../server/helpers/db_ops'
import { GetStaticProps } from 'next'
import { makeStyles } from '@material-ui/core/styles'
import Chip from '@material-ui/core/Chip'
import { Typography } from '@material-ui/core'
import { makeStyles } from 'tss-react/mui';
import Chip from '@mui/material/Chip'
import { Typography } from '@mui/material'
import AppBar from '../components/AppBar'
const useStyles = makeStyles(() => ({
const useStyles = makeStyles()(() => ({
chip: {
margin: 5
}
}))
}));
interface Tags {
_id: string,
@ -17,7 +17,7 @@ interface Tags {
}
export default function Tags(props: { tags: Tags[] }) {
const classes = useStyles()
const { classes } = useStyles()
// const Seasons = ["winter", "spring", "summer", "autumn"]
const Orientation = ["horizontal", "vertical", "square"]
const Tags = []

View File

@ -2,7 +2,6 @@
import bcrypt from "bcrypt"
import crypto from "crypto"
import db_ops from "./db_ops"
const cryptoAsync = require('@ronomon/crypto-async');
const SALTROUNDS = 10
async function generate_activation_token(): Promise<string> {
@ -42,16 +41,16 @@ async function generate_password_recovery_token(): Promise<string> {
}
async function hash_password(password: string): Promise<string> {
const hashed_pass = bcrypt.hash(password, SALTROUNDS);
const hashed_pass = bcrypt.hash(password, SALTROUNDS)
return hashed_pass
}
async function check_password(password: string, hash: string): Promise<boolean> {
const result = bcrypt.compare(password, hash);
const result = bcrypt.compare(password, hash)
return result
}
async function image_buffer_sha256_hash(image_buffer:Buffer){
return cryptoAsync.hash("sha256",image_buffer).toString('hex')
function image_buffer_sha256_hash(image_buffer: Buffer) {
return crypto.createHash('sha256').update(image_buffer).digest('hex')
}
export default {generate_activation_token,generate_password_recovery_token,hash_password,check_password,image_buffer_sha256_hash}

View File

@ -9,7 +9,7 @@ import { unlink as fs_unlink_callback } from 'fs'
import { promisify } from 'util'
import { exec } from 'child_process'
const exec_async = promisify(exec);
import FileType from 'file-type'
import {fromBuffer} from 'file-type'
import path from "path"
const PATH_TO_IMAGES = path.join(config.root_path, 'public', 'images')
const PATH_TO_THUMBNAILS = path.join(config.root_path, 'public', 'thumbnails')
@ -186,7 +186,7 @@ async function parse_author(tags: string[]) {
}
async function import_image(image_buffer: Buffer, tags: string[] = [], source_url = "") {
const sha256_hash = await crypto_ops.image_buffer_sha256_hash(image_buffer)
const sha256_hash = crypto_ops.image_buffer_sha256_hash(image_buffer)
const found_img = await db_ops.image_ops.find_image_by_sha256(sha256_hash)
if (found_img) {
return `Image with the same sha256 is already in the db. Image id = ${found_img.id} `
@ -198,7 +198,7 @@ async function import_image(image_buffer: Buffer, tags: string[] = [], source_ur
}
}
try {
const mime_type = (await FileType.fromBuffer(image_buffer))?.mime
const mime_type = (await fromBuffer(image_buffer))?.mime
let file_ext = ""
switch (mime_type) {
case "image/png":
@ -271,7 +271,7 @@ async function import_image_without_check(image_buffer: Buffer, tags: string[] =
return `Image with the same sha256 is already in the db. Image id = ${found_img.id} `
}
try {
const mime_type = (await FileType.fromBuffer(image_buffer))?.mime
const mime_type = (await fromBuffer(image_buffer))?.mime
let file_ext = ""
switch (mime_type) {
case "image/png":
@ -295,7 +295,7 @@ async function import_image_without_check(image_buffer: Buffer, tags: string[] =
if (config.optimize_images) {
image_buffer = await optimize_image(file_ext, image_buffer)
}
tags.push(orientation)
const new_image_id = (await db_ops.image_ops.get_max_image_id()) + 1
@ -308,7 +308,7 @@ async function import_image_without_check(image_buffer: Buffer, tags: string[] =
}
await fs.writeFile(`${PATH_TO_THUMBNAILS}/${new_image_id}.jpg`, thumbnail_buffer, 'binary')
// console.log(`OK. New image_id: ${new_image_id}`)
return {image_id:new_image_id, new_file_name:`${new_image_id}.${file_ext}`}
return { image_id: new_image_id, new_file_name: `${new_image_id}.${file_ext}` }
} catch (error) {
console.error(error);
}

View File

@ -1,14 +1,21 @@
import fastify, { FastifyInstance } from 'fastify'
import formBodyPlugin from 'fastify-formbody'
import fastifyCookie from 'fastify-cookie'
import formBodyPlugin from '@fastify/formbody'
import fastifyCookie from '@fastify/cookie'
import config from "./../config/config"
import MongoStore from 'connect-mongo'
import fastifyMultipart from 'fastify-multipart'
import fastifyCors from 'fastify-cors'
import fastifySession from 'fastify-session';
import fastifyMultipart from '@fastify/multipart'
import fastifyCors from '@fastify/cors'
import fastifySession from '@fastify/session'
import fastifyRecaptcha from 'fastify-recaptcha'
import next from 'next'
declare module "fastify" {
interface Session {
user_id?: string
}
}
////////////////////////////////////////////////////////INIT DEFAULT FOLDERS
import fs from 'fs'
import path from "path"
@ -40,7 +47,7 @@ import google_oauth_callback from './routes/google_oauth_callback';
import signup from './routes/signup';
import login from './routes/login';
import change_password from './routes/change_password';
import forgot_password from './routes/forgot_password';
// import forgot_password from './routes/forgot_password';
import activate_account_email from './routes/activate_account_email';
import update_image_data from './routes/update_image_data'
import delete_image from './routes/delete_image'
@ -53,7 +60,13 @@ import get_image_info from './routes/public_api/get_image_info'
function main() {
const server = fastify({ trustProxy: true })
const server = fastify({ trustProxy: true})
server.register(fastifyCors, {
"origin": config.domain,
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE"
})
server.register(formBodyPlugin)
server.register(fastifyCookie);
server.register(fastifySession, {
@ -73,7 +86,6 @@ function main() {
server.register(fastifyMultipart, {
attachFieldsToBody: true,
sharedSchemaId: '#mySharedSchema',
limits: {
fieldNameSize: 100, // Max field name size in bytes
fieldSize: 1000, // Max field value size in bytes
@ -84,11 +96,6 @@ function main() {
}
})
server.register(fastifyCors, {
"origin": config.domain,
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
server.addHook<{ Body: { "g-recaptcha-response": any } }>('preValidation', async (request) => {
if (request.body && typeof request.body["g-recaptcha-response"]?.value === "string") {
@ -120,7 +127,7 @@ function main() {
server.post('/login', login)
server.post('/signup', signup)
server.post('/change_pw', change_password)
server.post('/forgot_pw', forgot_password)
// server.post('/forgot_pw', forgot_password)
server.get('/activate', activate_account_email)
///////////////////////////////////////////////////////////////
@ -137,7 +144,7 @@ function main() {
server.get('/logout', (req, res) => {
if (req.session) {
req.destroySession(function (err) {
req.session.destroy(function (err) {
if (err) {
console.log(err)
}
@ -146,13 +153,19 @@ function main() {
}
})
server.all('/*', (req, reply) => {
server.get('/*', async (req, reply) => {
req.raw.session = req.session
return handle(req.raw, reply.raw).then(() => {
reply.sent = true
})
await handle(req.raw, reply.raw)
reply.hijack()
})
server.listen(port, "127.0.0.1", function (err, address) {
server.post('/*', async (req, reply) => {
req.raw.session = req.session
await handle(req.raw, reply.raw)
reply.hijack()
})
server.listen({port:port, host:"127.0.0.1"}, function (err, address) {
if (err) {
console.error(err)
process.exit(1)

View File

@ -42,7 +42,6 @@ async function github_oauth_callback(req: FastifyRequest<{ Querystring: FromSche
} else {
req.session.user_id = user.id;
}
req.session.authed = true;
res.redirect(config.domain)
} catch (e) {
console.log(e)

View File

@ -38,7 +38,6 @@ async function google_oauth_callback(req: FastifyRequest<{ Querystring: FromSche
} else {
req.session.user_id = user.id;
}
req.session.authed = true;
res.redirect(config.domain)
} catch (e) {
console.log(e)

View File

@ -5,7 +5,15 @@ import { FromSchema } from "json-schema-to-ts";
const body_schema_import_image = {
type: 'object',
properties: {
image: { $ref: '#mySharedSchema' },
image: {
type: 'object',
properties: {
encoding: { type: 'string' },
filename: { type: 'string' },
limit: { type: 'boolean' },
mimetype: { type: 'string' }
}
},
source_url: {
type: "object",
properties: {
@ -40,7 +48,11 @@ async function import_image(req: FastifyRequest<{ Body: FromSchema<typeof body_s
}
let image_buffer: Buffer;
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
image_buffer = await (req as any).body.image.toBuffer()
if (!Buffer.isBuffer(image_buffer)){
throw "not a buffer"
}
} catch (err) {
return res.status(500).send()
}
@ -56,7 +68,7 @@ async function import_image(req: FastifyRequest<{ Body: FromSchema<typeof body_s
}
if (req.session?.user_id) {
const user = await db_ops.activated_user.find_user_by_id(req.session?.user_id)
const user = await db_ops.activated_user.find_user_by_id(req.session.user_id)
if (user && user.isAdmin) {
const results = await image_ops.import_image(image_buffer, tags, source_url)
if (results) {

View File

@ -27,7 +27,6 @@ async function login(req: FastifyRequest<{ Body: FromSchema<typeof body_schema_l
const match = await crypto_ops.check_password(password, user.password||"");
if (match) {
if (user.activated === true) {
req.session.authed = true;
req.session.user_id = user.id;
res.send({
message: "success"

View File

@ -4,9 +4,17 @@ import { FastifyRequest, FastifyReply } from "fastify"
const body_schema_reverse_search = {
type: 'object',
image: { $ref: '#mySharedSchema' },
properties: {
"g-recaptcha-response": { type: 'string' },
image: {
type: 'object',
properties: {
encoding: { type: 'string' },
filename: { type: 'string' },
limit: { type: 'boolean' },
mimetype: { type: 'string' }
}
}
},
required: ['image', 'g-recaptcha-response'],
} as const;
@ -14,7 +22,11 @@ const body_schema_reverse_search = {
async function reverse_search(req: FastifyRequest, res: FastifyReply) {
let image_buffer: Buffer;
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
image_buffer = await (req as any).body.image.toBuffer()
if (!Buffer.isBuffer(image_buffer)){
throw "not a buffer"
}
} catch (err) {
return res.send({ ids: '' })
}

View File

@ -3,7 +3,11 @@
"target": "esnext",
"module": "esnext",
"jsx": "preserve",
"lib": ["dom", "es2020","ESNext.String"],
"lib": [
"dom",
"esnext",
"ESNext.String"
],
"baseUrl": ".",
"moduleResolution": "node",
"strict": true,
@ -19,8 +23,20 @@
"preserveConstEnums": true,
"sourceMap": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
"resolveJsonModule": true,
"incremental": true
},
"exclude": ["dist", ".next", "out", "next.config.js","ambience"],
"include": ["next-env.d.ts","additional.d.ts", "**/*.ts", "**/*.tsx"]
"exclude": [
"dist",
".next",
"out",
"next.config.js",
"ambience"
],
"include": [
"next-env.d.ts",
"additional.d.ts",
"**/*.ts",
"**/*.tsx"
]
}

View File

@ -2,11 +2,11 @@
"extends": "./tsconfig.json",
"ts-node": { "files": true },
"compilerOptions": {
"module": "commonjs",
"module": "CommonJS",
"outDir": "dist",
"target": "esnext",
"isolatedModules": false,
"noEmit": false
},
"include": ["additional.d.ts", "server/**/*.ts"]
"include": ["additional.d.ts", "src/server/**/*.ts"]
}