Compare commits
No commits in common. "ff8cc4cccfac7aba0c3ea79366bfe4d729926e82" and "b7e4ba433cf79113f38996247996ea38744d9fcd" have entirely different histories.
ff8cc4cccf
...
b7e4ba433c
@ -1 +0,0 @@
|
||||
{ "lang": "ts" }
|
@ -1,61 +0,0 @@
|
||||
{
|
||||
"name": "deguapp-api",
|
||||
"version": "2.0.0",
|
||||
"description": "DeguApp REST API",
|
||||
"main": "dist/app.js",
|
||||
"bin": "dist/app.js",
|
||||
"types": "dist/app.d.ts",
|
||||
"scripts": {
|
||||
"start": "npm run start:prod",
|
||||
"start:dev": "tsx watch src/server.ts",
|
||||
"start:prod": "node dist/server.js",
|
||||
"tsc": "tsc -p .",
|
||||
"clean": "rimraf dist",
|
||||
"copy-assets": "ts-node src/utils/copyAssets",
|
||||
"build": "npm-run-all clean tsc copy-assets",
|
||||
"test": "mocha --config .mocharc.json --watch src/**/*.test.ts",
|
||||
"format": "npx prettier --write ."
|
||||
},
|
||||
"author": "Filip Rojek",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"colors": "1.4.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
"fs-extra": "^10.0.0",
|
||||
"inquirer": "^8.1.2",
|
||||
"morgan": "^1.10.0",
|
||||
"pad": "^3.2.0",
|
||||
"path": "^0.12.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.22",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/inquirer": "^8.1.3",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/shelljs": "^0.8.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.5.0",
|
||||
"@typescript-eslint/parser": "^5.5.0",
|
||||
"chai": "^4.3.4",
|
||||
"eslint": "^8.3.0",
|
||||
"http": "^0.0.1-security",
|
||||
"mocha": "^9.1.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"shelljs": "^0.8.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsx": "^4.7.3",
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/filiprojek/nork.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/filiprojek/nork/issues"
|
||||
},
|
||||
"homepage": "https://github.com/filiprojek/nork/blob/master/README.md"
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import express from "express";
|
||||
import morgan from "morgan";
|
||||
//import path from 'path'
|
||||
//import cors from 'cors'
|
||||
//import cookieParser from 'cookie-parser'
|
||||
import { router as routes } from "./routes";
|
||||
//import { router as middlewares } from './middlewares'
|
||||
//import env from './config/environment'
|
||||
|
||||
//export let corsWhitelist: Array<string>
|
||||
//if (env.CORS_WHITELIST != 'undefined') {
|
||||
// corsWhitelist = [...['http://localhost:8080', 'http://localhost:6040'], ...env.CORS_WHITELIST.split(';')]
|
||||
//} else {
|
||||
// corsWhitelist = ['http://localhost:8080', 'http://localhost:6040']
|
||||
//}
|
||||
//const corsOptions = {
|
||||
// origin: function (origin: any, callback: any) {
|
||||
// if (!origin || corsWhitelist.indexOf(origin) !== -1) {
|
||||
// callback(null, true)
|
||||
// } else {
|
||||
// callback(new Error('Not allowed by CORS'))
|
||||
// }
|
||||
// },
|
||||
// optionsSuccessStatus: 200,
|
||||
// credentials: true
|
||||
//}
|
||||
|
||||
export const app = express();
|
||||
|
||||
// Middlewares
|
||||
//app.use(middlewares)
|
||||
//app.set('view engine', 'ejs')
|
||||
//app.set('views', path.join(__dirname, 'views'))
|
||||
//app.use(cors(corsOptions))
|
||||
app.use(morgan("dev"));
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json());
|
||||
//app.use(express.static(path.join(__dirname, 'public')))
|
||||
//app.use(cookieParser())
|
||||
|
||||
// Routes
|
||||
app.use(routes);
|
@ -1,4 +0,0 @@
|
||||
import path from "path";
|
||||
import { Env } from "nork";
|
||||
const env = Env.get(path.join(__dirname, "../.env"));
|
||||
export default env;
|
@ -1,5 +0,0 @@
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export function login_post(req: Request, res: Response) {
|
||||
res.send("logged in");
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
import { Router } from "express";
|
||||
import * as authController from "../controllers/authController";
|
||||
//import authValidator from "../validators/authValidator";
|
||||
//import handleValidation from "../middlewares/handleValidation";
|
||||
//import { requireAuth } from "../middlewares/authMiddleware";
|
||||
|
||||
const router = Router();
|
||||
|
||||
//const mws = [requireAuth, handleValidation.handleValidationError];
|
||||
|
||||
router.post("/login", authController.login_post);
|
||||
|
||||
//router.post(
|
||||
// "/login",
|
||||
// authValidator.checkUserLogin(),
|
||||
// handleValidation.handleValidationError,
|
||||
// userController.login_post
|
||||
//);
|
||||
|
||||
//router.post(
|
||||
// "/register",
|
||||
// authValidator.checkUserRegister(),
|
||||
// handleValidation.handleValidationError,
|
||||
// userController.register_post
|
||||
//);
|
||||
|
||||
//router.post("/logout", userController.logout_post);
|
||||
|
||||
//router.post(
|
||||
// "/edit",
|
||||
// [requireAuth],
|
||||
// authValidator.checkChange(),
|
||||
// userController.edit_post
|
||||
//);
|
||||
|
||||
export default router;
|
@ -1,15 +0,0 @@
|
||||
import { Request, Response, Router } from "express";
|
||||
import path from "path";
|
||||
import authRoutes from "./authRoutes";
|
||||
export const router = Router();
|
||||
|
||||
router.use("/api/auth", authRoutes);
|
||||
|
||||
//router.get("*", (req: Request, res: Response) => {
|
||||
// res.sendFile(path.join(__dirname, "../views/index.html"));
|
||||
//});
|
||||
|
||||
// 404
|
||||
router.use((req: Request, res: Response) => {
|
||||
res.status(404).send("Error 404\n");
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
import http from "http";
|
||||
import { app } from "./app";
|
||||
import env from "./config/environment";
|
||||
//const env = {
|
||||
// APP_PORT: 8080,
|
||||
// APP_HOSTNAME: "127.0.0.1",
|
||||
//};
|
||||
import { Log } from "nork";
|
||||
//import database from './config/database'
|
||||
const port: number = env.APP_PORT || 8080;
|
||||
const hostname: string = env.APP_HOSTNAME || "localhost";
|
||||
export const server = http.createServer(app);
|
||||
|
||||
// Server
|
||||
export function runServer(): void {
|
||||
server.listen(port, hostname, () => {
|
||||
Log.info(200, `Server is listening on http://${hostname}:${port}`);
|
||||
});
|
||||
}
|
||||
|
||||
//if (!env.NORK.database) {
|
||||
runServer();
|
||||
//} else {
|
||||
// const db_connection = database()
|
||||
// runServer()
|
||||
//}
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
||||
"rootDir": "./src" /* Specify the root folder within your source files. */,
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
"baseUrl": "./" /* Base directory to resolve non-absolute module names. */,
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */,
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": ["_old", "node_modules", "src/make-files", "src/skeletons", "src/tests", "src/interfaces", "src/utils"]
|
||||
}
|
BIN
backend/.db.txt.swp
Normal file
59
backend/.githooks/pre-push
Executable file
@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
|
||||
# @link https://gist.github.com/mattscilipoti/8424018
|
||||
#
|
||||
# Called by "git push" after it has checked the remote status,
|
||||
# but before anything has been pushed.
|
||||
#
|
||||
# If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# Steps to install, from the root directory of your repo...
|
||||
# 1. Copy the file into your repo at `.git/hooks/pre-push`
|
||||
# 2. Set executable permissions, run `chmod +x .git/hooks/pre-push`
|
||||
# 3. Or, use `rake hooks:pre_push` to install
|
||||
#
|
||||
# Try a push to master, you should get a message `*** [Policy] Never push code directly to...`
|
||||
#
|
||||
# The commands below will not be allowed...
|
||||
# `git push origin master`
|
||||
# `git push --force origin master`
|
||||
# `git push --delete origin master`
|
||||
|
||||
|
||||
protected_branch='master'
|
||||
|
||||
policy="\n\n[Policy] Never push code directly to the "$protected_branch" branch! (Prevented with pre-push hook.)\n\n"
|
||||
|
||||
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
|
||||
|
||||
push_command=$(ps -ocommand= -p $PPID)
|
||||
|
||||
is_destructive='force|delete|\-f'
|
||||
|
||||
will_remove_protected_branch=':'$protected_branch
|
||||
|
||||
do_exit(){
|
||||
echo -e $policy
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ $push_command =~ $is_destructive ]] && [ $current_branch = $protected_branch ]; then
|
||||
do_exit
|
||||
fi
|
||||
|
||||
if [[ $push_command =~ $is_destructive ]] && [[ $push_command =~ $protected_branch ]]; then
|
||||
do_exit
|
||||
fi
|
||||
|
||||
if [[ $push_command =~ $will_remove_protected_branch ]]; then
|
||||
do_exit
|
||||
fi
|
||||
|
||||
# Prevent ALL pushes to protected_branch
|
||||
if [[ $push_command =~ $protected_branch ]] || [ $current_branch = $protected_branch ]; then
|
||||
do_exit
|
||||
fi
|
||||
|
||||
unset do_exit
|
||||
|
||||
exit 0
|
1
api/.gitignore → backend/.gitignore
vendored
@ -1,3 +1,2 @@
|
||||
node_modules/
|
||||
package-lock.json
|
||||
.env
|
15
backend/.prettierrc
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"semi": false,
|
||||
"trailingComma": "none",
|
||||
"jsxSingleQuote": true,
|
||||
"jsxBracketSameLine": true,
|
||||
"printWidth": 200,
|
||||
"bracketSpacing": true,
|
||||
"vueIndentScriptAndStyle": true,
|
||||
"arrowParens": "always",
|
||||
"bracketSameLine": false,
|
||||
"endOfLine": "lf"
|
||||
}
|
1
backend/README.md
Normal file
@ -0,0 +1 @@
|
||||
# New Project
|
31
backend/db.txt
Normal file
@ -0,0 +1,31 @@
|
||||
User
|
||||
name
|
||||
email
|
||||
password
|
||||
|
||||
Beer
|
||||
brand
|
||||
name
|
||||
degree
|
||||
packaging
|
||||
|
||||
Events
|
||||
date
|
||||
name
|
||||
participants
|
||||
|
||||
Review
|
||||
logo
|
||||
aroma
|
||||
foam
|
||||
color
|
||||
bitterness
|
||||
sweetness
|
||||
note
|
||||
again
|
||||
overall_rating
|
||||
final_rating
|
||||
date
|
||||
participants
|
||||
signature
|
||||
|
12
backend/norkconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"project_name": "deguapp",
|
||||
"lang": "ts",
|
||||
"author": "Filip Rojek",
|
||||
"database": {
|
||||
"db": "mongodb",
|
||||
"orm": "mongoose"
|
||||
},
|
||||
"website": "http://filiprojek.cz/",
|
||||
"email": "filip@filiprojek.cz",
|
||||
"version": "3.0.5"
|
||||
}
|
7161
backend/package-lock.json
generated
Normal file
73
backend/package.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "deguapp",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "dist/server.js",
|
||||
"private": "true",
|
||||
"keywords": [],
|
||||
"author": "Filip Rojek <filip@filiprojek.cz> (http://filiprojek.cz/)",
|
||||
"repository": "github:username/repo",
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"start": "node dist/server.js",
|
||||
"start:dev": "nodemon src/server.ts",
|
||||
"test": "jest",
|
||||
"clean": "rimraf dist/*",
|
||||
"copy-assets": "npx ts-node src/utils/copyAssets",
|
||||
"tsc": "tsc -p .",
|
||||
"build": "npm-run-all clean tsc copy-assets",
|
||||
"format": "npx prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"colors": "1.4.0",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^8.2.0",
|
||||
"ejs": "^3.1.6",
|
||||
"express": "^4.17.1",
|
||||
"express-validator": "^6.14.2",
|
||||
"fs-extra": "^10.0.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mongoose": "^5.12.3",
|
||||
"pg": "^8.7.1",
|
||||
"pg-hstore": "^2.3.4",
|
||||
"sequelize": "^6.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/cors": "^2.8.10",
|
||||
"@types/ejs": "^3.0.6",
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/fs-extra": "^9.0.12",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/jsonwebtoken": "^8.5.8",
|
||||
"@types/mongoose": "^5.10.5",
|
||||
"@types/morgan": "^1.9.2",
|
||||
"@types/node": "^14.14.41",
|
||||
"@types/shelljs": "^0.8.9",
|
||||
"jest": "^27.0.6",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rimraf": "^3.0.2",
|
||||
"shelljs": "^0.8.4",
|
||||
"ts-jest": "^27.1.5",
|
||||
"ts-node": "^10.8.1",
|
||||
"typescript": "^4.2.4",
|
||||
"morgan": "^1.10.0"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
"testEnvironment": "node"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"ignore": [
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.ts",
|
||||
".git",
|
||||
"node_modules"
|
||||
],
|
||||
"watch": [
|
||||
"src"
|
||||
],
|
||||
"ext": "ts, js"
|
||||
}
|
||||
}
|
5
backend/setup-repo.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
cp .githooks/* .git/hooks
|
||||
|
||||
echo "hooks have been copied"
|
26
backend/src/.env.example
Normal file
@ -0,0 +1,26 @@
|
||||
# General
|
||||
APP_PORT = 6060
|
||||
APP_HOSTNAME = 'localhost'
|
||||
APP_HOST = 'http://localhost:8080' # frontend url
|
||||
|
||||
# Timezone
|
||||
TZ = 'Europe/Prague'
|
||||
|
||||
CORS_WHITELIST = http://172.15.46.21:8080;http://192.168.0.1:8080
|
||||
JWT_SECRET = ''
|
||||
|
||||
# MongoDB
|
||||
DB_URI = 'mongodb://username:password@localhost:27017/database?authSource=admin'
|
||||
|
||||
# PostgreSQL
|
||||
DB_PORT = 5432
|
||||
DB_HOST = '127.0.0.1'
|
||||
DB_USERNAME = ''
|
||||
DB_PASSWORD = ''
|
||||
DB_DATABASE = ''
|
||||
|
||||
# SMTP
|
||||
SMTP_HOST = ''
|
||||
SMTP_USER = ''
|
||||
SMTP_PASS = ''
|
||||
SMTP_FROM = ''
|
42
backend/src/app.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import express from 'express'
|
||||
import morgan from 'morgan'
|
||||
import path from 'path'
|
||||
import cors from 'cors'
|
||||
import cookieParser from 'cookie-parser'
|
||||
import { router as routes } from './routes'
|
||||
import { router as middlewares } from './middlewares'
|
||||
import env from './config/environment'
|
||||
|
||||
export let corsWhitelist: Array<string>
|
||||
if (env.CORS_WHITELIST != 'undefined') {
|
||||
corsWhitelist = [...['http://localhost:8080', 'http://localhost:6040'], ...env.CORS_WHITELIST.split(';')]
|
||||
} else {
|
||||
corsWhitelist = ['http://localhost:8080', 'http://localhost:6040']
|
||||
}
|
||||
const corsOptions = {
|
||||
origin: function (origin: any, callback: any) {
|
||||
if (!origin || corsWhitelist.indexOf(origin) !== -1) {
|
||||
callback(null, true)
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'))
|
||||
}
|
||||
},
|
||||
optionsSuccessStatus: 200,
|
||||
credentials: true
|
||||
}
|
||||
|
||||
export const app = express()
|
||||
|
||||
// Middlewares
|
||||
app.use(middlewares)
|
||||
app.set('view engine', 'ejs')
|
||||
app.set('views', path.join(__dirname, 'views'))
|
||||
app.use(cors(corsOptions))
|
||||
app.use(morgan('dev'))
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
app.use(express.json())
|
||||
app.use(express.static(path.join(__dirname, 'public')))
|
||||
app.use(cookieParser())
|
||||
|
||||
// Routes
|
||||
app.use(routes)
|
49
backend/src/config/database.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import mongoose from 'mongoose'
|
||||
import env from './environment'
|
||||
import { Err, Succ } from '../services/globalService'
|
||||
import db from './sequelize.config'
|
||||
|
||||
// MongoDB
|
||||
const dbURI: string = env.DB_URI
|
||||
async function connect() {
|
||||
if (!env.NORK.database) {
|
||||
new Err(500, 'no database is in norkcfg.json')
|
||||
return false
|
||||
}
|
||||
|
||||
if (env.NORK.database.orm == 'mongoose') {
|
||||
mongoose
|
||||
.connect(dbURI, {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
useCreateIndex: true
|
||||
})
|
||||
.then(() => {
|
||||
new Succ(200, 'connected to db')
|
||||
return true
|
||||
})
|
||||
.catch((err: any) => {
|
||||
new Err(500, err)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
if (env.NORK.database.orm == 'sequelize') {
|
||||
db.sync()
|
||||
.then(() => {
|
||||
new Succ(200, 'connected to db')
|
||||
return true
|
||||
})
|
||||
.catch((err: any) => {
|
||||
new Err(500, `Can't connect to db\n${err}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
if (env.NORK.database.db.length > 0) {
|
||||
new Err(500, `unsupported database ${env.NORK.database.db}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export default connect
|
59
backend/src/config/environment.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { Err } from '../services/globalService'
|
||||
import dotenv from 'dotenv'
|
||||
const env_path = process.env.NODE_ENV ? `../.env.${process.env.NODE_ENV}` : '../.env'
|
||||
|
||||
dotenv.config({ path: path.join(__dirname, env_path) })
|
||||
const norkcfg = fs.readJSONSync(path.join(__dirname, '../../norkconfig.json'))
|
||||
|
||||
if (norkcfg.database) {
|
||||
if (norkcfg.database.db == 'postgresql') {
|
||||
if (!process.env.DB_PORT) {
|
||||
process.env.DB_PORT = '5432'
|
||||
}
|
||||
if (!process.env.DB_HOST) {
|
||||
process.env.DB_HOST = '127.0.0.1'
|
||||
}
|
||||
if (!process.env.DB_USERNAME || !process.env.DB_PASSWORD || !process.env.DB_DATABASE) {
|
||||
new Err(500, 'missing DB parameters in .env file')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fs.existsSync(path.join(__dirname, env_path))) {
|
||||
console.log('$env_path = ', env_path)
|
||||
console.log('$__dirname = ', __dirname)
|
||||
new Err(500, `.env file for ${process.env.NODE_ENV ? process.env.NODE_ENV : ''} environment does not exists`)
|
||||
process.exit()
|
||||
}
|
||||
|
||||
if (process.env.JWT_SECRET === undefined || process.env.JWT_SECRET == '') {
|
||||
new Err(500, 'JWT_SECRET is not set!')
|
||||
process.exit()
|
||||
}
|
||||
|
||||
export default {
|
||||
// General
|
||||
APP_PORT: Number(process.env.APP_PORT),
|
||||
APP_HOST: String(process.env.APP_HOST),
|
||||
APP_HOSTNAME: process.env.APP_HOSTNAME !== undefined ? String(process.env.APP_HOSTNAME) : null,
|
||||
CORS_WHITELIST: String(process.env.CORS_WHITELIST),
|
||||
JWT_SECRET: String(process.env.JWT_SECRET),
|
||||
// MongoDB
|
||||
DB_URI: String(process.env.DB_URI),
|
||||
// PostgreSQL
|
||||
DB_PORT: Number(process.env.DB_PORT),
|
||||
DB_HOST: String(process.env.DB_HOST),
|
||||
DB_USERNAME: String(process.env.DB_USERNAME),
|
||||
DB_PASSWORD: String(process.env.DB_PASSWORD),
|
||||
DB_DATABASE: String(process.env.DB_DATABASE),
|
||||
// Nork
|
||||
NORK: norkcfg,
|
||||
// SMTP
|
||||
SMTP_HOST: String(process.env.SMTP_HOST),
|
||||
SMTP_USER: String(process.env.SMTP_USER),
|
||||
SMTP_PASS: String(process.env.SMTP_PASS),
|
||||
SMTP_FROM: String(process.env.SMTP_FROM)
|
||||
}
|
10
backend/src/config/sequelize.config.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Sequelize } from 'sequelize'
|
||||
import env from './environment'
|
||||
|
||||
const db = new Sequelize(env.DB_DATABASE, env.DB_USERNAME, env.DB_PASSWORD, {
|
||||
host: env.DB_HOST,
|
||||
dialect: 'postgres',
|
||||
logging: false
|
||||
})
|
||||
|
||||
export default db
|
26
backend/src/controllers/beerController.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { Request, Response } from 'express'
|
||||
import Beer from '../models/Beer'
|
||||
|
||||
export function add_post(req: Request, res: Response) {
|
||||
console.log(req.body, 'request body')
|
||||
const beer = new Beer(req.body)
|
||||
beer.save()
|
||||
res.json({status: 'ok'})
|
||||
return 0
|
||||
}
|
||||
|
||||
export function del_post(req: Request, res: Response) {
|
||||
return 0
|
||||
}
|
||||
|
||||
export function edit_post(req: Request, res: Response) {
|
||||
res.json({status: 'ok'})
|
||||
return 0
|
||||
}
|
||||
|
||||
export async function get_get(req: Request, res: Response) {
|
||||
const beer = await Beer.find();
|
||||
res.json(beer)
|
||||
return 0
|
||||
}
|
||||
|
15
backend/src/controllers/reviewController.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Request, Response } from 'express'
|
||||
import Review from '../models/Review'
|
||||
|
||||
export const root_get = (req: Request, res: Response) => {
|
||||
res.render('home')
|
||||
return true
|
||||
}
|
||||
|
||||
export function add_post(req: Request, res: Response) {
|
||||
console.log(req.body)
|
||||
const review = new Review(req.body);
|
||||
review.save()
|
||||
res.json({status: "ok"})
|
||||
}
|
||||
|
6
backend/src/controllers/rootController.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
export function root_get(req: Request, res: Response) {
|
||||
res.render('home')
|
||||
return true
|
||||
}
|
9
backend/src/controllers/userController.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Request, Response } from 'express'
|
||||
import User from '../models/User'
|
||||
|
||||
export function add_post(req: Request, res: Response) {
|
||||
const user = new User(req.body)
|
||||
user.save()
|
||||
res.json({status: 'ok'})
|
||||
return 0
|
||||
}
|
4
backend/src/interfaces/globalInterface.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface ErrType {
|
||||
code: number
|
||||
message: string
|
||||
}
|
49
backend/src/logs/Err.global.log
Normal file
@ -0,0 +1,49 @@
|
||||
Date: "2023-06-30 01:23:29" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 01:23:37" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 01:25:41" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 01:26:27" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 01:26:36" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 11:48:07" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 11:48:37" Type: "Err" Code: "500" Message: "{"message":"connect ENETUNREACH 10.123.0.1:27017 - Local (0.0.0.0:0)","reason":{"type":"Single","setName":null,"maxSetVersion":null,"maxElectionId":null,"servers":{},"stale":false,"compatible":true,"compatibilityError":null,"logicalSessionTimeoutMinutes":null,"heartbeatFrequencyMS":10000,"localThresholdMS":15,"commonWireVersion":null}}"
|
||||
Date: "2023-06-30 11:50:18" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:05:10" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:05:37" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:08:25" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:09:14" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:11:02" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:11:59" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:12:25" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:13:33" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:21:16" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:37:40" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:38:33" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 12:39:26" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 13:20:38" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 13:21:43" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 13:24:42" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 20:14:29" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 20:24:27" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 20:28:58" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 21:37:00" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 21:37:06" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 21:45:43" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:18:05" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:22:38" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:22:54" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:23:00" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:28:16" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:29:59" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:32:14" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:38:24" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:50:25" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:50:44" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:51:12" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:51:40" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 22:51:53" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 23:00:51" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-06-30 23:01:52" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-07-01 10:46:49" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-07-01 18:30:40" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-07-01 18:31:01" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-07-01 18:31:26" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
||||
Date: "2023-07-01 18:32:01" Type: "Err" Code: "500" Message: "unsupported database mongodb"
|
63
backend/src/middlewares/authMiddleware.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import env from '../config/environment'
|
||||
import { Err, Succ } from '../services/globalService'
|
||||
import User from '../models/User' // uncomment this
|
||||
|
||||
export function requireAuth(req: Request, res: Response, next: NextFunction) {
|
||||
const token = req.cookies.jwt
|
||||
new Err(500, 'uncomment code in authMiddleware before using!')
|
||||
if (token) {
|
||||
jwt.verify(token, env.JWT_SECRET, async (err: any, decodedToken: any) => {
|
||||
if (err) {
|
||||
// console.error(err.message)
|
||||
res.status(401).json(new Err(401, 'user is not authenticated'))
|
||||
}
|
||||
if (!err) {
|
||||
const user = (async () => {
|
||||
if (env.NORK.db.orm) {
|
||||
if (env.NORK.db.orm == 'sequelize') {
|
||||
return await User.findByPk(decodedToken.id)
|
||||
}
|
||||
if (env.NORK.db.orm == 'mongoose') {
|
||||
return await User.findById(decodedToken.id)
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})()
|
||||
|
||||
if (user === null) {
|
||||
res.status(401).json(new Err(401, 'user is not authenticated'))
|
||||
return
|
||||
}
|
||||
|
||||
res.locals.user = user
|
||||
new Succ(100, 'user is authenticated')
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
res.status(401).json(new Err(401, 'user is not authenticated'))
|
||||
}
|
||||
}
|
||||
|
||||
export function requireVerified(req: Request, res: Response, next: NextFunction) {
|
||||
if (res.locals.user._id) {
|
||||
if (res.locals.user.verified) {
|
||||
new Succ(100, 'user is verified')
|
||||
next()
|
||||
return
|
||||
}
|
||||
|
||||
res.status(403).json(new Err(403, 'user is not verified'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!res.locals.user._id) {
|
||||
res.status(401).json(new Err(401, 'user is not authenticated'))
|
||||
return
|
||||
}
|
||||
}
|
16
backend/src/middlewares/handleValidation.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import { validationResult } from 'express-validator'
|
||||
import { Err } from '../services/globalService'
|
||||
|
||||
class Middleware {
|
||||
handleValidationError(req: Request, res: Response, next: NextFunction) {
|
||||
const error = validationResult(req)
|
||||
if (!error.isEmpty()) {
|
||||
new Err(400, error)
|
||||
return res.status(400).json(new Err(400, 'validation error', error.array()[0]))
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
export default new Middleware()
|
6
backend/src/middlewares/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Router } from 'express'
|
||||
import { router as sayHiMiddleware } from '../middlewares/sayHiMiddleware'
|
||||
|
||||
export const router = Router()
|
||||
|
||||
// router.use(sayHiMiddleware)
|
9
backend/src/middlewares/sayHiMiddleware.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Router, Request, Response, NextFunction } from 'express'
|
||||
|
||||
export const router = Router()
|
||||
|
||||
router.use((req: Request, res: Response, next: NextFunction) => {
|
||||
console.log('Hi :)')
|
||||
|
||||
next()
|
||||
})
|
37
backend/src/models/Beer.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { Schema, model } from 'mongoose'
|
||||
import path from 'path'
|
||||
|
||||
const schema = new Schema<any>(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
degree: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
percentage: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
packaging: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
note: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
photo: {
|
||||
type: Array,
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
},
|
||||
)
|
||||
|
||||
export default model(path.basename(__filename).split('.')[0], schema)
|
||||
|
16
backend/src/models/Events.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Schema, model } from 'mongoose'
|
||||
import path from 'path'
|
||||
|
||||
export const schemaName = path.basename(__filename).split('.')[0]
|
||||
{
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
},
|
||||
)
|
||||
|
||||
export default model(path.basename(__filename).split('.')[0], schema)
|
68
backend/src/models/Review.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { Schema, model } from 'mongoose'
|
||||
import path from 'path'
|
||||
|
||||
const schema = new Schema<any>(
|
||||
{
|
||||
beer_id: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
logo: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
aroma: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
foam: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
color: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
bitterness: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
sweetness: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
note: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
again: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
overall_rating: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
final_rating: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
date: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
participants: {
|
||||
type: Array,
|
||||
required: false,
|
||||
},
|
||||
signature: {
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
},
|
||||
)
|
||||
|
||||
export default model(path.basename(__filename).split('.')[0], schema)
|
26
backend/src/models/User.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import path from 'path'
|
||||
import { Schema, model } from 'mongoose'
|
||||
|
||||
export const schemaName = path.basename(__filename).split('.')[0]
|
||||
const schema = new Schema(
|
||||
{
|
||||
username: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true
|
||||
},
|
||||
password: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
)
|
||||
|
||||
export default model(path.basename(__filename).split('.')[0], schema)
|
BIN
backend/src/public/expressjs.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
1
backend/src/public/nodejs_logo.svg
Normal file
After Width: | Height: | Size: 5.8 KiB |
11
backend/src/routes/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { Request, Response, Router } from 'express'
|
||||
import { router as rootRoutes } from './rootRoutes'
|
||||
|
||||
export const router = Router()
|
||||
|
||||
router.use(rootRoutes)
|
||||
|
||||
// 404
|
||||
router.use((req: Request, res: Response) => {
|
||||
res.status(404).send('E404')
|
||||
})
|
22
backend/src/routes/rootRoutes.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { Router } from 'express'
|
||||
import * as rootController from '../controllers/rootController'
|
||||
import * as beerController from '../controllers/beerController'
|
||||
import * as reviewController from '../controllers/reviewController'
|
||||
import * as userController from '../controllers/userController'
|
||||
import rootValidator from '../validators/rootValidator'
|
||||
import handleValidation from '../middlewares/handleValidation'
|
||||
|
||||
export const router = Router()
|
||||
const mws = [handleValidation.handleValidationError]
|
||||
|
||||
router.get('/', rootValidator.checkRootGet(), mws, rootController.root_get)
|
||||
|
||||
router.post('/api/v1/beer/add', beerController.add_post)
|
||||
router.post('/api/v1/beer/del', beerController.del_post)
|
||||
router.post('/api/v1/beer/edit', beerController.edit_post)
|
||||
router.get('/api/v1/beer/get', beerController.get_get)
|
||||
|
||||
router.post('/api/v1/review/add', reviewController.add_post)
|
||||
//router.post('/api/v1/review/del', reviewController.del_post)
|
||||
|
||||
router.post('/api/v1/user/add', userController.add_post)
|
31
backend/src/server.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import http from 'http'
|
||||
import { app } from './app'
|
||||
import env from './config/environment'
|
||||
import { Succ } from './services/globalService'
|
||||
import database from './config/database'
|
||||
const port: number = env.APP_PORT || 8080
|
||||
const hostname: string = env.APP_HOSTNAME || 'localhost'
|
||||
export const server = http.createServer(app)
|
||||
|
||||
// Server
|
||||
export function runServer(): void {
|
||||
server.listen(port, hostname, () => {
|
||||
new Succ(200, `Server is listening on http://${hostname}:${port}`)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: Fix this shit
|
||||
//(async () => {
|
||||
// if (!env.NORK.database) {
|
||||
// runServer()
|
||||
// } else {
|
||||
// const db_connection = await database()
|
||||
// if (db_connection) {
|
||||
// runServer()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//})()
|
||||
//
|
||||
runServer()
|
||||
const db_connection = database()
|
173
backend/src/services/globalService.ts
Normal file
@ -0,0 +1,173 @@
|
||||
import colors from 'colors'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
export interface ErrType {
|
||||
code: number
|
||||
message: string
|
||||
data?: any
|
||||
}
|
||||
|
||||
export class Err implements ErrType {
|
||||
code: number
|
||||
message: string
|
||||
data: any
|
||||
|
||||
constructor(code: number, message: string | object, data: any = null) {
|
||||
this.code = code
|
||||
typeof message === 'object' ? (this.message = JSON.stringify(message)) : (this.message = message)
|
||||
data ? (this.data = data) : false
|
||||
// typeof data === 'object' ? (this.data = JSON.stringify(data)) : (this.data = data)
|
||||
|
||||
this.drop()
|
||||
}
|
||||
|
||||
drop() {
|
||||
if (this.data) {
|
||||
console.log(colors.bgRed(`${this.code}`) + colors.bgBlack.red(` ${this.message}`) + this.data)
|
||||
Log.make('Err', this.code, this.message, this.data)
|
||||
return {
|
||||
code: this.code,
|
||||
message: this.message,
|
||||
data: this.data
|
||||
}
|
||||
}
|
||||
|
||||
console.log(colors.bgRed(`${this.code}`) + colors.bgBlack.red(` ${this.message}`))
|
||||
Log.make('Err', this.code, this.message)
|
||||
return {
|
||||
code: this.code,
|
||||
message: this.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Succ {
|
||||
code: number
|
||||
message: string
|
||||
data?: any
|
||||
|
||||
constructor(code: number, message: string, data: any = null) {
|
||||
this.code = code
|
||||
this.message = message
|
||||
data ? (this.data = data) : false
|
||||
this.drop()
|
||||
}
|
||||
|
||||
drop() {
|
||||
if (this.data) {
|
||||
console.log(colors.bgGreen.black(`${this.code}`) + colors.green.bgBlack(` ${this.message}`) + this.data)
|
||||
return {
|
||||
code: this.code,
|
||||
message: this.message,
|
||||
data: this.data
|
||||
}
|
||||
}
|
||||
|
||||
console.log(colors.bgGreen.black(`${this.code}`) + colors.green.bgBlack(` ${this.message}`))
|
||||
return {
|
||||
code: this.code,
|
||||
message: this.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface LogType {
|
||||
type: 'Err' | 'Succ' | 'Info'
|
||||
code?: number
|
||||
message?: string
|
||||
data?: any
|
||||
logFile?: string
|
||||
}
|
||||
export class Log implements LogType {
|
||||
type: 'Err' | 'Succ' | 'Info'
|
||||
code?: number
|
||||
message?: string
|
||||
data?: any
|
||||
logFile?: string
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* - Type of log
|
||||
* - Err | Succ | Info
|
||||
* @param code
|
||||
* - not required
|
||||
* - HTTP status code
|
||||
* @param message
|
||||
* - could be anything
|
||||
* @param data
|
||||
* - could be anything
|
||||
* @param logFile
|
||||
* - name of logFile
|
||||
* - default is log type file
|
||||
*/
|
||||
constructor(type: 'Err' | 'Succ' | 'Info', code?: number, message?: string, data?: any, logFile?: string) {
|
||||
this.type = type
|
||||
this.code = code
|
||||
this.message = message
|
||||
this.data = data
|
||||
this.logFile = logFile
|
||||
|
||||
if (!this.logFile) {
|
||||
this.logFile = `${type}.global.log`
|
||||
} else {
|
||||
this.logFile = this.logFile + '.log'
|
||||
}
|
||||
|
||||
this.logFile = path.join(__dirname, this.logFile)
|
||||
}
|
||||
|
||||
static pathMake(type: string, name?: string) {
|
||||
let logName
|
||||
if (!name) {
|
||||
logName = `${type}.global.log`
|
||||
} else {
|
||||
logName = name + '.log'
|
||||
}
|
||||
|
||||
return path.join(__dirname, '../logs/' + logName)
|
||||
}
|
||||
|
||||
/**
|
||||
* returns current date in my custom format
|
||||
*/
|
||||
static dateNow(): string {
|
||||
/**
|
||||
* @param num: number
|
||||
*
|
||||
* receives number and returns two digits number
|
||||
* example:
|
||||
* input num = 9 => returns string 09
|
||||
*/
|
||||
function add0(num: number): string {
|
||||
if (num.toString().length <= 1) {
|
||||
return '0' + String(num)
|
||||
}
|
||||
return String(num)
|
||||
}
|
||||
|
||||
const d = new Date()
|
||||
return `${d.getFullYear()}-${add0(d.getMonth() + 1)}-${add0(d.getDate())} ${add0(d.getHours())}:${add0(d.getMinutes())}:${add0(d.getSeconds())}`
|
||||
}
|
||||
|
||||
static make(type: 'Err' | 'Succ' | 'Info', code?: number, message?: string, data?: any, logFile?: string) {
|
||||
let realPath = Log.pathMake(type, logFile)
|
||||
let formattedData = `Date: "${Log.dateNow()}" Type: "${type}"`
|
||||
|
||||
code ? (formattedData += ` Code: "${code}"`) : false
|
||||
message ? (formattedData += ` Message: "${message}"`) : false
|
||||
if (data) {
|
||||
if (typeof data === 'object') {
|
||||
data = JSON.stringify(data)
|
||||
}
|
||||
formattedData += ` Data: "${data}"`
|
||||
}
|
||||
formattedData += '\n'
|
||||
|
||||
if (fs.existsSync(realPath)) {
|
||||
fs.appendFileSync(realPath, formattedData)
|
||||
} else {
|
||||
fs.writeFileSync(realPath, formattedData)
|
||||
}
|
||||
}
|
||||
}
|
3
backend/src/services/rootService.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const helloWorld = () => {
|
||||
console.log('hello world')
|
||||
}
|
7
backend/src/utils/copyAssets.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import * as shell from 'shelljs'
|
||||
|
||||
// Copy all the view templates
|
||||
shell.cp('-R', 'src/views', 'dist/')
|
||||
shell.cp('-R', 'src/public', 'dist/')
|
||||
shell.cp('-R', 'src/models', 'dist/')
|
||||
shell.cp('-u', 'src/.env', 'dist/')
|
9
backend/src/validators/rootValidator.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { body, param, query } from 'express-validator'
|
||||
|
||||
class rootValidator {
|
||||
checkRootGet() {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export default new rootValidator()
|
69
backend/src/views/home.ejs
Normal file
@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>New Project</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
.content {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 5rem;
|
||||
flex-direction: column;
|
||||
}
|
||||
footer, .welcome {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.welcome {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
img {
|
||||
width: 200px;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
footer {
|
||||
padding-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.logos {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<div class="welcome">
|
||||
<h1>Let's make something amazing!</h1>
|
||||
<div class="logos">
|
||||
<img src="/nodejs_logo.svg" alt="node.js logo">
|
||||
<img src="/expressjs.png" alt="express.js logo">
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div class="author">
|
||||
<p>Made by </p><a href="http://www.filiprojek.cz">filiprojek.cz</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
0
backend/tests/beer_routes.sh
Normal file
0
backend/tests/run.sh
Normal file
63
backend/tsconfig.json
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es6",
|
||||
|
||||
/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs",
|
||||
|
||||
/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "./dist",
|
||||
|
||||
/* Redirect output structure to the directory. */
|
||||
"rootDir": "./src",
|
||||
/* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true,
|
||||
/* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
"baseUrl": "./",
|
||||
"esModuleInterop": true,
|
||||
/* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
"resolveJsonModule": true,
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
/* Experimental Options */
|
||||
"experimentalDecorators": true,
|
||||
/* Enables experimental support for ES7 decorators. */
|
||||
"emitDecoratorMetadata": true,
|
||||
/* Enables experimental support for emitting type metadata for decorators. */
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true,
|
||||
/* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true
|
||||
/* Disallow inconsistently-cased references to the same file. */
|
||||
},
|
||||
"exclude": ["src/tests"]
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/beer
|
||||
/add
|
||||
/del
|
||||
/get
|
||||
/edit?
|
||||
/review
|
||||
/add
|
||||
/del
|
||||
/get
|
||||
/edit?
|
||||
|
||||
/user
|
||||
/add
|
||||
/del
|
||||
/get
|
||||
/login
|
||||
/signup
|
||||
/edit?
|
||||
|
||||
review kriteria:
|
||||
- pena
|
||||
- 3 stupne hodnoceni
|
||||
- horkost-sladkost
|
||||
- slider
|
||||
- kyselost
|
||||
- T/F
|
||||
- packaging
|
||||
- 5 stupnu hodnoceni
|
||||
- dal bych si znovu
|
||||
- T/F
|
||||
|
@ -5,9 +5,7 @@ services:
|
||||
image: mariadb
|
||||
restart: always
|
||||
environment:
|
||||
MARIADB_ROOT_PASSWORD: '39In1bx7'
|
||||
ports:
|
||||
- 3306:3306
|
||||
MARIADB_ROOT_PASSWORD: 39In1bx7
|
||||
volumes:
|
||||
- ./db_data:/var/lib/mysql
|
||||
|
||||
|
56
frontend-plain/css/_general.css
Normal file
@ -0,0 +1,56 @@
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: OpenSans Roboto sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.f-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.f-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.f-center {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.abs-center {
|
||||
position: absolute;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.tmpsqrt {
|
||||
padding: 5rem 2.5rem;
|
||||
background: red;
|
||||
}
|
0
frontend-plain/css/_variables.css
Normal file
20
frontend-plain/css/add.css
Normal file
@ -0,0 +1,20 @@
|
||||
.form_add {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
.form_group_label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 1rem;
|
||||
}
|
||||
input {
|
||||
margin: 0.3rem 0;
|
||||
}
|
||||
input[type="file"] {
|
||||
font-size: 17px;
|
||||
}
|
15
frontend-plain/css/home.css
Normal file
@ -0,0 +1,15 @@
|
||||
.main-wrapper h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2rem;
|
||||
}
|
||||
.card {
|
||||
width: 15rem;
|
||||
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||
padding: .5rem;
|
||||
cursor: pointer;
|
||||
}
|
10
frontend-plain/css/md-add.css
Normal file
@ -0,0 +1,10 @@
|
||||
.select-box {
|
||||
padding: 4rem;
|
||||
/*border: 5px solid red;*/
|
||||
cursor: pointer;
|
||||
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||
}
|
||||
|
||||
#md-add-tree .f-row.f-center{
|
||||
gap: 2rem;
|
||||
}
|
77
frontend-plain/css/modal.css
Normal file
@ -0,0 +1,77 @@
|
||||
.modal {
|
||||
display: none; /* Hidden by default */
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 1; /* Sit on top */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%; /* Full width */
|
||||
height: 100%; /* Full height */
|
||||
overflow: auto; /* Enable scroll if needed */
|
||||
background-color: rgb(0,0,0); /* Fallback color */
|
||||
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
||||
|
||||
animation-name: fadein;
|
||||
animation-duration: 0.4s;
|
||||
}
|
||||
|
||||
/* Modal Content/Box */
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: 15% auto; /* 15% from the top and centered */
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 15px;
|
||||
width: 80%; /* Could be more or less, depending on screen size */
|
||||
|
||||
|
||||
position: relative;
|
||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
|
||||
animation-name: fadein;
|
||||
animation-duration: 0.4s;
|
||||
}
|
||||
|
||||
.md-close {
|
||||
position: relative;
|
||||
left: 95%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.md-active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.md-active-mobile {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 600px) {
|
||||
.md-active {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content h2 {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.modal-content a {
|
||||
text-decoration: none;
|
||||
padding: 1rem 0rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-content a:hover {
|
||||
background-color: #888;
|
||||
}
|
||||
|
||||
/* Add Animation */
|
||||
@keyframes fadein {
|
||||
from { opacity: 0}
|
||||
to {opacity: 1}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
from { opacity: 1}
|
||||
to {opacity: 0}
|
||||
}
|
47
frontend-plain/css/nav.css
Normal file
@ -0,0 +1,47 @@
|
||||
.nav-wrapper {
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem;
|
||||
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.nav-2 {
|
||||
gap: 1rem;
|
||||
}
|
||||
.nav-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-user img {
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 600px) {
|
||||
.nav-user-dropdown {
|
||||
position: absolute;
|
||||
right: .5rem;
|
||||
top: 4rem;
|
||||
background: white;
|
||||
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
||||
height: 5rem;
|
||||
width: 8rem;
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
gap: .5rem;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
.nav-user-dropdown {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.visible {
|
||||
visibility: visible;
|
||||
}
|
0
frontend-plain/css/show.css
Normal file
1
frontend-plain/img/icons/beer.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M320-200h280v-400h-80q-28 0-46 14t-43 41q-20 22-46.5 45.5T320-465v265Zm-80 80v-346q-52-14-86-56t-34-98q0-53 30.5-94t78.5-57q23-48 68.5-78T400-879q35 0 65.5 12t55.5 32q10-2 19-3.5t20-1.5q66 0 113 47t47 113q0 22-5.5 42T698-600h62q33 0 56.5 23.5T840-520v240q0 33-23.5 56.5T760-200h-80v80H240Zm-40-500q0 33 23.5 56.5T280-540q32 0 54.5-21t46.5-47q25-27 56.5-49.5T520-680h120q0-33-23.5-56.5T560-760q-25 0-42 6.5l-17 6.5-31-26q-11-9-28.5-17.5T400-799q-32 0-58.5 17T301-736l-14 30-32 11q-25 8-40 28.5T200-620Zm480 340h80v-240h-80v240Zm-360 80h280-280Z"/></svg>
|
After Width: | Height: | Size: 649 B |
1
frontend-plain/img/icons/close.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>
|
After Width: | Height: | Size: 203 B |
1
frontend-plain/img/icons/delete.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>
|
After Width: | Height: | Size: 300 B |
1
frontend-plain/img/icons/expand_more.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z"/></svg>
|
After Width: | Height: | Size: 159 B |
1
frontend-plain/img/icons/home.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M240-200h120v-240h240v240h120v-360L480-740 240-560v360Zm-80 80v-480l320-240 320 240v480H520v-240h-80v240H160Zm320-350Z"/></svg>
|
After Width: | Height: | Size: 224 B |
1
frontend-plain/img/icons/login.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-120v-80h280v-560H480v-80h280q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H480Zm-80-160-55-58 102-102H120v-80h327L345-622l55-58 200 200-200 200Z"/></svg>
|
After Width: | Height: | Size: 259 B |
1
frontend-plain/img/icons/logout.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h280v80H200Zm440-160-55-58 102-102H360v-80h327L585-622l55-58 200 200-200 200Z"/></svg>
|
After Width: | Height: | Size: 258 B |
1
frontend-plain/img/icons/menu.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 174 B |
1
frontend-plain/img/icons/plus.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"/></svg>
|
After Width: | Height: | Size: 163 B |
1
frontend-plain/img/icons/refresh.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z"/></svg>
|
After Width: | Height: | Size: 314 B |
1
frontend-plain/img/icons/search.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>
|
After Width: | Height: | Size: 357 B |
1
frontend-plain/img/icons/settings.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m370-80-16-128q-13-5-24.5-12T307-235l-119 50L78-375l103-78q-1-7-1-13.5v-27q0-6.5 1-13.5L78-585l110-190 119 50q11-8 23-15t24-12l16-128h220l16 128q13 5 24.5 12t22.5 15l119-50 110 190-103 78q1 7 1 13.5v27q0 6.5-2 13.5l103 78-110 190-118-50q-11 8-23 15t-24 12L590-80H370Zm70-80h79l14-106q31-8 57.5-23.5T639-327l99 41 39-68-86-65q5-14 7-29.5t2-31.5q0-16-2-31.5t-7-29.5l86-65-39-68-99 42q-22-23-48.5-38.5T533-694l-13-106h-79l-14 106q-31 8-57.5 23.5T321-633l-99-41-39 68 86 64q-5 15-7 30t-2 32q0 16 2 31t7 30l-86 65 39 68 99-42q22 23 48.5 38.5T427-266l13 106Zm42-180q58 0 99-41t41-99q0-58-41-99t-99-41q-59 0-99.5 41T342-480q0 58 40.5 99t99.5 41Zm-2-140Z"/></svg>
|
After Width: | Height: | Size: 752 B |
1
frontend-plain/img/icons/star.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m354-247 126-76 126 77-33-144 111-96-146-13-58-136-58 135-146 13 111 97-33 143ZM233-80l65-281L80-550l288-25 112-265 112 265 288 25-218 189 65 281-247-149L233-80Zm247-350Z"/></svg>
|
After Width: | Height: | Size: 276 B |
95
frontend-plain/img/icons/user.svg
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 2666.6667 2666.6667"
|
||||
height="2666.6667"
|
||||
width="2666.6667"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath28"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path26"
|
||||
d="m 16823.6,10000 c 0,-3768.6 -3055,-6823.6 -6823.6,-6823.6 -3768.59,0 -6823.64,3055 -6823.64,6823.6 0,3768.6 3055.05,6823.6 6823.64,6823.6 3768.6,0 6823.6,-3055 6823.6,-6823.6 z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,2666.6667)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><g
|
||||
transform="scale(1.22699)"
|
||||
id="g14"><path
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 16300,0 H 0 V 16300 H 16300 V 0" /></g><g
|
||||
transform="scale(1.03213)"
|
||||
id="g18"><path
|
||||
id="path20"
|
||||
style="fill:#feedf1;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 16300,9688.75 c 0,-3651.3 -2960,-6611.21 -6611.25,-6611.21 -3651.29,0 -6611.26,2959.91 -6611.26,6611.21 C 3077.49,13340 6037.46,16300 9688.75,16300 13340,16300 16300,13340 16300,9688.75" /></g><g
|
||||
id="g22"><g
|
||||
clip-path="url(#clipPath28)"
|
||||
id="g24"><path
|
||||
id="path30"
|
||||
style="fill:#c3bfb6;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 12471.2,3176.4 c -1693.4,0 -3386.74,0 -5080.12,0 -0.37,9.1 3.3,16.1 10.97,21.1 29.48,15.1 61.53,12 92.87,12 1624.15,0.2 3248.28,0.2 4872.48,0 31.3,0 63.4,3.2 92.9,-11.9 7.7,-5 11.3,-12.1 10.9,-21.2" /><path
|
||||
id="path32"
|
||||
style="fill:#c3bfb6;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 5861.99,3176.4 c 0.31,67.7 -10.59,136.1 11.17,202.6 30.86,-33.5 15.92,-75.1 19.77,-113.4 2.95,-29.3 0.49,-61.8 45.59,-57.3 435.08,2.4 870.03,0.7 1304.98,0.9 25.12,0 50.64,0.7 73.9,-11.8 7.71,-4.9 11.19,-12 10.5,-21 -488.64,0 -977.27,0 -1465.91,0" /><path
|
||||
id="path34"
|
||||
style="fill:#c3bfb6;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 14138.2,3190.6 c 0.4,-4.7 0.8,-9.5 1.1,-14.2 -539.2,0 -1078.4,0 -1617.5,0 -0.7,9.1 2.9,16 10.6,20.9 23.2,12.6 48.6,11.9 73.7,11.9 484.9,0.3 969.8,0.5 1454.7,0 10.5,0 21,-0.5 31.4,-2.2 16.8,-1.2 33.2,-4 46,-16.4" /><path
|
||||
id="path36"
|
||||
style="fill:#aaa8a7;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 7327.9,3176.4 c 0.07,3.2 0.16,6.5 0.26,9.7 1.32,2.5 2.64,4.9 3.94,7.3 15.31,9.9 31.53,9.3 48.16,4.3 5.25,-2.4 8.68,-6.5 10.56,-11.9 0.17,-3.2 0.26,-6.3 0.26,-9.4 -21.06,0 -42.12,0 -63.18,0" /><path
|
||||
id="path38"
|
||||
style="fill:#a9a7a6;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 12521.5,3185.8 c 0.2,-3.1 0.2,-6.3 0.3,-9.4 -16.9,0 -33.7,0 -50.6,0 0,3 0,6.1 0.2,9.1 1,2.5 1.9,4.9 2.8,7.4 11.8,8.2 24.5,8.3 37.7,4.3 5,-2.3 8.1,-6.1 9.6,-11.4" /><path
|
||||
id="path40"
|
||||
style="fill:#110f0d;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 14138.2,3190.6 c -12.1,-0.1 -24.2,-0.3 -36.4,-0.4 -30.7,71.2 -23.9,148 -29.1,222.3 -6.2,88 -1.8,176.8 -1.4,265.2 1,269.3 -17.5,537.7 -35.8,806.3 -32.2,474.3 -90.4,946.1 -138.2,1418.8 -9.3,92 -10,185 -12.6,277.1 -6.5,233.9 -31.2,465.9 -56.2,697.8 -28.6,265.5 -51.5,532 -98.3,795.4 -53.2,299.1 -122.7,593.8 -237.7,876.1 -102.7,252.5 -264.8,458 -490.2,611.7 -239.7,163.4 -498.9,286.6 -771.3,386.6 -238,87.3 -488.6,128.1 -727.2,211.4 -41.9,14.7 -55.5,-8.3 -70.7,-39.7 -67,-139.2 -140.5,-277 -260.4,-376.8 -269.2,-223.9 -565.4,-393.2 -930.4,-381.8 -186.3,5.8 -365.97,57.5 -539.4,124.4 -230.32,88.9 -456.26,186.2 -636.19,364.9 -96.41,95.8 -178.21,201.6 -245.25,319.2 -14.92,26.2 -22.73,54.8 -5.61,84 8.75,12.7 25.34,16.7 34.2,29.5 -9.33,-9.4 -21.7,-14.3 -32.53,-21.7 C 8663.39,9798.3 8501.73,9754 8352.96,9679.5 8016.12,9511 7668.55,9364.9 7339.83,9178.8 6946.76,8956.4 6698.33,8623.7 6552.66,8205 6459.55,7937.3 6409.77,7659.9 6365.29,7380.9 6301,6977.7 6241.61,6573.7 6169.22,6171.6 c -32.34,-179.6 -30.9,-364.5 -59.75,-545.4 -64.01,-401.3 -86.05,-807.1 -130.13,-1210.5 -36.69,-335.9 -18.64,-672.8 -24.46,-1009.3 -1.25,-72.6 0.37,-146.7 -30.48,-215.7 -52.86,-1.3 -52.29,-1.3 -52.48,45.4 -0.2,47.6 7.31,95.2 1.24,142.9 6.93,170.4 11.01,340.9 8.88,511.5 -3.38,270 19.87,538.1 51.4,806 25.57,217.3 41.14,435.8 65.46,653.3 20.33,181.9 47.59,362.9 70.41,544.5 10.49,83.5 16.39,167.5 26.63,251 25.1,204.7 68.09,406.6 98.02,610.5 37.89,258 79.37,515.5 123.1,772.6 50.55,297.3 119.16,589.2 241.61,866.4 157.75,357.1 394.31,643.3 738.9,835.9 152.37,85.1 304.41,170.2 463.8,241.9 107.3,48.2 213.91,98.3 318.93,151.3 259.86,131.1 531.25,232.2 811.2,309.5 74.06,20.4 120.66,60.8 153.91,126 40.09,78.5 55.97,162.3 60.94,249.2 7.63,133.1 -11.05,264.3 -27,395.9 -11.25,92.9 -47.19,178.3 -69.57,267.7 -32.76,130.8 -47.21,264.9 -64.57,398.3 -4.29,33 -12.98,43.8 -49.85,44.7 -88.69,2.1 -153.84,50.7 -199.59,124.7 -26.74,43.2 -41.15,91.9 -53.53,140.9 -30.86,122.4 -57.79,245.6 -70.81,371.3 -3.02,29.1 -4.42,59.1 -1,88.1 10.78,91.3 47.31,142.1 134.21,192.7 -46.72,107.7 -93.65,215.4 -140.25,323.2 -69.71,161.4 -98.2,329.8 -85.68,505.1 5.11,71.6 19.78,141.6 39.12,210.4 35.79,127.4 76.84,253.5 109.18,381.7 39.07,155 133.93,253.3 283.39,302.7 187.63,61.9 373.33,129 549.97,218.3 109.34,55.2 223.37,95.8 340.99,129.3 130.72,37.2 257.34,33.1 382.84,-18 54.5,-22.2 109.7,-42.8 163.1,-67.2 139.6,-63.6 287.2,-93.5 438.4,-110.5 64.7,-7.3 129.5,-14.5 191.7,-36 95.5,-33 169.5,-91.4 218.5,-180.4 22.3,-40.5 44.8,-81 67.6,-121.2 29.6,-52.2 68.9,-95.5 120.8,-126.4 184.4,-109.5 259.3,-277.4 265.2,-485.5 5.9,-208.2 -40.6,-404.7 -120.3,-594.9 -44.6,-106.6 -95.9,-209.9 -162.4,-305.2 111.6,-55 147.3,-155.1 153.2,-262.1 11.1,-200.6 -37.7,-388 -157.7,-552.9 -27.4,-37.8 -60.9,-69.6 -99,-96.7 -45.8,-32.6 -94.6,-44.4 -149.1,-22.7 -15.6,-7.1 -15.7,-22.9 -19.1,-36.8 -4,-16.4 -6.3,-33.3 -12,-49 -56.6,-157 -60.1,-320.8 -63.9,-484.8 -3.8,-166.3 -9.9,-332.5 -14.4,-498.7 -2.5,-90.2 21.1,-175.2 57.4,-256.5 52.1,-117 144.9,-190.5 265.8,-224.9 181.7,-51.7 361.9,-107.6 545.6,-153.5 399.7,-99.6 779.1,-252.2 1125.4,-480 279,-183.6 470.6,-434.2 582.7,-747.9 109.4,-306 184.7,-620.3 229.6,-941.7 55.9,-400.1 98.7,-801.7 129.3,-1204.6 12.6,-165.7 17.4,-331.8 31,-497.6 16.5,-201.3 40.1,-402 58.2,-603.1 16.8,-186.5 40.5,-372.4 56.1,-558.9 38.5,-459.7 57.4,-920.3 54.2,-1381.6 -0.2,-37.9 -1.2,-75.8 -1.9,-113.7" /><path
|
||||
id="path42"
|
||||
style="fill:#473e2e;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 5924.4,3190.7 c 22.18,270.9 12.68,542.3 13.77,813.6 0.72,178.6 15.61,356.2 35.53,533.6 11.7,104.1 16.65,209 28.88,313.1 12.23,104.1 16.05,209 33.1,312.6 8.49,51.6 9.78,104.6 13.1,156.6 7.09,111.5 35.1,219.5 46.5,330 9.03,87.5 25.47,174.5 30.53,262.2 10.15,176.3 35.93,349.9 69.66,523 28.42,145.9 53.78,292.5 73.21,440.2 22.66,172.3 55.72,343.3 80.96,515.3 22.22,151.5 47.55,302.3 81.67,451.6 53.08,232.1 121.83,459 235.62,669.7 87.35,161.7 190.22,312.5 326.1,438.1 102.33,94.5 218.14,170.8 337.55,241.9 204.53,121.7 419.17,223.2 636.1,320.5 82.49,37 162.42,79.7 243.27,120.3 186.42,93.7 382.11,164.1 578.83,232.1 14.1,4.8 27.92,9.1 42.92,8.6 3.9,-2.8 5.17,-5.5 3.82,-8.3 -1.34,-2.7 -2.67,-4 -4.01,-4 -21.13,-31.2 -10.75,-60.6 6.27,-88.6 46.91,-77.4 97.19,-152.3 156.67,-220.8 157.81,-181.8 354.14,-305.6 575.98,-395.7 168,-68.3 338.67,-122.8 516.47,-159.6 193.9,-40.1 380.7,-19.1 562.6,50.1 159.8,60.8 306.7,147.3 444.2,249.2 99.7,73.8 175.5,168.7 239.2,273.7 39.2,64.6 79.8,129.1 101.7,202.2 7.3,24.1 17.9,22.4 36.7,16.3 79.9,-26.1 158.5,-59.7 240.5,-74.6 199.8,-36.3 389.8,-103.8 579.5,-171 284.9,-100.9 553.4,-236.5 794,-420.7 201.5,-154.3 342.9,-355.7 434.8,-592.3 98.5,-253.5 165.2,-515.5 214.5,-782.3 35,-189.8 59.8,-380.9 77.9,-573 12.3,-131.4 33.1,-261.9 46.6,-393.2 11.8,-114.8 17.8,-230.1 28.2,-345 15.4,-171.5 18.3,-343.7 26.5,-515.6 4.7,-98 22.4,-195.5 32.8,-293.3 10.4,-98 18.6,-196.3 28.7,-294.3 10.5,-102.2 21.8,-204.2 33.4,-306.2 5.7,-50 10.9,-100.4 14.1,-150.3 8.2,-127.7 23.6,-254.8 30.6,-382.8 8.7,-157.1 16.4,-314.4 26.3,-471.5 8,-126.2 9.1,-252.1 8.9,-378.1 -0.2,-151.5 7,-302.6 13.2,-453.8 -442.9,-0.4 -885.8,-0.7 -1328.6,-1.3 -83.9,-0.2 -167.8,-2 -251.7,-3.1 l 0.4,5.4 c -28.1,53 -5.4,107.3 -2,160.4 11.7,180.8 9.4,361.3 0.5,542.2 -8,163.5 -24.4,326.2 -10.6,491.4 13.8,165.1 9.9,331.9 -2.6,498.2 -17.2,230 -2.8,460 46.7,684.4 79.9,362.9 113.9,731.7 160,1099.1 11.2,89.6 6.8,180.6 11.2,270.9 7.5,151.3 20.4,302 30.6,453.1 -51,-452.6 -66.1,-908.6 -128.7,-1360.1 -22.6,-162.9 -64.7,-321.9 -95.3,-483.2 -26.3,-138.9 -42.8,-278.3 -41.6,-420.1 1.9,-246.3 6.8,-492.8 -1.2,-738.9 -8.2,-250.7 16.3,-499.5 23.8,-749.2 4.1,-138.2 -8.6,-277.3 -25.3,-415.2 -1.5,-12.8 -7,-24.1 -16.3,-33.4 l 0.3,-5.3 c -25.1,1.2 -50.3,3.3 -75.4,3.3 -1643.3,0.2 -3286.47,0.2 -4929.69,0.1 -25.16,0 -50.33,-2.1 -75.49,-3.1 l 0.39,5.4 c -18.66,22.7 -10.02,48.3 -6.62,72.7 62.4,448.2 128.12,896.5 157.97,1347.7 21.15,319.6 70.23,635.7 92.29,954.6 14.42,208.4 -5.69,416.2 -28.55,623.4 -37.81,342.7 -86.87,683.9 -136.66,1025 53.02,-376.8 96.7,-754.6 139.31,-1132.6 35.93,-318.8 10.08,-634.4 -38.84,-949.4 -28.8,-185.4 -34.52,-372.6 -46.96,-559.4 -11.6,-174.3 -36.77,-347.3 -61.08,-520.3 -36.64,-260.5 -55.08,-523.3 -100.86,-782.6 -5.12,-29 -5.44,-59.4 -33.27,-78.5 l 0.22,-5.7 c -25.11,1 -50.22,2.8 -75.33,2.8 -419.76,0.2 -839.51,0.1 -1259.27,0.2 -23.06,0 -46.11,1.1 -69.16,1.6" /><path
|
||||
id="path44"
|
||||
style="fill:#110f0d;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 7327.94,3191.8 c 16.77,107.6 34.53,215.1 50.03,322.9 18.79,130.7 27.64,262.6 47.22,393.3 17.07,114.1 28.04,229 42.24,343.4 10.84,87.4 23.75,174.5 33.43,261.9 8.56,77.3 10.31,155.3 13.29,232.7 6.15,159.9 27.96,317.4 50.12,475.3 32.45,231.2 57.31,463.6 38.85,697.2 -11.56,146.1 -24.98,292.3 -45.24,437.8 -21.97,157.8 -35.38,316.7 -54.48,474.9 -13.56,112.3 -31.73,224.1 -45.02,336.4 -4.61,39.1 -0.73,79.1 -0.73,125.1 32.12,-30.7 27.52,-68.6 32.68,-100.7 27.01,-167.6 51.78,-335.5 75.05,-503.7 15.79,-114.2 25.5,-229.3 42.1,-343.3 21.76,-149.6 34.81,-300.2 45.43,-450.5 9,-127.5 9.53,-256 -5.24,-384.4 -10.79,-93.6 -17.38,-187.9 -29.04,-281.6 -10.88,-87.4 -23.21,-174.6 -32.59,-262.1 -7.6,-70.9 -15.62,-142.1 -16.65,-213.3 -2.15,-149.4 -19.2,-297.2 -36.1,-445.3 -13.32,-116.7 -24.31,-233.6 -41.09,-349.9 -28.15,-195 -41.26,-391.9 -72.8,-586.6 -9.7,-59.9 -19.9,-119.9 -28.19,-180.1 -21.12,-3.3 -42.22,-3.5 -63.27,0.6" /><path
|
||||
id="path46"
|
||||
style="fill:#110f0d;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 12471.1,3190.8 c 7.6,119.3 15.6,238.6 22.5,358 2,33.5 3.1,67.4 0.6,100.9 -10.9,150.8 -15,302 -26.5,452.5 -5.8,76.2 2.1,150.5 2.3,225.7 0.4,260.9 1.9,521.9 -0.7,782.9 -1.8,173.3 22.4,343 56.8,511.9 26.8,131.4 57,262.3 79.2,394.4 15.6,92.9 19.7,187.6 30.1,281.4 9.7,87.5 21.3,174.7 31.2,262.2 7.1,62.4 18.2,125.1 17.9,187.6 -0.7,115.8 9.5,231 16.4,346.2 6.2,104.3 23.5,208.2 38.9,311.8 3.2,22.1 4.8,50.7 33.9,63.5 0,-49.8 5.6,-97.2 -1,-143 -21.4,-147.8 -18.5,-297.2 -33.4,-445.3 -4,-39.7 -1.9,-79.9 -2.1,-119.9 -0.6,-111.6 -18.5,-221.3 -33.4,-331.5 -11.3,-83 -23,-166.3 -28.4,-249.8 -9.8,-149.2 -39.4,-295 -68.6,-440.9 -33.7,-168.6 -65.4,-336.9 -76.1,-509.4 -6.7,-107.4 -13.2,-214.9 -5.3,-321.1 11.5,-155.7 5.2,-311 8.9,-466.5 1.1,-46.7 -10.1,-91.8 -11.1,-137.9 -3.5,-147.2 13.7,-293.5 19.9,-440.1 7.3,-172 14,-344.5 -5.6,-516.7 -5.9,-52 -9,-104.5 -15.6,-156.5 -17,-0.1 -33.9,-0.2 -50.8,-0.4" /><path
|
||||
id="path48"
|
||||
style="fill:#fbc6a5;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 11115.2,12266.8 c -2.1,-239.9 -10.1,-479.6 -32.9,-718.5 -16,-166.6 -66.6,-324.9 -121,-482 -28.2,-81.4 -58.4,-162.2 -96.1,-239.8 -136,-280 -353,-454 -662.6,-509.6 -232.48,-41.8 -451.87,-10.8 -658.6,105.2 -67.97,38.2 -133.66,79.5 -196.56,125.7 -172.86,127.1 -278.28,294.2 -312.71,507.1 -48.05,297 -99.72,593.6 -109.31,895.1 -9.42,296.3 23.22,587.1 107.6,872.8 56.81,192.5 175.8,303.9 372.77,337.8 217.81,37.4 435.56,72.4 657.31,78.1 122.2,3.2 241.6,31.4 361.8,52.1 91.4,15.8 183.1,23.2 276.3,9.9 151.6,-21.5 256.6,-100.5 309.9,-243.8 41.8,-112.7 68.5,-229.6 82.8,-349 17.5,-146.5 24.7,-293.6 21.3,-441.1" /><path
|
||||
id="path50"
|
||||
style="fill:#1f1612;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 11146.3,12044.6 c -3.2,88.1 18.6,175.2 10.7,263.7 -11.4,127.2 -12.4,255 -22.8,382.4 -10.8,133 -39.5,260.8 -82.5,385.8 -46.4,134.9 -141.3,222.3 -279.2,257.6 -96.6,24.7 -195.6,21.7 -293.6,4.9 -121.5,-20.9 -242.5,-45.2 -364.4,-63.9 -45.3,-6.9 -92.6,-4.4 -138.72,-1.9 -116.15,6.5 -230.18,-12.7 -344.07,-28.6 -90.88,-12.7 -182.42,-24.2 -271.55,-47.9 -52.97,-14.1 -103.11,-35.6 -152.61,-58.6 -83.12,-38.7 -134.13,-109.3 -168.68,-188.6 -60.42,-138.8 -94.24,-286 -119.69,-435.2 -26.51,-155.4 -37.43,-311.7 -37.02,-469.1 0.03,-7.7 2.35,-16.1 -8.17,-26.2 -25.99,39.4 -36.67,84.8 -51.14,126.5 -61.34,176.9 -143.91,344.7 -216.82,516.6 -70.89,167.2 -103,341.3 -88.84,522.4 6.04,77.2 29.79,151.9 51.29,226.2 36.69,127 77.05,252.8 112.55,380.1 30.53,109.4 106.95,173.7 206.05,213.5 103.17,41.4 209.33,75.4 313.54,114.3 86.57,32.3 171.87,67.9 254.23,110.1 137.13,70.3 280.78,123.7 432.36,150.7 93.89,16.7 187.99,8.6 278.09,-29.6 104.3,-44.2 207.6,-91.4 315.9,-125.5 92.1,-29 187,-44 282.9,-55.4 84.8,-10.2 170.5,-18.3 249.1,-59.2 69.5,-36.2 123,-85.8 157.4,-156.3 14.7,-30.3 31.8,-59.3 46.6,-89.5 43.6,-89 123.2,-141 199.7,-196.5 106,-77.1 163,-182.5 183.2,-310.9 7.6,-47.9 11.8,-95.4 12,-143.8 1,-188 -49.1,-364 -120.8,-535.7 -50.4,-120.7 -117.4,-231.2 -185.7,-342.4 -56.6,-92 -115.9,-185.1 -150.3,-289.7 l -4.4,-4.1 -4.6,3.8" /><path
|
||||
id="path52"
|
||||
style="fill:#fbc6a5;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 9133.63,10693.3 c 167.3,-202.5 379.62,-336.7 631.53,-406.2 222.98,-61.5 443.04,-34 656.54,44.7 145.5,53.7 260.8,151.7 356.2,273.3 84,107.2 140.8,228.8 190,354.5 31.2,-3 14.8,-23.7 14.2,-38.5 -7.7,-182.9 -16.9,-365.8 -22.5,-548.8 -3.3,-111 19.2,-217.8 70.7,-317 50.6,-97.5 129.5,-164.3 230.1,-206.5 11.6,-4.8 23.6,-8.8 35.5,-13 106.7,-37.4 105.8,-36.9 53.1,-141.2 -100.6,-199.3 -245.4,-355.2 -443,-461.7 -114.8,-61.8 -227.9,-126.6 -353.6,-165.3 -185.2,-57 -368.7,-43 -554.49,1.1 -206.06,49 -402.08,124.5 -590.52,217.7 -224.32,111 -396.67,281.9 -525.15,496.6 -27.87,46.5 -27.63,48.5 20.64,76.2 149.98,86.2 217.27,220.4 235.32,387.8 15.3,141.9 -1.83,281.4 -17.6,421.5 -3.35,12.3 -11.38,27.1 13.03,24.8" /><path
|
||||
id="path54"
|
||||
style="fill:#fbc6a5;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 11474.3,12024.1 c -2.8,-118.7 -25.5,-233.2 -75.8,-341.3 -37,-79.4 -88.3,-147.5 -162.8,-196 -25.1,-16.3 -51.2,-29.7 -82.4,-24.5 -23.2,3.8 -40.2,14.3 -35.2,41.8 25,136.4 2.4,276.9 37.7,412.9 34.2,131.8 92.4,251.4 166.2,364.7 15.2,23.3 32.7,23.2 53.2,10 25.6,-16.4 42.1,-41.1 56.4,-66.8 34.6,-62.3 46,-130 42.7,-200.8" /><path
|
||||
id="path56"
|
||||
style="fill:#fbc6a5;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 8604.1,12090.9 c -1.44,36.4 3.74,71.8 14.34,106.1 10.1,32.7 27.26,61.4 55.37,82.3 36.94,27.5 46.16,26 62.85,-16.4 48.48,-123 95.87,-246.4 143.33,-369.8 7.56,-19.7 10.62,-40.3 11.45,-61.7 4.53,-115.6 19.03,-230.2 35.63,-344.6 5.31,-36.6 1.61,-41.4 -34.7,-37.4 -61.46,6.6 -111.23,35.4 -149.44,84 -17.03,21.7 -30.19,45.7 -39.09,71.6 -54.05,157.8 -82.7,320.7 -99.74,485.9" /><path
|
||||
id="path58"
|
||||
style="fill:#796c63;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 10982.1,10921.1 c -8.1,11.6 3.4,30.4 -14.2,38.5 -0.7,17.6 5.7,31.4 21.8,42.2 5.4,-29 6.1,-55.5 -7.6,-80.7" /><path
|
||||
id="path60"
|
||||
style="fill:#252623;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 8831.51,9861.4 c -0.06,4.1 0,8.2 0.19,12.3 9.81,13.3 22.74,20.6 44.97,21.9 -8.79,-24 -30.62,-24.8 -45.16,-34.2" /><path
|
||||
id="path62"
|
||||
style="fill:#857a68;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 9133.63,10693.3 c -10.93,-4.8 -8,-16.9 -13.03,-24.8 -3.43,7.2 -8.6,14.1 -9.82,21.6 -1.37,8.5 -7.88,22.3 5.61,24.4 10.57,1.6 14.73,-11.2 17.24,-21.2" /><path
|
||||
id="path64"
|
||||
style="fill:#4c5254;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 11146.3,12044.6 c 3,0.5 6,0.6 9,0.3 -1.1,-6.3 5.7,-15.5 -6.6,-17.5 -0.8,5.8 -1.6,11.5 -2.4,17.2" /><path
|
||||
id="path66"
|
||||
style="fill:#222423;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 8885.94,11991.9 c -0.13,-1.4 0.25,-3.5 -0.5,-4 -1.26,-0.9 -3.61,-1.7 -4.84,-1.1 -5.18,2.5 -4.94,5.2 0.6,6.7 1.32,0.4 3.15,-1 4.74,-1.6" /></g></g></g></g></svg>
|
After Width: | Height: | Size: 17 KiB |
BIN
frontend-plain/img/tabornici_logo.png
Normal file
After Width: | Height: | Size: 188 KiB |
171
frontend-plain/index.php
Normal file
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
require_once("./libs/Router.php");
|
||||
|
||||
// Display Errors
|
||||
ini_set('display_startup_errors', 1);
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(-1);
|
||||
|
||||
// Display var_dump
|
||||
#var_dump($_SESSION);
|
||||
|
||||
// Date Time Zone
|
||||
date_default_timezone_set('Europe/Prague');
|
||||
$API_URL = "http://localhost:6060";
|
||||
|
||||
$LOGGEDIN = !false;
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="cs">
|
||||
<head>
|
||||
<title>DeguApp</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="/img/icons/beer.svg" type="image/svg+xml">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap">
|
||||
<link rel="stylesheet" href="/css/_general.css">
|
||||
<link rel="stylesheet" href="/css/_variables.css">
|
||||
<link rel="stylesheet" href="/css/nav.css">
|
||||
<link rel="stylesheet" href="/css/home.css">
|
||||
<link rel="stylesheet" href="/css/md-add.css">
|
||||
<link rel="stylesheet" href="/css/modal.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="f-row nav-wrapper">
|
||||
<div class="f-row f-center">
|
||||
<a href="/" class="f-row f-center">
|
||||
<img src="/img/icons/beer.svg" alt="degu app home">
|
||||
<span>Degu App</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="f-row nav-2">
|
||||
<?php
|
||||
if(!$LOGGEDIN) {
|
||||
?>
|
||||
<div id="nav-login" class="nav-item">
|
||||
<p>Přihlásit se</p>
|
||||
</div>
|
||||
<div id="nav-signup" class="nav-item">
|
||||
<p>Registrace</p>
|
||||
</div>
|
||||
<?php
|
||||
} else{
|
||||
?>
|
||||
<div class="nav-item">
|
||||
<img src="/img/icons/search.svg" alt="">
|
||||
</div>
|
||||
<div class="nav-item nav-add">
|
||||
<img src="/img/icons/plus.svg" alt="add beer or review">
|
||||
</div>
|
||||
<div class="nav-item nav-user">
|
||||
<img src="/img/icons/user.svg" alt="user icon">
|
||||
<a href="#">Test Testovic</a>
|
||||
</div>
|
||||
<div class="nav-user-dropdown">
|
||||
<a href="#">Můj účet</a>
|
||||
<a href="#">Nastavení</a>
|
||||
<a href="#">Odhlásit se</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</header>
|
||||
<section class="main-wrapper">
|
||||
<!-- routing shits -->
|
||||
<?php
|
||||
$R = new Router();
|
||||
if(!$LOGGEDIN) {
|
||||
$R->route('GET', '/', 'home');
|
||||
$R->route('GET', '/login', 'login');
|
||||
$R->route('GET', '/signup', 'signup');
|
||||
}
|
||||
|
||||
if($LOGGEDIN) {
|
||||
$R->route('GET', '/', 'beer_get');
|
||||
$R->route('GET', '/beer/add', 'beer_add');
|
||||
$R->route('GET', '/beer/get/{id}', 'beer_get');
|
||||
$R->route('GET', '/review/add', 'review_add');
|
||||
|
||||
$R->route('POST', '/contact/send', 'contact');
|
||||
}
|
||||
|
||||
if(!$LOGGEDIN && $R->getUrl() == '/') {
|
||||
// show login page
|
||||
}
|
||||
|
||||
//$R = null;
|
||||
?>
|
||||
|
||||
<!-- modals -->
|
||||
<!-- add modal -->
|
||||
<?php if($LOGGEDIN) {?>
|
||||
<section class="modal" id="md-add-tree">
|
||||
<div class="modal-content">
|
||||
<span class="md-close">×</span>
|
||||
<div class="f-row f-center">
|
||||
<a class="select-box" href="/beer/add">
|
||||
<b>Add Beer</b>
|
||||
</a>
|
||||
<a class="select-box" href="/review/add">
|
||||
<b>Add Review</b>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- user actions modal -->
|
||||
<section class="modal" id="md-user-tree">
|
||||
<div class="modal-content">
|
||||
<span class="md-close">×</span>
|
||||
<div class="f-col f-center">
|
||||
<h2>Ahoj Pepo!</h2>
|
||||
<a href="/my-account">Můj účet</a>
|
||||
<a href="/settings">Nastavení</a>
|
||||
<a href="/logout">Odhlásit se</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php }?>
|
||||
|
||||
<?php if(!$LOGGEDIN) {?>
|
||||
<!-- login modal -->
|
||||
<section class="modal" id="md-login">
|
||||
<div class="modal-content">
|
||||
<span class="md-close">×</span>
|
||||
<div class="f-col f-center">
|
||||
<p>Přihlaste se</p>
|
||||
<?php
|
||||
require_once("./pages/login/login.php");
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- login modal -->
|
||||
<section class="modal" id="md-signup">
|
||||
<div class="modal-content">
|
||||
<span class="md-close">×</span>
|
||||
<div class="f-col f-center">
|
||||
<p>Zaregistrujte se</p>
|
||||
<?php
|
||||
require_once("./pages/signup/signup.php");
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php }?>
|
||||
|
||||
</section>
|
||||
<footer>
|
||||
<a href="https://git.filiprojek.cz/fr/deguapp">Source</a>
|
||||
<a href="http://filiprojek.cz/">(c) Filip Rojek, 2023</a>
|
||||
</footer>
|
||||
|
||||
<script defer src="/js/general.js"></script>
|
||||
<script defer src="/js/modal.js"></script>
|
||||
<script defer src="/js/nav.js"></script>
|
||||
<script defer src="/js/home.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
15
frontend-plain/js/general.js
Normal file
@ -0,0 +1,15 @@
|
||||
function qS(selector) {
|
||||
if(!selector) {
|
||||
console.error("No selector is defined!")
|
||||
return
|
||||
}
|
||||
return document.querySelector(selector)
|
||||
}
|
||||
|
||||
function qSA(selector) {
|
||||
if(!selector) {
|
||||
console.error("No selector is defined!")
|
||||
return
|
||||
}
|
||||
return document.querySelectorAll(selector)
|
||||
}
|
5
frontend-plain/js/home.js
Normal file
@ -0,0 +1,5 @@
|
||||
qSA(".card-beer").forEach(el => {
|
||||
el.addEventListener("click", (e) => {
|
||||
window.location.href = "/beer/" + el.querySelector("img").id
|
||||
})
|
||||
});
|
15
frontend-plain/js/modal.js
Normal file
@ -0,0 +1,15 @@
|
||||
// close on button
|
||||
const close = qSA(".md-close")
|
||||
close.forEach(one => {
|
||||
one.addEventListener("click", (el) => {
|
||||
qS(".md-active").classList.remove("md-active")
|
||||
})
|
||||
})
|
||||
|
||||
// close on backdrop
|
||||
window.onclick = function(event) {
|
||||
const active = qS(".md-active")
|
||||
if (event.target == active) {
|
||||
active.classList.remove("md-active")
|
||||
}
|
||||
}
|
25
frontend-plain/js/nav.js
Normal file
@ -0,0 +1,25 @@
|
||||
function show_modal(selector, modal_selector = null) {
|
||||
try {
|
||||
if(modal_selector === null) {
|
||||
modal_selector = selector
|
||||
}
|
||||
const btn = qS(selector)
|
||||
const md = qS(modal_selector)
|
||||
btn.addEventListener("click", (el) => {
|
||||
md.classList.add("md-active")
|
||||
})
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
show_modal(".nav-add", "#md-add-tree")
|
||||
show_modal("#nav-login", "#md-login")
|
||||
show_modal("#nav-signup", "#md-signup")
|
||||
show_modal(".nav-user", "#md-user-tree")
|
||||
|
||||
try {
|
||||
qS(".nav-user").addEventListener("click", () => {
|
||||
qS(".nav-user-dropdown").classList.toggle("visible")
|
||||
})
|
||||
} catch (err) {
|
||||
}
|
61
frontend-plain/libs/Router.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
class Router {
|
||||
public $returned = false;
|
||||
public $url = null;
|
||||
public $id = null;
|
||||
|
||||
function route($method, $url, $filename) {
|
||||
$this->url = $url;
|
||||
$methods = ['GET', 'POST'];
|
||||
if(in_array($method, $methods)) {
|
||||
if($_SERVER['REQUEST_METHOD'] == $method) {
|
||||
if(count(explode("{", $url)) > 1) {
|
||||
if(explode("}", explode("{", $url)[1])[0] == "id") {
|
||||
$tmp = explode("/", $_SERVER['REQUEST_URI'], 1);
|
||||
$cnt = count(explode("/", $_SERVER['REQUEST_URI'], 1));
|
||||
$this->id = $tmp[$cnt - 1];
|
||||
require_once("./pages/$filename/$filename.php");
|
||||
$this->returned = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if($_SERVER['REQUEST_URI'] == $url) {
|
||||
require_once("./pages/$filename/$filename.php");
|
||||
$this->returned = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function getUrl() {
|
||||
return $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
|
||||
static function getID() {
|
||||
$tmp = explode("/", $_SERVER['REQUEST_URI']);
|
||||
$cnt = count($tmp);
|
||||
$id = $tmp[$cnt -1];
|
||||
if(is_numeric($id)) {
|
||||
return $id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
if($_SERVER['REQUEST_METHOD'] == 'GET') {
|
||||
if(!$this->returned){
|
||||
$url = explode("/", $_SERVER['REQUEST_URI']);
|
||||
$url = $url[count($url)-1];
|
||||
|
||||
if (file_exists("./pages/$url/$url.php")) {
|
||||
require_once("./pages/$url/$url.php");
|
||||
} else {
|
||||
require_once("./pages/errors/404.php");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
89
frontend-plain/pages/beer_add/beer_add.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
$API_URL = "http://localhost:6060"
|
||||
?>
|
||||
<link href="/css/add.css" rel="stylesheet">
|
||||
<h1>Přidání piva</h1>
|
||||
|
||||
<section class="flex f-center">
|
||||
<form class="form_add card">
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="name">Název, značka:</label>
|
||||
<input type="text" name="name" id="name" enable>
|
||||
</div>
|
||||
<div class=form_group_label>
|
||||
<label for="degree">Stupeň:</label>
|
||||
<input type="text" name="degree" id="degree" enable>
|
||||
</div>
|
||||
<div class=form_group_label>
|
||||
<label for="percentage">Procento:</label>
|
||||
<input type="text" name="percentage" id="percentage" enable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="packaging">Obal:</label>
|
||||
<select id="packaging" name="packaging" enable>
|
||||
<option value="1">Plech</option>
|
||||
<option value="2">Sklo</option>
|
||||
<option value="3">Sud</option>
|
||||
<option value="4">Tank</option>
|
||||
<option value="5">Jiné</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class=form_group_label>
|
||||
<label for="note">Poznámka:</label>
|
||||
<input type="text" name="note" id="note" enable>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form_group">
|
||||
<div class=form_group_label>
|
||||
<label for="photo">Foto:</label>
|
||||
<input type="file" name="photo" id="photo" enable>
|
||||
<label for="upload">Upload File</label>
|
||||
n
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form_group">
|
||||
<button class="btn-send">Přidat záznam</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const btn = document.querySelector('.btn-send')
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
console.log('click')
|
||||
send()
|
||||
})
|
||||
|
||||
async function send() {
|
||||
console.log('click')
|
||||
let form = new FormData(document.querySelector("form"));
|
||||
|
||||
let body = JSON.stringify(Object.fromEntries(form))
|
||||
fetch('<?php echo $API_URL;?>/api/v1/beer/add', {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
body: body,
|
||||
})
|
||||
.then(res => {
|
||||
console.log(res)
|
||||
console.log(res.json())
|
||||
|
||||
})
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</section>
|
20
frontend-plain/pages/beer_get/beer_get.php
Normal file
@ -0,0 +1,20 @@
|
||||
<section class="card-wrapper f-center" style="">
|
||||
<?php
|
||||
if(Router::getID() == null) {
|
||||
for ($i=0; $i < 8; $i++) {
|
||||
?>
|
||||
<div class="card card-beer f-col">
|
||||
<img width="200px" id="<?= $i ?>" src="https://live.staticflickr.com/65535/49818361653_351771faae_h.jpg" alt="beer image">
|
||||
<h2>Beer Name</h2>
|
||||
<p>12 Degree</p>
|
||||
</div>
|
||||
<?php
|
||||
}} else { ?>
|
||||
<div class="card card-beer f-col">
|
||||
<img width="200px" id="<?= $i ?>" src="https://live.staticflickr.com/65535/49818361653_351771faae_h.jpg" alt="beer image">
|
||||
<h2>Beer Name</h2>
|
||||
<p>12 Degree</p>
|
||||
</div>
|
||||
<?php
|
||||
}?>
|
||||
</section>
|
0
frontend-plain/pages/errors/404.php
Normal file
3
frontend-plain/pages/home/home.php
Normal file
@ -0,0 +1,3 @@
|
||||
<h1>Welcome to DeguApp!</h1>
|
||||
<br>
|
||||
<p style="text-align: center">Please Log in</p>
|
50
frontend-plain/pages/login/login.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
$API_URL = "http://localhost:6060"
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="/css/add.css">
|
||||
|
||||
<form class="form_add">
|
||||
<label for="email">E-mail:</label>
|
||||
<input type="email" name="email" id="email">
|
||||
|
||||
<label for="password">Heslo:</label>
|
||||
<input type="password" name="password" id="password">
|
||||
|
||||
<button id="submit" class="btn-send">Přihlásit se</button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const btn = document.querySelector('.btn-send')
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
send()
|
||||
})
|
||||
|
||||
function send() {
|
||||
let form = new FormData(document.querySelector("form"));
|
||||
|
||||
let body = JSON.stringify(Object.fromEntries(form))
|
||||
|
||||
//fetch('<?php echo $API_URL;?>/api/v1/user/add', {
|
||||
// credentials: 'include',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// },
|
||||
// method: 'POST',
|
||||
// body: body,
|
||||
//})
|
||||
.then(res => {
|
||||
console.log(res)
|
||||
console.log(res.json())
|
||||
|
||||
})
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
197
frontend-plain/pages/review_add/review_add.php
Normal file
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
$API_URL = "http://localhost:6060"
|
||||
?>
|
||||
<link href="/css/add.css" rel="stylesheet">
|
||||
<h1>Přidání záznamu</h1>
|
||||
|
||||
<form class="form_add">
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="user">Uživatel:</label>
|
||||
<select id="user" name="user" enable>
|
||||
<option value="649f42f62b93542c8a465526">Dž</option>
|
||||
<option value="649f43182b93542c8a465528">Dý Ej En</option>
|
||||
<option value="649f42c32b93542c8a465524">frfr</option>
|
||||
<option value="649f43332b93542c8a46552a">Pch</option>
|
||||
<option value="649f46072b93542c8a46552f">Sš</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="beer">Beer:</label>
|
||||
<select name="beer_id" id="beer_id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="logo">Logo:</label>
|
||||
<input type="number" name="logo" id="logo" min="1" max="10" step="1" enable>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="aroma">Vůně:</label>
|
||||
<input type="number" name="aroma" id="aroma" min="1" max="10" step="1" enable>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="foam">Pěna:</label>
|
||||
<input type="number" name="foam" id="foam" min="1" max="10" step="1" enable>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="color">Barva:</label>
|
||||
<input type="number" name="color" id="color" min="1" max="10" step="1" enable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="bitterness">Hořkost:</label>
|
||||
<input type="number" name="bitterness" id="bitterness" min="1" max="10" step="1" enable>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="sweetness">Sladkost:</label>
|
||||
<input type="number" name="sweetness" id="sweetness" min="1" max="10" step="1" enable>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="note">Poznámka:</label>
|
||||
<input type="text" name="note" id="note" enable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="again">Dal bych si znovu?</label>
|
||||
<select name="again" enable>
|
||||
<option value="yes">Ano</option>
|
||||
<option value="no">Ne</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="overall_rating">Celkový dojem:</label>
|
||||
<input type="number" name="overall_rating" id="overall_rating" min="1" max="10" step="1" enable>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="final_rating">Hodnocení:</label>
|
||||
<input type="number" name="final_rating" id="final_rating" min="1" max="10" step="0.5" enable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=form_group>
|
||||
<div class=form_group_label>
|
||||
<label for="date">Datum:</label>
|
||||
<input type="date" name="date" id="date" enable>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="attendedts">S kým:</label>
|
||||
<select id="attendedts" name="attendedts" multiple size="3" enable>
|
||||
<option value="649f42f62b93542c8a465526">Dž</option>
|
||||
<option value="649f43182b93542c8a465528">Dý Ej En</option>
|
||||
<option value="649f42c32b93542c8a465524">frfr</option>
|
||||
<option value="649f43332b93542c8a46552a">Pch</option>
|
||||
<option value="649f46072b93542c8a46552f">Sš</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class=form_group_label>
|
||||
<label for="sign">Podpis:</label>
|
||||
<input type="text" name="sign" id="sign" enable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form_group">
|
||||
<div class=form_group_label>
|
||||
<label for="photo">Foto:</label>
|
||||
<input type="file" name="image" id="image" enable>
|
||||
</div>
|
||||
<div class=form_group_label>
|
||||
<label for="bebeer">BeBeer:</label>
|
||||
<input type="file" name="bebeer" id="bebeer" enable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form_group">
|
||||
<button class="btn-send">Přidat záznam</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script defer>
|
||||
async function getBeers() {
|
||||
try {
|
||||
const res = await fetch('<?php echo $API_URL;?>/api/v1/beer/get')
|
||||
const data = await res.json()
|
||||
console.log(data)
|
||||
return data
|
||||
} catch(err) {
|
||||
console.log(err, "penis")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const btn = document.querySelector('.btn-send')
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
send()
|
||||
})
|
||||
|
||||
async function send() {
|
||||
let form = new FormData(document.querySelector("form"));
|
||||
|
||||
let body = JSON.stringify(Object.fromEntries(form))
|
||||
fetch('<?php echo $API_URL;?>/api/v1/review/add', {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
body: body,
|
||||
})
|
||||
.then(res => {
|
||||
console.log(res)
|
||||
console.log(res.json())
|
||||
|
||||
})
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<script async defer>
|
||||
const packagingToLang = (id_pckg) => {
|
||||
const pckgs = {
|
||||
1: "Plech",
|
||||
2: "Sklo",
|
||||
3: "Plast"
|
||||
}
|
||||
return pckgs[id_pckg]
|
||||
}
|
||||
|
||||
(async() => {
|
||||
// get beers and fill form data
|
||||
const beerData = await getBeers()
|
||||
const beer = document.querySelector('#beer_id')
|
||||
|
||||
const beerOptions = beerData?.map((beer) => {
|
||||
return `
|
||||
<option value="${beer._id}">${beer.name} ${beer.degree} ${packagingToLang(beer.packaging)}</option>
|
||||
`
|
||||
})
|
||||
console.log(beerData)
|
||||
|
||||
beer.innerHTML = beerOptions
|
||||
})()
|
||||
</script>
|
||||
|
0
frontend-plain/pages/show/show.php
Normal file
55
frontend-plain/pages/signup/signup.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
$API_URL = "http://localhost:6060"
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="/css/add.css">
|
||||
|
||||
<form class="form_add">
|
||||
<label for="username">Uživatelské jméno:</label>
|
||||
<input type="text" name="username" id="username">
|
||||
|
||||
<label for="email">E-mail:</label>
|
||||
<input type="email" name="email" id="email">
|
||||
|
||||
<label for="password">Heslo:</label>
|
||||
<input type="password" name="password" id="password">
|
||||
|
||||
<button id="submit" class="btn-send">Registrovat se</button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
(() => {
|
||||
const btn = document.querySelector('.btn-send')
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
send()
|
||||
})
|
||||
})()
|
||||
|
||||
function send() {
|
||||
let form = new FormData(document.querySelector("form"));
|
||||
|
||||
let body = JSON.stringify(Object.fromEntries(form))
|
||||
|
||||
fetch('<?php echo $API_URL;?>/api/v1/user/add', {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
body: body,
|
||||
})
|
||||
.then(res => {
|
||||
console.log(res)
|
||||
console.log(res.json())
|
||||
|
||||
})
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
14
frontend/.eslintrc.cjs
Normal file
@ -0,0 +1,14 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
}
|
||||
}
|
30
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
8
frontend/.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
8
frontend/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"Vue.vscode-typescript-vue-plugin",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
35
frontend/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
# deguapp
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
13
frontend/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>DeguApp</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
8
frontend/jsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
3830
frontend/package-lock.json
generated
Normal file
28
frontend/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "deguapp",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.3.10",
|
||||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
"@vitejs/plugin-vue": "^4.5.1",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"prettier": "^3.0.3",
|
||||
"sass": "^1.69.5",
|
||||
"vite": "^5.0.5"
|
||||
}
|
||||
}
|
BIN
frontend/public/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |