upd
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
POSTGRES_URI=postgres://postgres:admin@192.168.1.250:5432/postgres
|
# POSTGRES_URI=postgres://postgres:admin@192.168.1.250:5432/postgres
|
||||||
DB_HOST=192.168.1.250:5432
|
POSTGRES_URI=postgres://postgres:v1sq3vD5faXL@194.26.138.94:5432/estate
|
||||||
DB_USER=postgres
|
PORT=3003
|
||||||
DB_PASSWORD=admin
|
|
||||||
DB_DATABASE=postgres
|
|
||||||
PORT=3001
|
|
||||||
JWT_ACCESS_SECRET=aboba
|
JWT_ACCESS_SECRET=aboba
|
||||||
JWT_REFRESH_SECRET=aboba
|
JWT_REFRESH_SECRET=aboba
|
||||||
JWT_ACCESS_EXP_TIME=30d
|
JWT_ACCESS_EXP_TIME=30d
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
POSTGRES_URI=postgres://postgres:v1sq3vD5faXL@194.26.138.94:5432/estate
|
||||||
|
PORT=3003
|
||||||
|
JWT_ACCESS_SECRET=aboba
|
||||||
|
JWT_REFRESH_SECRET=aboba
|
||||||
|
JWT_ACCESS_EXP_TIME=30d
|
||||||
|
JWT_REFRESH_EXP_TIME=30d
|
||||||
|
NODE_ENV=development
|
||||||
|
S3_REGION=ru-central1
|
||||||
|
S3_ENDPOINT=https://storage.yandexcloud.net
|
||||||
|
S3_ACCESS_KEY_ID=YCAJE7XefUV51hyi9GEdld8S3
|
||||||
|
S3_ACCESS_KEY=YCPY__ni1vs95aDjhutAlF8xX0kg3XP6Lbj9PifZ
|
||||||
|
S3_BUCKET=dult-faib-knac-fint
|
||||||
@@ -33,6 +33,9 @@ yarn-error.log*
|
|||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|
||||||
|
dist
|
||||||
|
.vscode
|
||||||
|
|
||||||
**/*.trace
|
**/*.trace
|
||||||
**/*.zip
|
**/*.zip
|
||||||
**/*.tar.gz
|
**/*.tar.gz
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { $, Glob } from 'bun';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
// Cross-platform directory removal
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
// await $`cmd /c "rmdir /s /q dist"`;
|
||||||
|
} else {
|
||||||
|
await $`rm -rf ./dist`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// await Bun.build({
|
||||||
|
// entrypoints: ["./src/index.ts"],
|
||||||
|
// env: "inline",
|
||||||
|
// target: "bun",
|
||||||
|
// outdir: `./dist`,
|
||||||
|
// minify: true,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Build all files in src
|
||||||
|
for (const entrypoint of new Glob('./src/**/*.ts').scanSync()) {
|
||||||
|
const parts = entrypoint.split(path.sep);
|
||||||
|
const entrypointPath = path.join(...parts.slice(2, -1));
|
||||||
|
|
||||||
|
await Bun.build({
|
||||||
|
entrypoints: [entrypoint],
|
||||||
|
target: 'bun',
|
||||||
|
outdir: path.join('dist', entrypointPath),
|
||||||
|
env: 'inline',
|
||||||
|
minify: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { Glob } from 'bun';
|
|
||||||
|
|
||||||
for (const entrypoint of new Glob('src/**/*.ts').scanSync())
|
|
||||||
await Bun.build({
|
|
||||||
entrypoints: [entrypoint],
|
|
||||||
target: 'bun',
|
|
||||||
outdir: './dist/' + entrypoint.split('\\').slice(1, -1).join('\\'),
|
|
||||||
});
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import { defineConfig } from 'drizzle-kit';
|
import { defineConfig } from 'drizzle-kit';
|
||||||
|
|
||||||
|
console.log('POSTGRES_URI!', process.env.POSTGRES_URI!);
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
dialect: 'postgresql',
|
dialect: 'postgresql',
|
||||||
schema: './src/db/schema/index.ts',
|
schema: './src/db/schema/index.ts',
|
||||||
|
|||||||
+2
-1
@@ -4,7 +4,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"dev": "bun --hot ./src",
|
"dev": "bun --hot ./src",
|
||||||
"push": "drizzle-kit push"
|
"push": "drizzle-kit push",
|
||||||
|
"build": "bun ./bun.build.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.709.0",
|
"@aws-sdk/client-s3": "^3.709.0",
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import Elysia, { t } from 'elysia';
|
import Elysia, { t } from 'elysia';
|
||||||
import { authMiddleware } from '../middlewares/auth';
|
import { authMiddleware } from '../middlewares/auth.ts';
|
||||||
import { getAll, getOne, create, remove, update } from '../services/articles';
|
import {
|
||||||
import { Block } from '../types/article';
|
getAll,
|
||||||
import { getCount } from '../services/articles/getCount';
|
getOne,
|
||||||
|
create,
|
||||||
|
remove,
|
||||||
|
update,
|
||||||
|
} from '../services/articles/index.ts';
|
||||||
|
import { getCount } from '../services/articles/getCount.ts';
|
||||||
import { createInsertSchema, createSelectSchema } from 'drizzle-typebox';
|
import { createInsertSchema, createSelectSchema } from 'drizzle-typebox';
|
||||||
import { articlesTable } from '../db/schema';
|
import { articlesTable } from '../db/schema/index.ts';
|
||||||
import { getDrafted } from '../services/articles/getDrafted';
|
import { getDrafted } from '../services/articles/getDrafted.ts';
|
||||||
|
|
||||||
const getArticle = createSelectSchema(articlesTable);
|
const getArticle = createSelectSchema(articlesTable);
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -3,7 +3,7 @@ import { authMiddleware } from '../middlewares/auth';
|
|||||||
import { login, logout, refresh } from '../services/auth';
|
import { login, logout, refresh } from '../services/auth';
|
||||||
|
|
||||||
export const authController = new Elysia({ prefix: '/auth' })
|
export const authController = new Elysia({ prefix: '/auth' })
|
||||||
.post('/login', async ({ body, cookie }) => await login(body, cookie), {
|
.post('/login', async ({ body }) => await login(body), {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
username: t.String(),
|
username: t.String(),
|
||||||
password: t.String({ minLength: 6 }),
|
password: t.String({ minLength: 6 }),
|
||||||
@@ -16,16 +16,15 @@ export const authController = new Elysia({ prefix: '/auth' })
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.use(authMiddleware)
|
.use(authMiddleware)
|
||||||
.get('/check', async (context) => {
|
.get('/check', async (context) => ({
|
||||||
return {
|
auth: !!('adminId' in context && context.adminId),
|
||||||
auth: 'adminId' in context && context.adminId,
|
}))
|
||||||
};
|
|
||||||
})
|
|
||||||
.get(
|
.get(
|
||||||
'/logout',
|
'/logout',
|
||||||
async ({ cookie, adminId }) => await logout(cookie, adminId),
|
async ({ adminId, headers }) =>
|
||||||
|
await logout(adminId, headers.authorization),
|
||||||
{
|
{
|
||||||
cookie: t.Cookie({ accessToken: t.String(), refreshToken: t.String() }),
|
// cookie: t.Cookie({ accessToken: t.String(), refreshToken: t.String() }),
|
||||||
adminId: t.String(),
|
adminId: t.String(),
|
||||||
response: {
|
response: {
|
||||||
200: t.Object({ success: t.Boolean() }),
|
200: t.Object({ success: t.Boolean() }),
|
||||||
@@ -33,6 +32,9 @@ export const authController = new Elysia({ prefix: '/auth' })
|
|||||||
401: t.ObjectString({}),
|
401: t.ObjectString({}),
|
||||||
500: t.ObjectString({}),
|
500: t.ObjectString({}),
|
||||||
},
|
},
|
||||||
|
headers: t.Object({
|
||||||
|
authorization: t.String(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.get(
|
.get(
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import {
|
|||||||
create,
|
create,
|
||||||
update,
|
update,
|
||||||
remove,
|
remove,
|
||||||
} from '../services/companies';
|
} from '../services/companies/index.ts';
|
||||||
import { authMiddleware } from '../middlewares/auth';
|
import { authMiddleware } from '../middlewares/auth.ts';
|
||||||
import { createInsertSchema, createSelectSchema } from 'drizzle-typebox';
|
import { createInsertSchema, createSelectSchema } from 'drizzle-typebox';
|
||||||
import { companiesTable } from '../db/schema';
|
import { companiesTable } from '../db/schema/index.ts';
|
||||||
import { getByCity } from '../services/companies/getByCity';
|
import { getByCity } from '../services/companies/getByCity.ts';
|
||||||
|
|
||||||
const createCompany = createInsertSchema(companiesTable);
|
const createCompany = createInsertSchema(companiesTable);
|
||||||
|
|
||||||
|
|||||||
+53
-35
@@ -1,51 +1,69 @@
|
|||||||
import Elysia, { t } from 'elysia';
|
import Elysia, { error, t } from 'elysia';
|
||||||
import nodemailer from 'nodemailer';
|
import nodemailer from 'nodemailer';
|
||||||
|
import { db } from '../db';
|
||||||
|
import { mailTable } from '../db/schema/mail';
|
||||||
|
import { createInsertSchema } from 'drizzle-typebox';
|
||||||
|
|
||||||
|
const createMailSchema = createInsertSchema(mailTable);
|
||||||
|
|
||||||
export const mailController = new Elysia({ prefix: '/mail' }).post(
|
export const mailController = new Elysia({ prefix: '/mail' }).post(
|
||||||
'/',
|
'/',
|
||||||
async ({
|
async ({
|
||||||
headers: { referer },
|
headers: { referer },
|
||||||
body: { email, fullname, phone, products },
|
body: { email, fullname, phone, products = [], request = '' },
|
||||||
}) => {
|
}) => {
|
||||||
const url = new URL(referer);
|
const url = new URL(referer);
|
||||||
|
|
||||||
let transporter = nodemailer.createTransport({
|
try {
|
||||||
host: 'mail.netangels.ru',
|
await db
|
||||||
port: 587,
|
.insert(mailTable)
|
||||||
secure: false, // true for 465, false for other ports
|
.values({ email, fullname, phone, products, request, from: url.host });
|
||||||
auth: {
|
|
||||||
user: 'test@graff.tech', // generated ethereal user
|
|
||||||
pass: 'ZmL0pKiDFWUyCDMq', // generated ethereal password
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let info = await transporter.sendMail({
|
let transporter = nodemailer.createTransport({
|
||||||
from: email, // sender address
|
host: 'mail.netangels.ru',
|
||||||
to: 'info@graff.tech', // list of receivers
|
port: 587,
|
||||||
subject: `Заявка с сайта ${url.host}`, // Subject line
|
secure: false, // true for 465, false for other ports
|
||||||
text: `
|
auth: {
|
||||||
Имя Фамилия: ${fullname}
|
user: 'test@graff.tech', // generated ethereal user
|
||||||
Email: ${email}
|
pass: 'ZmL0pKiDFWUyCDMq', // generated ethereal password
|
||||||
Телефон: ${phone}
|
},
|
||||||
Продукты: ${products.join(', ')}
|
});
|
||||||
`, // plain text body
|
|
||||||
html: `<div>
|
|
||||||
<p>Имя: ${fullname}</p>
|
|
||||||
<p>Email: ${email}</p>
|
|
||||||
<p>Телефон: ${phone}</p>
|
|
||||||
<p>Продукты: ${products.join(', ')}</p>
|
|
||||||
</div>`, // html body
|
|
||||||
});
|
|
||||||
|
|
||||||
return info;
|
let info = await transporter.sendMail({
|
||||||
|
from: email, // sender address
|
||||||
|
to: 'info@graff.tech', // list of receivers
|
||||||
|
subject: `Заявка с сайта ${url.host}`, // Subject line
|
||||||
|
text: `
|
||||||
|
Имя Фамилия: ${fullname}
|
||||||
|
Email: ${email}
|
||||||
|
${phone ? `Телефон: ${phone}` : ''}
|
||||||
|
${
|
||||||
|
products && products.length > 0
|
||||||
|
? 'Продукты: ' + products.join(', ')
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
`, // plain text body
|
||||||
|
html: `<div>
|
||||||
|
<p>Имя: ${fullname}</p>
|
||||||
|
<p>Email: ${email}</p>
|
||||||
|
${phone ? `<p>Телефон: ${phone}</p>` : ''}
|
||||||
|
${
|
||||||
|
products && products.length > 0
|
||||||
|
? '<p>Продукты: ' + products.join(', ') + '</p>'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
${request ? '<p>Текст заявки: ' + request + '</p>' : ''}
|
||||||
|
</div>`, // html body
|
||||||
|
});
|
||||||
|
|
||||||
|
return info;
|
||||||
|
} catch (err) {
|
||||||
|
console.log((err as Error).message);
|
||||||
|
return error(500, { error: 'Internal Server Error' });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: t.Object({ referer: t.String() }),
|
headers: t.Object({ referer: t.String() }),
|
||||||
body: t.Object({
|
body: createMailSchema,
|
||||||
fullname: t.String(),
|
|
||||||
email: t.String({ format: 'email' }),
|
|
||||||
phone: t.String(),
|
|
||||||
products: t.Array(t.String()),
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { createInsertSchema, createSelectSchema } from 'drizzle-typebox';
|
||||||
|
import Elysia, { t } from 'elysia';
|
||||||
|
import { mapTable } from '../db/schema';
|
||||||
|
import { getByCity } from '../services/map/getByCity';
|
||||||
|
import { authMiddleware } from '../middlewares/auth';
|
||||||
|
import { createMapPoint } from '../services/map/createMapPoint';
|
||||||
|
import { updateMapPoint } from '../services/map/updateMapPoint';
|
||||||
|
import { deleteMapPoint } from '../services/map/deleteMapPoint';
|
||||||
|
|
||||||
|
const getMapPointsSchema = createSelectSchema(mapTable);
|
||||||
|
|
||||||
|
const createMapPointSchema = createInsertSchema(mapTable);
|
||||||
|
|
||||||
|
export const mapController = new Elysia({
|
||||||
|
prefix: '/map',
|
||||||
|
})
|
||||||
|
.get('/', async ({ query: { city } }) => await getByCity(city), {
|
||||||
|
response: {
|
||||||
|
200: t.Array(getMapPointsSchema),
|
||||||
|
404: t.ObjectString({}),
|
||||||
|
500: t.ObjectString({}),
|
||||||
|
},
|
||||||
|
query: t.Object({
|
||||||
|
city: t.String(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.use(authMiddleware)
|
||||||
|
.post('/', async ({ body }) => await createMapPoint(body), {
|
||||||
|
response: { 200: getMapPointsSchema, 500: t.ObjectString({}) },
|
||||||
|
body: createMapPointSchema,
|
||||||
|
})
|
||||||
|
.put(
|
||||||
|
'/:id',
|
||||||
|
async ({ body, params: { id } }) => await updateMapPoint(id, body),
|
||||||
|
{
|
||||||
|
response: {
|
||||||
|
200: getMapPointsSchema,
|
||||||
|
404: t.ObjectString({}),
|
||||||
|
500: t.ObjectString({}),
|
||||||
|
},
|
||||||
|
params: t.Object({ id: t.String({ format: 'uuid' }) }),
|
||||||
|
body: createMapPointSchema,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.delete('/:id', async ({ params: { id } }) => await deleteMapPoint(id), {
|
||||||
|
response: {
|
||||||
|
200: getMapPointsSchema,
|
||||||
|
404: t.ObjectString({}),
|
||||||
|
500: t.ObjectString({}),
|
||||||
|
},
|
||||||
|
params: t.Object({ id: t.String({ format: 'uuid' }) }),
|
||||||
|
});
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import { getAll } from '../services/mapVideos/getAll';
|
|
||||||
import { createInsertSchema, createSelectSchema } from 'drizzle-typebox';
|
|
||||||
import Elysia, { t } from 'elysia';
|
|
||||||
import { mapVideosTable } from '../db/schema';
|
|
||||||
import { authMiddleware } from '../middlewares/auth';
|
|
||||||
import { createMapVideo } from '../services/mapVideos/create';
|
|
||||||
import { updateMapVideo } from '../services/mapVideos/update';
|
|
||||||
import { deleteMapVideo } from '../services/mapVideos/delete';
|
|
||||||
|
|
||||||
const getMapVideosSchema = createSelectSchema(mapVideosTable);
|
|
||||||
|
|
||||||
const createMapVideoSchema = createInsertSchema(mapVideosTable);
|
|
||||||
|
|
||||||
export const mapVideosController = new Elysia({ prefix: '/mapVideos' })
|
|
||||||
.get('/', async () => await getAll(), {
|
|
||||||
response: {
|
|
||||||
200: t.Array(getMapVideosSchema),
|
|
||||||
500: t.ObjectString({}),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.use(authMiddleware)
|
|
||||||
.post('/', async ({ body }) => await createMapVideo(body), {
|
|
||||||
body: createMapVideoSchema,
|
|
||||||
response: {
|
|
||||||
200: getMapVideosSchema,
|
|
||||||
500: t.ObjectString({}),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.put(
|
|
||||||
'/:id',
|
|
||||||
async ({ body, params: { id } }) => await updateMapVideo(id, body),
|
|
||||||
{
|
|
||||||
params: t.Object({ id: t.String({ format: 'uuid' }) }),
|
|
||||||
body: createMapVideoSchema,
|
|
||||||
response: {
|
|
||||||
200: getMapVideosSchema,
|
|
||||||
404: t.ObjectString({}),
|
|
||||||
500: t.ObjectString({}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.delete('/:id', async ({ params: { id } }) => await deleteMapVideo(id), {
|
|
||||||
params: t.Object({ id: t.String({ format: 'uuid' }) }),
|
|
||||||
response: {
|
|
||||||
200: getMapVideosSchema,
|
|
||||||
404: t.ObjectString({}),
|
|
||||||
500: t.ObjectString({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Elysia, { error, t } from 'elysia';
|
import Elysia, { error, t } from 'elysia';
|
||||||
import { authMiddleware } from '../middlewares/auth';
|
import { authMiddleware } from '../middlewares/auth.ts';
|
||||||
import { s3client } from '../config/s3client';
|
import { s3client } from '../config/s3client.ts';
|
||||||
import { PutObjectCommand } from '@aws-sdk/client-s3';
|
import { PutObjectCommand } from '@aws-sdk/client-s3';
|
||||||
import { randomUUIDv7 } from 'bun';
|
import { randomUUIDv7 } from 'bun';
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ export * from './projects.ts';
|
|||||||
export * from './tokens.ts';
|
export * from './tokens.ts';
|
||||||
export * from './companies.ts';
|
export * from './companies.ts';
|
||||||
export * from './stories.ts';
|
export * from './stories.ts';
|
||||||
export * from './mapVideos.ts';
|
export * from './map.ts';
|
||||||
|
export * from './mail.ts';
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { text } from 'drizzle-orm/pg-core';
|
||||||
|
import { pgTable, uuid } from 'drizzle-orm/pg-core';
|
||||||
|
|
||||||
|
export const mailTable = pgTable('mail', {
|
||||||
|
id: uuid('id').defaultRandom().primaryKey(),
|
||||||
|
fullname: text('fullname').notNull(),
|
||||||
|
email: text('email').notNull(),
|
||||||
|
phone: text('phone'),
|
||||||
|
request: text('request'),
|
||||||
|
products: text('products', {
|
||||||
|
enum: [
|
||||||
|
'Интерактивная презентация',
|
||||||
|
'Удаленная демонстрация',
|
||||||
|
'Архитектурная визуализация',
|
||||||
|
'Создание сайтов',
|
||||||
|
'Web-тур по 360 сферам',
|
||||||
|
],
|
||||||
|
}).array(),
|
||||||
|
from: text('from').notNull(),
|
||||||
|
});
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { pgTable, text, uuid, varchar } from 'drizzle-orm/pg-core';
|
||||||
|
import { companiesTable } from './companies';
|
||||||
|
import { projectsTable } from './projects';
|
||||||
|
import { relations } from 'drizzle-orm';
|
||||||
|
|
||||||
|
export const mapTable = pgTable('map', {
|
||||||
|
id: uuid('id').defaultRandom().primaryKey(),
|
||||||
|
city: varchar('city', { length: 50 }).notNull(),
|
||||||
|
src: text('src'),
|
||||||
|
companyId: uuid('company_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => companiesTable.id),
|
||||||
|
projectId: uuid('project_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => projectsTable.id),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const mapRelations = relations(mapTable, ({ one }) => ({
|
||||||
|
company: one(companiesTable, {
|
||||||
|
fields: [mapTable.companyId],
|
||||||
|
references: [companiesTable.id],
|
||||||
|
}),
|
||||||
|
project: one(projectsTable, {
|
||||||
|
fields: [mapTable.projectId],
|
||||||
|
references: [projectsTable.id],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { pgTable, text, uuid, varchar } from 'drizzle-orm/pg-core';
|
|
||||||
import { companiesTable } from './companies';
|
|
||||||
import { relations } from 'drizzle-orm';
|
|
||||||
|
|
||||||
export const mapVideosTable = pgTable('map_videos', {
|
|
||||||
id: uuid('id').defaultRandom().primaryKey(),
|
|
||||||
city: varchar('city', { length: 50 }).notNull(),
|
|
||||||
video: text('video').notNull(),
|
|
||||||
companyId: uuid('company_id').references(() => companiesTable.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const videosRelations = relations(mapVideosTable, ({ one }) => ({
|
|
||||||
company: one(companiesTable, {
|
|
||||||
fields: [mapVideosTable.companyId],
|
|
||||||
references: [companiesTable.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
+2
-5
@@ -10,10 +10,7 @@ import { companiesController } from './controllers/companies';
|
|||||||
import { mailController } from './controllers/mail';
|
import { mailController } from './controllers/mail';
|
||||||
import { getReionNameController } from './controllers/getRegionName';
|
import { getReionNameController } from './controllers/getRegionName';
|
||||||
import { storiesController } from './controllers/stories';
|
import { storiesController } from './controllers/stories';
|
||||||
import { mapVideosController } from './controllers/mapVideos';
|
import { mapController } from './controllers/map';
|
||||||
import { db } from './db';
|
|
||||||
import { projectsTable } from './db/schema';
|
|
||||||
import { eq, ne } from 'drizzle-orm';
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const app = new Elysia();
|
const app = new Elysia();
|
||||||
@@ -30,7 +27,7 @@ try {
|
|||||||
.use(uploadController)
|
.use(uploadController)
|
||||||
.use(companiesController)
|
.use(companiesController)
|
||||||
.use(storiesController)
|
.use(storiesController)
|
||||||
.use(mapVideosController)
|
.use(mapController)
|
||||||
.use(mailController)
|
.use(mailController)
|
||||||
.use(getReionNameController)
|
.use(getReionNameController)
|
||||||
.listen(process.env.PORT);
|
.listen(process.env.PORT);
|
||||||
|
|||||||
+5
-16
@@ -5,16 +5,10 @@ import { verifyToken } from '../utils/verifyToken';
|
|||||||
import { adminsTable } from '../db/schema';
|
import { adminsTable } from '../db/schema';
|
||||||
|
|
||||||
export const authMiddleware = new Elysia()
|
export const authMiddleware = new Elysia()
|
||||||
.derive({ as: 'scoped' }, async ({ headers, cookie, path }: Context) => {
|
.derive({ as: 'scoped' }, async ({ headers, path }: Context) => {
|
||||||
const token =
|
const token = headers['authorization'];
|
||||||
(path === '/auth/refresh'
|
|
||||||
? cookie.refreshToken.value
|
|
||||||
: cookie.accessToken.value) || headers.authorization;
|
|
||||||
|
|
||||||
const payload = await verifyToken(
|
const payload = await verifyToken('access', token);
|
||||||
path === '/auth/refresh' ? 'refresh' : 'access',
|
|
||||||
token
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!token || !payload)
|
if (!token || !payload)
|
||||||
return path === '/auth/check'
|
return path === '/auth/check'
|
||||||
@@ -32,14 +26,9 @@ export const authMiddleware = new Elysia()
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!user ||
|
!user ||
|
||||||
user.tokens.every(
|
user.tokens.every(({ accessToken }) => token !== accessToken)
|
||||||
({ accessToken, refreshToken }) =>
|
)
|
||||||
token !== (path === '/auth/refresh' ? refreshToken : accessToken)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
console.log("attempt to login with someone else's token");
|
|
||||||
return error(401, { error: 'Not authorized' });
|
return error(401, { error: 'Not authorized' });
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log((err as Error).message);
|
console.log((err as Error).message);
|
||||||
return error(500, {
|
return error(500, {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { error } from 'elysia';
|
import { error } from 'elysia';
|
||||||
import { db } from '../../db';
|
import { db } from '../../db/index.ts';
|
||||||
import { articlesTable } from '../../db/schema';
|
import { articlesTable } from '../../db/schema/index.ts';
|
||||||
import { slugify } from 'transliteration';
|
import { slugify } from 'transliteration';
|
||||||
|
|
||||||
export async function create(input: typeof articlesTable.$inferInsert) {
|
export async function create(input: typeof articlesTable.$inferInsert) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { and, arrayContains, not } from 'drizzle-orm';
|
import { and, arrayContains, arrayOverlaps, desc, not } from 'drizzle-orm';
|
||||||
import { db } from '../../db';
|
import { db } from '../../db';
|
||||||
import { articlesTable } from '../../db/schema';
|
import { articlesTable } from '../../db/schema';
|
||||||
import { error } from 'elysia';
|
import { error } from 'elysia';
|
||||||
@@ -10,8 +10,9 @@ export async function getAll(tags: string[] = [], offset = 0, limit = 10) {
|
|||||||
limit,
|
limit,
|
||||||
where: and(
|
where: and(
|
||||||
not(articlesTable.drafted),
|
not(articlesTable.drafted),
|
||||||
tags.length > 0 ? arrayContains(articlesTable.tags, tags) : undefined
|
tags.length > 0 ? arrayOverlaps(articlesTable.tags, tags) : undefined
|
||||||
),
|
),
|
||||||
|
orderBy: desc(articlesTable.createdAt),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log((err as Error).message);
|
console.log((err as Error).message);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export * from './getAll';
|
export * from './getAll.ts';
|
||||||
export * from './getOne';
|
export * from './getOne.ts';
|
||||||
export * from './create';
|
export * from './create.ts';
|
||||||
export * from './remove';
|
export * from './remove.ts';
|
||||||
export * from './update';
|
export * from './update.ts';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { db } from '../../db';
|
import { db } from '../../db/index.ts';
|
||||||
import { articlesTable } from '../../db/schema';
|
import { articlesTable } from '../../db/schema/index.ts';
|
||||||
import { error } from 'elysia';
|
import { error } from 'elysia';
|
||||||
import { slugify } from 'transliteration';
|
import { slugify } from 'transliteration';
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ import { generateToken } from '../../utils/generateToken';
|
|||||||
import { db } from '../../db';
|
import { db } from '../../db';
|
||||||
import { tokensTable } from '../../db/schema';
|
import { tokensTable } from '../../db/schema';
|
||||||
|
|
||||||
export async function generateTokens(
|
export async function generateTokens(adminId: string): Promise<
|
||||||
adminId: string,
|
| {
|
||||||
cookie: Record<string, Cookie<string | undefined>>
|
accessToken: string;
|
||||||
) {
|
refreshToken: string;
|
||||||
|
}
|
||||||
|
| ReturnType<typeof error>
|
||||||
|
> {
|
||||||
const accessToken = await generateToken(adminId, 'access');
|
const accessToken = await generateToken(adminId, 'access');
|
||||||
|
|
||||||
const refreshToken = await generateToken(adminId, 'refresh');
|
const refreshToken = await generateToken(adminId, 'refresh');
|
||||||
@@ -23,20 +26,6 @@ export async function generateTokens(
|
|||||||
return error(500, { error: 'Something went wrong (Postgres insert)' });
|
return error(500, { error: 'Something went wrong (Postgres insert)' });
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie.accessToken.set({
|
|
||||||
value: accessToken,
|
|
||||||
httpOnly: true,
|
|
||||||
// secure: true,
|
|
||||||
maxAge: 3600 * 24 * 30,
|
|
||||||
});
|
|
||||||
|
|
||||||
cookie.refreshToken.set({
|
|
||||||
value: refreshToken,
|
|
||||||
httpOnly: true,
|
|
||||||
// secure: true,
|
|
||||||
maxAge: 3600 * 24 * 30,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accessToken,
|
accessToken,
|
||||||
refreshToken,
|
refreshToken,
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { getUserByUsername } from '../admins/getByUsername';
|
|||||||
import { generateTokens } from './generateTokens';
|
import { generateTokens } from './generateTokens';
|
||||||
|
|
||||||
export async function login(
|
export async function login(
|
||||||
body: { username: string; password: string },
|
body: { username: string; password: string }
|
||||||
cookie: Record<string, Cookie<string | undefined>>
|
// cookie: Record<string, Cookie<string | undefined>>
|
||||||
) {
|
) {
|
||||||
const { username, password } = body;
|
const { username, password } = body;
|
||||||
|
|
||||||
@@ -14,12 +14,28 @@ export async function login(
|
|||||||
if (user instanceof ElysiaCustomStatusResponse)
|
if (user instanceof ElysiaCustomStatusResponse)
|
||||||
return error(user.code, user.response.error);
|
return error(user.code, user.response.error);
|
||||||
|
|
||||||
const passwordMatches = user
|
if (!user || !Bun.password.verifySync(password, user.hashedPassword))
|
||||||
? Bun.password.verifySync(password, user.hashedPassword)
|
|
||||||
: false;
|
|
||||||
|
|
||||||
if (!user || !passwordMatches)
|
|
||||||
return error(401, { error: 'Wrong credentials' });
|
return error(401, { error: 'Wrong credentials' });
|
||||||
|
|
||||||
return await generateTokens(user.id, cookie);
|
const res = await generateTokens(user.id);
|
||||||
|
|
||||||
|
// if ('accessToken' in res && 'refreshToken' in res) {
|
||||||
|
// cookie.accessToken.set({
|
||||||
|
// value: res.accessToken,
|
||||||
|
// httpOnly: true,
|
||||||
|
// sameSite: 'lax',
|
||||||
|
// // secure: true,
|
||||||
|
// maxAge: 3600 * 24 * 30,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// cookie.refreshToken.set({
|
||||||
|
// value: res.refreshToken,
|
||||||
|
// httpOnly: true,
|
||||||
|
// sameSite: 'lax',
|
||||||
|
// // secure: true,
|
||||||
|
// maxAge: 3600 * 24 * 30,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import { tokensTable } from '../../db/schema';
|
|||||||
import { and, eq } from 'drizzle-orm';
|
import { and, eq } from 'drizzle-orm';
|
||||||
|
|
||||||
export async function logout(
|
export async function logout(
|
||||||
cookie: Record<string, Cookie<string | undefined>> & {
|
adminId: string,
|
||||||
accessToken: Cookie<string>;
|
authorizatoin: string
|
||||||
refreshToken: Cookie<string>;
|
// cookie: Record<string, Cookie<string | undefined>> & {
|
||||||
},
|
// accessToken: Cookie<string>;
|
||||||
adminId: string
|
// refreshToken: Cookie<string>;
|
||||||
|
// }
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const result = await db
|
const result = await db
|
||||||
@@ -16,7 +17,7 @@ export async function logout(
|
|||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(tokensTable.adminId, adminId),
|
eq(tokensTable.adminId, adminId),
|
||||||
eq(tokensTable.accessToken, cookie.accessToken.value!)
|
eq(tokensTable.accessToken, authorizatoin)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.returning();
|
.returning();
|
||||||
@@ -29,8 +30,8 @@ export async function logout(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie.accessToken.remove();
|
// cookie.accessToken.remove();
|
||||||
cookie.refreshToken.remove();
|
// cookie.refreshToken.remove();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export * from './getMany';
|
export * from './getMany.ts';
|
||||||
export * from './getCount';
|
export * from './getCount.ts';
|
||||||
export * from './create';
|
export * from './create.ts';
|
||||||
export * from './update';
|
export * from './update.ts';
|
||||||
export * from './remove';
|
export * from './remove.ts';
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { error } from 'elysia';
|
||||||
|
import { db } from '../../db';
|
||||||
|
import { mapTable } from '../../db/schema';
|
||||||
|
|
||||||
|
export async function createMapPoint(payload: typeof mapTable.$inferInsert) {
|
||||||
|
try {
|
||||||
|
const res = await db.insert(mapTable).values(payload).returning();
|
||||||
|
if (res.length) return res[0];
|
||||||
|
return error(500, 'Internal Server Error');
|
||||||
|
} catch (err) {
|
||||||
|
console.log((err as Error).message);
|
||||||
|
return error(500, 'Internal Server Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { eq } from 'drizzle-orm';
|
|
||||||
import { db } from '../../db';
|
|
||||||
import { mapVideosTable } from '../../db/schema';
|
|
||||||
import { error } from 'elysia';
|
import { error } from 'elysia';
|
||||||
|
import { db } from '../../db';
|
||||||
|
import { mapTable } from '../../db/schema';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
|
||||||
export async function deleteMapVideo(id: string) {
|
export async function deleteMapPoint(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await db
|
const res = await db
|
||||||
.delete(mapVideosTable)
|
.delete(mapTable)
|
||||||
.where(eq(mapVideosTable.id, id))
|
.where(eq(mapTable.id, id))
|
||||||
.returning();
|
.returning();
|
||||||
if (!res.length) return error(404, 'Not Found');
|
if (!res.length) return error(404, 'Map not found');
|
||||||
return res[0];
|
return res[0];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log((err as Error).message);
|
console.log((err as Error).message);
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
import { db } from '../../db';
|
||||||
|
import { mapTable } from '../../db/schema';
|
||||||
|
import { error } from 'elysia';
|
||||||
|
|
||||||
|
export async function getByCity(city: string) {
|
||||||
|
try {
|
||||||
|
const res = await db.query.mapTable.findMany({
|
||||||
|
where: eq(mapTable.city, city),
|
||||||
|
with: {
|
||||||
|
company: true,
|
||||||
|
project: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!res) return error(404, { error: 'Map point not found' });
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
console.log((err as Error).message);
|
||||||
|
return error(500, 'Internal Server Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { error } from 'elysia';
|
||||||
|
import { mapTable } from '../../db/schema';
|
||||||
|
import { db } from '../../db';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
|
||||||
|
export async function updateMapPoint(
|
||||||
|
id: string,
|
||||||
|
payload: Partial<typeof mapTable.$inferInsert>
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const res = await db
|
||||||
|
.update(mapTable)
|
||||||
|
.set(payload)
|
||||||
|
.where(eq(mapTable.id, id))
|
||||||
|
.returning();
|
||||||
|
if (!res.length) return error(404, 'Map not found');
|
||||||
|
return res[0];
|
||||||
|
} catch (err) {
|
||||||
|
console.log((err as Error).message);
|
||||||
|
return error(500, 'Internal Server Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { error } from 'elysia';
|
|
||||||
import { db } from '../../db';
|
|
||||||
import { mapVideosTable } from '../../db/schema';
|
|
||||||
|
|
||||||
export async function createMapVideo(
|
|
||||||
paylaod: typeof mapVideosTable.$inferInsert
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const res = await db.insert(mapVideosTable).values(paylaod).returning();
|
|
||||||
if (!res) return error(500, 'Internal Server Error');
|
|
||||||
return res[0];
|
|
||||||
} catch (err) {
|
|
||||||
console.log((err as Error).message);
|
|
||||||
return error(500, 'Internal Server Error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { error } from 'elysia';
|
|
||||||
import { db } from '../../db';
|
|
||||||
|
|
||||||
export async function getAll() {
|
|
||||||
try {
|
|
||||||
return await db.query.mapVideosTable.findMany({ with: { company: true } });
|
|
||||||
} catch (err) {
|
|
||||||
console.log((err as Error).message);
|
|
||||||
return error(500, { error: 'Internal Server Error' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { error } from 'elysia';
|
|
||||||
import { db } from '../../db';
|
|
||||||
import { mapVideosTable } from '../../db/schema';
|
|
||||||
import { eq } from 'drizzle-orm';
|
|
||||||
|
|
||||||
export async function updateMapVideo(
|
|
||||||
id: string,
|
|
||||||
payload: typeof mapVideosTable.$inferInsert
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const candidate = await db.query.mapVideosTable.findFirst();
|
|
||||||
if (!candidate) return error(404, 'Not Found');
|
|
||||||
const res = await db
|
|
||||||
.update(mapVideosTable)
|
|
||||||
.set(payload)
|
|
||||||
.where(eq(mapVideosTable.id, id))
|
|
||||||
.returning();
|
|
||||||
if (!res) return error(500, 'Internal Server Error');
|
|
||||||
return res[0];
|
|
||||||
} catch (err) {
|
|
||||||
console.log((err as Error).message);
|
|
||||||
return error(500, 'Internal Server Error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { and, arrayContains, desc, eq } from 'drizzle-orm';
|
import { and, arrayContains, arrayOverlaps, desc, eq } from 'drizzle-orm';
|
||||||
import { db } from '../../db';
|
import { db } from '../../db';
|
||||||
import { projectsTable } from '../../db/schema';
|
import { projectsTable } from '../../db/schema';
|
||||||
import { error } from 'elysia';
|
import { error } from 'elysia';
|
||||||
@@ -12,7 +12,7 @@ export async function getMany(
|
|||||||
try {
|
try {
|
||||||
return await db.query.projectsTable.findMany({
|
return await db.query.projectsTable.findMany({
|
||||||
where: and(
|
where: and(
|
||||||
tags.length > 0 ? arrayContains(projectsTable.tags, tags) : undefined,
|
tags.length > 0 ? arrayOverlaps(projectsTable.tags, tags) : undefined,
|
||||||
city ? eq(projectsTable.city, city) : undefined,
|
city ? eq(projectsTable.city, city) : undefined,
|
||||||
companyId ? eq(projectsTable.companyId, companyId) : undefined
|
companyId ? eq(projectsTable.companyId, companyId) : undefined
|
||||||
),
|
),
|
||||||
|
|||||||
+1
-2
@@ -107,8 +107,7 @@
|
|||||||
"./drizzle.config.ts",
|
"./drizzle.config.ts",
|
||||||
"./env.d.ts",
|
"./env.d.ts",
|
||||||
"./src/**/*.ts",
|
"./src/**/*.ts",
|
||||||
"./bun.config.ts"
|
"./bun.build.ts"
|
||||||
// "src/controllers/getRegionName.ts"
|
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user