From f8608fc8aa0549c99bfecc921dcd3643df48316c Mon Sep 17 00:00:00 2001 From: fourhtyoz Date: Sun, 7 Apr 2024 16:24:52 +0300 Subject: [PATCH 1/7] added links --- frontend/src/api/httpServer.js | 2 +- frontend/src/components/Header.tsx | 3 ++- frontend/src/components/Navbar.module.css | 13 +++++++++- frontend/src/components/Navbar.tsx | 6 +++++ frontend/src/pages/About.tsx | 30 ++++++++++++++++++++--- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/frontend/src/api/httpServer.js b/frontend/src/api/httpServer.js index 659b115..3e51706 100644 --- a/frontend/src/api/httpServer.js +++ b/frontend/src/api/httpServer.js @@ -1,7 +1,7 @@ import axios from "axios"; export const httpServer = axios.create({ - baseURL: 'https://backend-ejlb.onrender.com' + baseURL: 'http://localhost:8000' }); httpServer.interceptors.request.use( diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index 5c116f6..297585e 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -4,6 +4,7 @@ import generateRandomColor from "../utils/randomColorGenerator" import { useSelector } from "react-redux" import { selectMode } from "../stores/selectors/selectors" import cn from 'classnames'; +import { Link } from "react-router-dom" export default function Header() { const accentColor = '#' + generateRandomColor() @@ -11,7 +12,7 @@ export default function Header() { const darkMode = mode === 'dark' return (
-

Cringomba!

+

Cringomba!

Your source of hilarity
) diff --git a/frontend/src/components/Navbar.module.css b/frontend/src/components/Navbar.module.css index 8916b9b..1321408 100644 --- a/frontend/src/components/Navbar.module.css +++ b/frontend/src/components/Navbar.module.css @@ -8,6 +8,11 @@ color: #ffffff; } +.currentPath { + background-color: #FAA50A !important; + color: #000 !important; +} + .link { color: rgba(0, 0, 128, .5); cursor: pointer; @@ -27,7 +32,8 @@ } -.wrapper button { +.wrapper button, +.wrapper a { background-color: transparent; border: none; padding: 5px 25px; @@ -36,14 +42,19 @@ border: 1px solid #383838; color: #ffffff; transition: .3s linear; + text-decoration: none; } .wrapper button:hover { cursor: pointer; border: 1px solid rgb(220, 220, 220); +} +.wrapper a:hover { + border: 1px solid rgb(220, 220, 220); } + .box { position: absolute; top: 50%; diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index 501c635..462c021 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -8,6 +8,7 @@ import store from "../stores/store"; import { useSelector } from "react-redux"; import { selectIsLoggedIn, selectMode, selectUser } from "../stores/selectors/selectors"; import cn from 'classnames'; +import { Link, useLocation } from "react-router-dom"; export default function Navbar() { const [registrationOpen, setRegistrationOpen] = useState(false) @@ -74,12 +75,17 @@ export default function Navbar() { const isLoggedIn = useSelector(selectIsLoggedIn) const mode = useSelector(selectMode) const darkMode = mode === 'dark' + + const currentLocation = useLocation() + return (
{isLoggedIn ? `Добро пожаловать, ${user.firstName} ${user.lastName}` : Привет, гость} {!isLoggedIn && } {isLoggedIn && } + О нас + Главная страница setLoggingInOpen(false)}>
diff --git a/frontend/src/pages/About.tsx b/frontend/src/pages/About.tsx index 94d23dd..9a880ef 100644 --- a/frontend/src/pages/About.tsx +++ b/frontend/src/pages/About.tsx @@ -1,7 +1,31 @@ export default function About() { return( -

- about -

+
+

Кринж (англ. krampus) - это мифическое существо, которое происходит из австрийской и баварской мифологии. Этот зловещий и ужасающий монстр схож с диким козлом, обладает длинными рогами, когтями и длинной языком. Кринж является традиционным символом зимнего времени и связан с праздником Святой Николая, который отмечается 5-6 декабря. Согласно народным верованиям, кринж наказывает непослушных и хулиганских детей, которые не смогли убедить Святого Николая в своей хорошей поведении.

+
+

Анекдоты - это короткие, обычно юмористические рассказы или истории, которые рассказываются в устной или письменной форме. Они могут быть связаны с различными темами или событиями и часто используются для развлечения, осмотра общественных стереотипов и передачи социальных сообщений.

+
+ Тесно связь между кринжем и анекдотами можно найти в том, что кринж стал популярным персонажем в современной культуре, и его образ начал использоваться в различных шутках и историях. Это связано с тем, что кринж представляет собой уникальный и захватывающий персонаж, который может быть легко адаптирован в различных контекстах. +
+ Ниже представлены несколько примеров анекдотов, связанных с кринжем: +
    +
  1. 1. Святой Николай спрашивал кринжа: "Помнишь, что делал мальчик, который всегда играл в футбол в зимнюю ночь?" Кринж отвечает: "Нет, но я знаю, что сегодня вечер - вторник!"
  2. + +
  3. 2. В одном городе решили устроить праздник в честь кринжа. Организаторы спрашивали у местных жителей, что им бы хотелось видеть на этом празднике. Одна женщина ответила: "Хотела бы видеть кринжа, который бы был менее строгим к детьми!"
  4. + +
  5. 3. Святой Николай спрашивал кринжа: "Как ты наказываешь детей, которые не могут решить, кого из нас они предпочитают?" Кринж отвечает: "Я просто заставляю их ежедневно спрашивать обоих!"
  6. + +
  7. 4. В одном городе решили заменить кринжа на Санта-Клауса, чтобы дети не боялись. Однако когда Санта-Клаус начал наказывать плохих детей, все решили, что это был кринж в другом обличье. В итоге, они решили вернуть кринжа, потому что люди поняли, что он играет важную роль в обучении детей отличать правое от неправого и наказывать их за плохие поступки.
  8. + +
  9. 5. Святой Николай спрашивал кринжа: "Как ты обучаешь детей, чтобы они стали лучше?" Кринж отвечает: "Я просто показываю им свои длинные рога и говорю: 'Если вы хотите избежать меня, нужно стать более умными и добрыми'."
  10. + +
  11. 6. В одном городе решили устроить конкурс на лучший анекдот о кринже. Однако, когда все собрались, кринж сам вышел на сцену и сказал: "Друзья, я знаю, что у вас есть много анекдотов о мне, но сегодня я хочу услышать анекдоты о вас самих. Покажите, что вы смогли узнать от меня!"
  12. + +
  13. 7. Святой Николай спрашивал кринжа: "Как ты обрабатываешь ситуацию, когда дети утверждают, что они хорошие, хотя их поступки говорят о противоположном?" Кринж отвечает: "Я просто показываю им свои когти и говорю: 'Эти когти - это результат моей работы с плохими детьми. Не хотите стать одной из них?'"
  14. + +
  15. 8. В одном городе решили организовать фестиваль, на котором кринж будет главным героем. Однако кринж не смог прийти, и люди решили заменить его. Однако, когда кринж узнал об этом, он сказал: "Я понимаю, что люди хотят увидеть что-то новое, но помните, что я - часть вашей культуры и истории. Не забывайте о моей важной миссии!"
  16. +
+

Таким образом, анекдоты о кринже стали популярным способом рассказать юмористические истории, которые одновременно передают важные уроки и подчеркивают культурное значение этого удивительного персонажа.

+
) } \ No newline at end of file From 3f9a77fc81f7c974d27885795ea6f7bcb09475de Mon Sep 17 00:00:00 2001 From: fourhtyoz Date: Sun, 7 Apr 2024 16:26:31 +0300 Subject: [PATCH 2/7] process.env.HOST --- frontend/src/api/httpServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/api/httpServer.js b/frontend/src/api/httpServer.js index 3e51706..2cd6516 100644 --- a/frontend/src/api/httpServer.js +++ b/frontend/src/api/httpServer.js @@ -1,7 +1,7 @@ import axios from "axios"; export const httpServer = axios.create({ - baseURL: 'http://localhost:8000' + baseURL: process.env.HOST || 'http://localhost:8000' }); httpServer.interceptors.request.use( From 8db3646242ad5bdc65a724dbce41d37ee027decb Mon Sep 17 00:00:00 2001 From: fourhtyoz Date: Mon, 8 Apr 2024 22:37:43 +0300 Subject: [PATCH 3/7] about styles --- frontend/src/pages/About.module.css | 25 ++++++++++++++++++++++ frontend/src/pages/About.tsx | 32 ++++++++++++++--------------- 2 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 frontend/src/pages/About.module.css diff --git a/frontend/src/pages/About.module.css b/frontend/src/pages/About.module.css new file mode 100644 index 0000000..ce2cf7a --- /dev/null +++ b/frontend/src/pages/About.module.css @@ -0,0 +1,25 @@ +.wrapper { + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + min-width: 300px; + max-width: 800px; + margin: 0 auto; + padding-block: 100px; +} + +.title { + font-size: 50px; + font-weight: bold; +} + +.text { + font-size: 30px; + text-align: justify; + text-justify: inter-word; +} + +.text ol li { + margin: 20px 0; +} \ No newline at end of file diff --git a/frontend/src/pages/About.tsx b/frontend/src/pages/About.tsx index 9a880ef..62c0ccb 100644 --- a/frontend/src/pages/About.tsx +++ b/frontend/src/pages/About.tsx @@ -1,31 +1,31 @@ +import s from './About.module.css'; + export default function About() { return( -
+
+ Что такое Cringomba!? +

Кринж (англ. krampus) - это мифическое существо, которое происходит из австрийской и баварской мифологии. Этот зловещий и ужасающий монстр схож с диким козлом, обладает длинными рогами, когтями и длинной языком. Кринж является традиционным символом зимнего времени и связан с праздником Святой Николая, который отмечается 5-6 декабря. Согласно народным верованиям, кринж наказывает непослушных и хулиганских детей, которые не смогли убедить Святого Николая в своей хорошей поведении.


Анекдоты - это короткие, обычно юмористические рассказы или истории, которые рассказываются в устной или письменной форме. Они могут быть связаны с различными темами или событиями и часто используются для развлечения, осмотра общественных стереотипов и передачи социальных сообщений.


Тесно связь между кринжем и анекдотами можно найти в том, что кринж стал популярным персонажем в современной культуре, и его образ начал использоваться в различных шутках и историях. Это связано с тем, что кринж представляет собой уникальный и захватывающий персонаж, который может быть легко адаптирован в различных контекстах.
+
Ниже представлены несколько примеров анекдотов, связанных с кринжем:
    -
  1. 1. Святой Николай спрашивал кринжа: "Помнишь, что делал мальчик, который всегда играл в футбол в зимнюю ночь?" Кринж отвечает: "Нет, но я знаю, что сегодня вечер - вторник!"
  2. - -
  3. 2. В одном городе решили устроить праздник в честь кринжа. Организаторы спрашивали у местных жителей, что им бы хотелось видеть на этом празднике. Одна женщина ответила: "Хотела бы видеть кринжа, который бы был менее строгим к детьми!"
  4. - -
  5. 3. Святой Николай спрашивал кринжа: "Как ты наказываешь детей, которые не могут решить, кого из нас они предпочитают?" Кринж отвечает: "Я просто заставляю их ежедневно спрашивать обоих!"
  6. - -
  7. 4. В одном городе решили заменить кринжа на Санта-Клауса, чтобы дети не боялись. Однако когда Санта-Клаус начал наказывать плохих детей, все решили, что это был кринж в другом обличье. В итоге, они решили вернуть кринжа, потому что люди поняли, что он играет важную роль в обучении детей отличать правое от неправого и наказывать их за плохие поступки.
  8. - -
  9. 5. Святой Николай спрашивал кринжа: "Как ты обучаешь детей, чтобы они стали лучше?" Кринж отвечает: "Я просто показываю им свои длинные рога и говорю: 'Если вы хотите избежать меня, нужно стать более умными и добрыми'."
  10. - -
  11. 6. В одном городе решили устроить конкурс на лучший анекдот о кринже. Однако, когда все собрались, кринж сам вышел на сцену и сказал: "Друзья, я знаю, что у вас есть много анекдотов о мне, но сегодня я хочу услышать анекдоты о вас самих. Покажите, что вы смогли узнать от меня!"
  12. - -
  13. 7. Святой Николай спрашивал кринжа: "Как ты обрабатываешь ситуацию, когда дети утверждают, что они хорошие, хотя их поступки говорят о противоположном?" Кринж отвечает: "Я просто показываю им свои когти и говорю: 'Эти когти - это результат моей работы с плохими детьми. Не хотите стать одной из них?'"
  14. - -
  15. 8. В одном городе решили организовать фестиваль, на котором кринж будет главным героем. Однако кринж не смог прийти, и люди решили заменить его. Однако, когда кринж узнал об этом, он сказал: "Я понимаю, что люди хотят увидеть что-то новое, но помните, что я - часть вашей культуры и истории. Не забывайте о моей важной миссии!"
  16. +
  17. Святой Николай спрашивал кринжа: "Помнишь, что делал мальчик, который всегда играл в футбол в зимнюю ночь?" Кринж отвечает: "Нет, но я знаю, что сегодня вечер - вторник!"
  18. +
  19. В одном городе решили устроить праздник в честь кринжа. Организаторы спрашивали у местных жителей, что им бы хотелось видеть на этом празднике. Одна женщина ответила: "Хотела бы видеть кринжа, который бы был менее строгим к детьми!"
  20. +
  21. Святой Николай спрашивал кринжа: "Как ты наказываешь детей, которые не могут решить, кого из нас они предпочитают?" Кринж отвечает: "Я просто заставляю их ежедневно спрашивать обоих!"
  22. +
  23. В одном городе решили заменить кринжа на Санта-Клауса, чтобы дети не боялись. Однако когда Санта-Клаус начал наказывать плохих детей, все решили, что это был кринж в другом обличье. В итоге, они решили вернуть кринжа, потому что люди поняли, что он играет важную роль в обучении детей отличать правое от неправого и наказывать их за плохие поступки.
  24. +
  25. Святой Николай спрашивал кринжа: "Как ты обучаешь детей, чтобы они стали лучше?" Кринж отвечает: "Я просто показываю им свои длинные рога и говорю: 'Если вы хотите избежать меня, нужно стать более умными и добрыми'."
  26. +
  27. В одном городе решили устроить конкурс на лучший анекдот о кринже. Однако, когда все собрались, кринж сам вышел на сцену и сказал: "Друзья, я знаю, что у вас есть много анекдотов о мне, но сегодня я хочу услышать анекдоты о вас самих. Покажите, что вы смогли узнать от меня!"
  28. +
  29. Святой Николай спрашивал кринжа: "Как ты обрабатываешь ситуацию, когда дети утверждают, что они хорошие, хотя их поступки говорят о противоположном?" Кринж отвечает: "Я просто показываю им свои когти и говорю: 'Эти когти - это результат моей работы с плохими детьми. Не хотите стать одной из них?'"
  30. +
  31. В одном городе решили организовать фестиваль, на котором кринж будет главным героем. Однако кринж не смог прийти, и люди решили заменить его. Однако, когда кринж узнал об этом, он сказал: "Я понимаю, что люди хотят увидеть что-то новое, но помните, что я - часть вашей культуры и истории. Не забывайте о моей важной миссии!"
+

Таким образом, анекдоты о кринже стали популярным способом рассказать юмористические истории, которые одновременно передают важные уроки и подчеркивают культурное значение этого удивительного персонажа.

+
) } \ No newline at end of file From 0f0e0aacf77e61de0a12ce87bc3f3a0de98eecde Mon Sep 17 00:00:00 2001 From: fourhtyoz Date: Tue, 9 Apr 2024 21:53:29 +0300 Subject: [PATCH 4/7] sending emails via node-cron + bull --- backend/controllers/apiController.js | 1 - backend/index.js | 26 ++- backend/package-lock.json | 298 +++++++++++++++++++++++++++ backend/package.json | 4 + backend/tasks.js | 39 ++++ 5 files changed, 365 insertions(+), 3 deletions(-) create mode 100644 backend/tasks.js diff --git a/backend/controllers/apiController.js b/backend/controllers/apiController.js index b0a2446..cadd6a3 100644 --- a/backend/controllers/apiController.js +++ b/backend/controllers/apiController.js @@ -1,6 +1,5 @@ const asyncHandler = require('express-async-handler') -// Models const Joke = require('../models/joke'); exports.get_joke = asyncHandler(async (req, res, next) => { diff --git a/backend/index.js b/backend/index.js index 1847624..de3ad0c 100644 --- a/backend/index.js +++ b/backend/index.js @@ -5,6 +5,12 @@ const mongoose = require('mongoose') const requireAuth = require('./middlewares/requireAuth'); const dotenv = require('dotenv') const createError = require('http-errors'); +const bodyParser = require('body-parser') +const cron = require('node-cron'); +const { sendEmail } = require('./tasks'); +const Joke = require('./models/joke'); +const User = require('./models/user') + dotenv.config() // DB @@ -29,8 +35,8 @@ const app = express() // Middleware app.use(cors()) app.use(morgan('common')) -app.use(express.json()); -app.use(express.urlencoded({ extended: true })); +app.use(bodyParser.urlencoded({ extended: false })) +app.use(bodyParser.json()) // URLs app.use('/', indexRouter) @@ -41,6 +47,22 @@ app.use((req, res, next) => { createError(404); }); +// cronjobs +cron.schedule('* * * * *', async () => { + let joke = await Joke.aggregate([{ $sample: { size: 1}}]) + joke = joke.length > 0 ? joke[0] : null + if (joke) { + const users = await User.find({}) + for (let user of users) { + sendEmail({ + to: user.email, + subject: 'Cringomba! Your joke of the day', + body: joke.text + }) + } + } +}); + const port = process.env.PORT || 8000 app.listen(port, () => { console.log('Server is listening on ' + port) diff --git a/backend/package-lock.json b/backend/package-lock.json index e0fa5fd..20e9c0b 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -10,6 +10,8 @@ "license": "ISC", "dependencies": { "bcrypt": "^5.1.1", + "body-parser": "^1.20.2", + "bull": "^4.12.2", "cors": "^2.8.5", "cross-env": "^7.0.3", "dotenv": "^16.4.5", @@ -21,10 +23,16 @@ "mongodb": "^6.5.0", "mongoose": "^8.2.3", "morgan": "^1.10.0", + "node-cron": "^3.0.3", + "nodemailer": "^6.9.13", "nodemon": "^3.1.0", "puppeteer": "^22.6.0", "supertest": "^6.3.4", "sv443-joke-api": "^0.1.0" + }, + "engines": { + "node": "21.5.0", + "npm": "10.2.4" } }, "node_modules/@ampproject/remapping": { @@ -554,6 +562,11 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1322,6 +1335,78 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@puppeteer/browsers": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.0.tgz", @@ -2060,6 +2145,23 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/bull": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bull/-/bull-4.12.2.tgz", + "integrity": "sha512-WPuc0VCYx+cIVMiZtPwRpWyyJFBrj4/OgKJ6n9Jf4tIw7rQNV+HAKQv15UDkcTvfpGFehvod7Fd1YztbYSJIDQ==", + "dependencies": { + "cron-parser": "^4.2.1", + "get-port": "^5.1.1", + "ioredis": "^5.3.2", + "lodash": "^4.17.21", + "msgpackr": "^1.10.1", + "semver": "^7.5.2", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2218,6 +2320,14 @@ "node": ">=12" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -2445,6 +2555,17 @@ "node": ">=8" } }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -2554,6 +2675,14 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3160,6 +3289,17 @@ "node": ">=8.0.0" } }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -3512,6 +3652,50 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ioredis": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", + "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==", + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ioredis/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ioredis/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -5308,11 +5492,26 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -5354,6 +5553,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -5719,6 +5926,35 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/msgpackr": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.1.tgz", + "integrity": "sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.0.7" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5745,6 +5981,17 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, + "node_modules/node-cron": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.3.tgz", + "integrity": "sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==", + "dependencies": { + "uuid": "8.3.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -5783,6 +6030,17 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -5793,6 +6051,14 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, + "node_modules/nodemailer": { + "version": "6.9.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", + "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/nodemon": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", @@ -6419,6 +6685,25 @@ "node": ">=8.10.0" } }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6773,6 +7058,11 @@ "node": ">=8" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -7187,6 +7477,14 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", diff --git a/backend/package.json b/backend/package.json index 34017f3..e944ddb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -17,6 +17,8 @@ "license": "ISC", "dependencies": { "bcrypt": "^5.1.1", + "body-parser": "^1.20.2", + "bull": "^4.12.2", "cors": "^2.8.5", "cross-env": "^7.0.3", "dotenv": "^16.4.5", @@ -28,6 +30,8 @@ "mongodb": "^6.5.0", "mongoose": "^8.2.3", "morgan": "^1.10.0", + "node-cron": "^3.0.3", + "nodemailer": "^6.9.13", "nodemon": "^3.1.0", "puppeteer": "^22.6.0", "supertest": "^6.3.4", diff --git a/backend/tasks.js b/backend/tasks.js new file mode 100644 index 0000000..89a9ef2 --- /dev/null +++ b/backend/tasks.js @@ -0,0 +1,39 @@ +const nodemailer = require('nodemailer'); +const Queue = require('bull') + +const emailQueue = new Queue('emails', {}) +const sendEmail = (data) => emailQueue.add(data) + +emailQueue.process(async (job) => { + const { to, subject, body } = job.data + + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + port: process.env.SMTP_PORT, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + } + }); + + let message = { + from: process.env.SMTP_FROM, + to: to, + subject: subject, + text: body, + }; + + await transporter.sendMail(message, (err, info) => { + if (err) { + console.log('Error occurred. ' + err.message); + return process.exit(1); + } + }); + + job.progress(100); + return Promise.resolve(); +}) + +module.exports = { + sendEmail +} From 4467be3d40b023356d85188182213c8fdead952f Mon Sep 17 00:00:00 2001 From: fourhtyoz Date: Tue, 9 Apr 2024 22:10:35 +0300 Subject: [PATCH 5/7] fixed navbar styles --- frontend/src/components/Navbar.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Navbar.module.css b/frontend/src/components/Navbar.module.css index 1321408..dda167e 100644 --- a/frontend/src/components/Navbar.module.css +++ b/frontend/src/components/Navbar.module.css @@ -37,7 +37,7 @@ background-color: transparent; border: none; padding: 5px 25px; - font-size: larger; + font-size: 16px; border-radius: 10px; border: 1px solid #383838; color: #ffffff; From 675ee4b1fbd1a2c7b138001493aa8b9e86106b69 Mon Sep 17 00:00:00 2001 From: fourhtyoz Date: Tue, 9 Apr 2024 22:13:01 +0300 Subject: [PATCH 6/7] fix --- backend/tasks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/tasks.js b/backend/tasks.js index 89a9ef2..71aaf0e 100644 --- a/backend/tasks.js +++ b/backend/tasks.js @@ -16,7 +16,7 @@ emailQueue.process(async (job) => { } }); - let message = { + const message = { from: process.env.SMTP_FROM, to: to, subject: subject, From 2361b9d14d8e7738f7d5c5388afc3e987995c5c0 Mon Sep 17 00:00:00 2001 From: fourhtyoz Date: Tue, 9 Apr 2024 22:17:21 +0300 Subject: [PATCH 7/7] fixed httpServer --- frontend/src/api/httpServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/api/httpServer.js b/frontend/src/api/httpServer.js index 2cd6516..fb042de 100644 --- a/frontend/src/api/httpServer.js +++ b/frontend/src/api/httpServer.js @@ -1,7 +1,7 @@ import axios from "axios"; export const httpServer = axios.create({ - baseURL: process.env.HOST || 'http://localhost:8000' + baseURL: process.env.NODE_ENV === 'development' ? 'http://localhost:8000' : '' }); httpServer.interceptors.request.use(