Compare commits
84
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90f16928a1 | ||
|
|
276ef4033b | ||
|
|
a520692bc5 | ||
|
|
a327c9caeb | ||
|
|
9a8fddee3b | ||
|
|
149d668bea | ||
|
|
5d08c4c1c2 | ||
|
|
2356259823 | ||
|
|
872c921a53 | ||
|
|
10b5207f9a | ||
|
|
2ede62bcd8 | ||
|
|
1788f90cde | ||
|
|
a37f7ea8a8 | ||
|
|
18b63bed21 | ||
|
|
707c3be3ec | ||
|
|
3d52ef9d4c | ||
|
|
42944af2d3 | ||
|
|
f0f6b78cd0 | ||
|
|
7c35f17008 | ||
|
|
0208e29ae3 | ||
|
|
4d5cd104ad | ||
|
|
6702473053 | ||
|
|
52083097a2 | ||
|
|
f7ac265e3b | ||
|
|
d46841c21f | ||
|
|
c95b015094 | ||
|
|
940349af29 | ||
|
|
268824c108 | ||
|
|
550554a7a5 | ||
|
|
f5a8585845 | ||
|
|
1e67f25066 | ||
|
|
359a136dbf | ||
|
|
bbc315e270 | ||
|
|
fbb5d26c8f | ||
|
|
9d3edcf0dd | ||
|
|
57eb548d6c | ||
|
|
34d2889c1d | ||
|
|
afc782f50f | ||
|
|
ff6e688206 | ||
|
|
4b0d9b4dbc | ||
|
|
2cfcd7347b | ||
|
|
c1fe275532 | ||
|
|
de46e9bf50 | ||
|
|
76558a7eef | ||
|
|
4bf3d662ec | ||
|
|
637939e9af | ||
|
|
02891fe301 | ||
|
|
6015bce32f | ||
|
|
528b37246b | ||
|
|
0c693e1bac | ||
|
|
c77aa76645 | ||
|
|
8a0ea25029 | ||
|
|
6fb3f3f921 | ||
|
|
89c9d7f901 | ||
|
|
b215e22f53 | ||
|
|
f13ae33cb4 | ||
|
|
18a1095cf0 | ||
|
|
3e27c0110c | ||
|
|
c2ada9072f | ||
|
|
1bd1d2b279 | ||
|
|
7b1ce2ae83 | ||
|
|
de22881c28 | ||
|
|
20d370f120 | ||
|
|
85986d1844 | ||
|
|
dccf769477 | ||
|
|
d088ef7af8 | ||
|
|
fad8cdfe08 | ||
|
|
a55e6d2ab2 | ||
|
|
eb6da8aa1b | ||
|
|
19a55f57c0 | ||
|
|
b649e86a43 | ||
|
|
c53f016eec | ||
|
|
0a7cbc3434 | ||
|
|
279650db25 | ||
|
|
2d45b4af72 | ||
|
|
bd4de9d7ba | ||
|
|
10dbe5c147 | ||
|
|
435f17ee22 | ||
|
|
677dc3dc29 | ||
|
|
88e3fe4172 | ||
|
|
21dcc8bbec | ||
|
|
4778dba7ed | ||
|
|
07a02ade1f | ||
|
|
311846f92d |
No files matched your search
@@ -1,45 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
commonjs: true,
|
|
||||||
es2021: true,
|
|
||||||
},
|
|
||||||
extends: [
|
|
||||||
'airbnb-base',
|
|
||||||
],
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 12,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
indent: ['error', 4],
|
|
||||||
semi: ['warn', 'never'],
|
|
||||||
'object-curly-newline': ['warn', {
|
|
||||||
ObjectExpression: 'always',
|
|
||||||
ObjectPattern: {
|
|
||||||
multiline: true,
|
|
||||||
},
|
|
||||||
ImportDeclaration: 'never',
|
|
||||||
ExportDeclaration: {
|
|
||||||
multiline: true, minProperties: 3,
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
'consistent-return': [0],
|
|
||||||
'prefer-const': [0],
|
|
||||||
'no-unused-vars': [0],
|
|
||||||
'no-console': [0],
|
|
||||||
'global-require': [0],
|
|
||||||
'no-plusplus': [0],
|
|
||||||
'no-underscore-dangle': [0],
|
|
||||||
'import/no-dynamic-require': [0],
|
|
||||||
'no-shadow': ['warn'],
|
|
||||||
'no-restricted-syntax': ['warn'],
|
|
||||||
'max-len': ['warn'],
|
|
||||||
'linebreak-style': [0],
|
|
||||||
'prefer-destructuring': [0],
|
|
||||||
'imoprt-order': [0],
|
|
||||||
'no-param-reassign': [1],
|
|
||||||
'no-await-in-loop': [1],
|
|
||||||
'no-return-assign': [1],
|
|
||||||
'spaced-comment': [1],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
.env
|
.env
|
||||||
.idea
|
.idea
|
||||||
|
coverage/
|
||||||
|
server/log/
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
port: 8044,
|
port: process.env.PORT ?? 8044,
|
||||||
mongoAddr: process.env.MONGO_ADDR || 'localhost',
|
mongoAddr: process.env.MONGO_ADDR || 'localhost',
|
||||||
mongoPort: 27017,
|
mongoPort: 27017,
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
FROM node:18
|
FROM node:20
|
||||||
|
|
||||||
RUN mkdir -p /usr/src/app/server/
|
RUN mkdir -p /usr/src/app/server/log/
|
||||||
WORKDIR /usr/src/app/
|
WORKDIR /usr/src/app/
|
||||||
|
|
||||||
COPY ./server /usr/src/app/server
|
COPY ./server /usr/src/app/server
|
||||||
|
|||||||
Vendored
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent {
|
agent {
|
||||||
docker {
|
docker {
|
||||||
image 'node:18'
|
image 'node:20'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ pipeline {
|
|||||||
steps {
|
steps {
|
||||||
sh 'node -v'
|
sh 'node -v'
|
||||||
sh 'npm -v'
|
sh 'npm -v'
|
||||||
sh 'npm install'
|
sh 'npm ci'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,15 +22,15 @@ pipeline {
|
|||||||
|
|
||||||
stage('test') {
|
stage('test') {
|
||||||
steps {
|
steps {
|
||||||
sh 'npm run test:start'
|
sh 'npm run test'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('clean-all') {
|
stage('archiving') {
|
||||||
steps {
|
steps {
|
||||||
sh 'rm -rf .[!.]*'
|
script {
|
||||||
sh 'rm -rf ./*'
|
archiveArtifacts artifacts: 'coverage/*/**'
|
||||||
sh 'ls -a'
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,4 +3,4 @@
|
|||||||
docker stop ms-mongo
|
docker stop ms-mongo
|
||||||
docker volume remove ms_volume
|
docker volume remove ms_volume
|
||||||
docker volume create ms_volume
|
docker volume create ms_volume
|
||||||
docker run --rm -v ms_volume:/data/db --name ms-mongo -p 27017:27017 -d mongo:4.4.13
|
docker run --rm -v ms_volume:/data/db --name ms-mongo -p 27017:27017 -d mongo:8.0.3
|
||||||
+8
-4
@@ -1,19 +1,23 @@
|
|||||||
version: "3"
|
version: "3"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
ms_volume:
|
ms_volume8:
|
||||||
|
ms_logs:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mongoDb:
|
mongoDb:
|
||||||
image: mongo:4.4.13
|
image: mongo:8.0.3
|
||||||
volumes:
|
volumes:
|
||||||
- ms_volume:/data/db
|
- ms_volume8:/data/db
|
||||||
restart: always
|
restart: always
|
||||||
# ports:
|
# ports:
|
||||||
# - 27017:27017
|
# - 27017:27017
|
||||||
multy-stubs:
|
multy-stubs:
|
||||||
build: .
|
# build: .
|
||||||
|
image: bro.js/ms/bh:$TAG
|
||||||
restart: always
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ms_logs:/usr/src/app/server/log
|
||||||
ports:
|
ports:
|
||||||
- 8044:8044
|
- 8044:8044
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import globals from "globals";
|
||||||
|
import pluginJs from "@eslint/js";
|
||||||
|
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{ ignores: ['server/routers/old/*'] },
|
||||||
|
{ files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } },
|
||||||
|
{ languageOptions: { globals: globals.node } },
|
||||||
|
pluginJs.configs.recommended,
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
semi: ['warn', 'never'],
|
||||||
|
'no-unused-vars': [0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
/**
|
||||||
|
* For a detailed explanation regarding each configuration property, visit:
|
||||||
|
* https://jestjs.io/docs/configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {import('jest').Config} */
|
||||||
|
const config = {
|
||||||
|
// All imported modules in your tests should be mocked automatically
|
||||||
|
// automock: false,
|
||||||
|
|
||||||
|
// Stop running tests after `n` failures
|
||||||
|
// bail: 0,
|
||||||
|
|
||||||
|
// The directory where Jest should store its cached dependency information
|
||||||
|
// cacheDirectory: "C:\\Users\\alex\\AppData\\Local\\Temp\\jest",
|
||||||
|
|
||||||
|
// Automatically clear mock calls, instances, contexts and results before every test
|
||||||
|
clearMocks: true,
|
||||||
|
|
||||||
|
// Indicates whether the coverage information should be collected while executing the test
|
||||||
|
collectCoverage: true,
|
||||||
|
|
||||||
|
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||||
|
collectCoverageFrom: [
|
||||||
|
"<rootDir>/server/routers/**/*.js"
|
||||||
|
],
|
||||||
|
|
||||||
|
// The directory where Jest should output its coverage files
|
||||||
|
coverageDirectory: "coverage",
|
||||||
|
|
||||||
|
// An array of regexp pattern strings used to skip coverage collection
|
||||||
|
coveragePathIgnorePatterns: [
|
||||||
|
"\\\\node_modules\\\\",
|
||||||
|
"<rootDir>/server/routers/old"
|
||||||
|
],
|
||||||
|
|
||||||
|
// Indicates which provider should be used to instrument code for coverage
|
||||||
|
coverageProvider: "v8",
|
||||||
|
|
||||||
|
// A list of reporter names that Jest uses when writing coverage reports
|
||||||
|
// coverageReporters: [
|
||||||
|
// "json",
|
||||||
|
// "text",
|
||||||
|
// "lcov",
|
||||||
|
// "clover"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An object that configures minimum threshold enforcement for coverage results
|
||||||
|
// coverageThreshold: undefined,
|
||||||
|
|
||||||
|
// A path to a custom dependency extractor
|
||||||
|
// dependencyExtractor: undefined,
|
||||||
|
|
||||||
|
// Make calling deprecated APIs throw helpful error messages
|
||||||
|
// errorOnDeprecated: false,
|
||||||
|
|
||||||
|
// The default configuration for fake timers
|
||||||
|
// fakeTimers: {
|
||||||
|
// "enableGlobally": false
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Force coverage collection from ignored files using an array of glob patterns
|
||||||
|
// forceCoverageMatch: [],
|
||||||
|
|
||||||
|
// A path to a module which exports an async function that is triggered once before all test suites
|
||||||
|
// globalSetup: undefined,
|
||||||
|
|
||||||
|
// A path to a module which exports an async function that is triggered once after all test suites
|
||||||
|
// globalTeardown: undefined,
|
||||||
|
|
||||||
|
// A set of global variables that need to be available in all test environments
|
||||||
|
// globals: {},
|
||||||
|
|
||||||
|
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
||||||
|
// maxWorkers: "50%",
|
||||||
|
|
||||||
|
// An array of directory names to be searched recursively up from the requiring module's location
|
||||||
|
// moduleDirectories: [
|
||||||
|
// "node_modules"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An array of file extensions your modules use
|
||||||
|
// moduleFileExtensions: [
|
||||||
|
// "js",
|
||||||
|
// "mjs",
|
||||||
|
// "cjs",
|
||||||
|
// "jsx",
|
||||||
|
// "ts",
|
||||||
|
// "tsx",
|
||||||
|
// "json",
|
||||||
|
// "node"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
||||||
|
// moduleNameMapper: {},
|
||||||
|
|
||||||
|
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||||
|
// modulePathIgnorePatterns: [],
|
||||||
|
|
||||||
|
// Activates notifications for test results
|
||||||
|
// notify: false,
|
||||||
|
|
||||||
|
// An enum that specifies notification mode. Requires { notify: true }
|
||||||
|
// notifyMode: "failure-change",
|
||||||
|
|
||||||
|
// A preset that is used as a base for Jest's configuration
|
||||||
|
// preset: undefined,
|
||||||
|
|
||||||
|
// Run tests from one or more projects
|
||||||
|
// projects: undefined,
|
||||||
|
|
||||||
|
// Use this configuration option to add custom reporters to Jest
|
||||||
|
// reporters: undefined,
|
||||||
|
|
||||||
|
// Automatically reset mock state before every test
|
||||||
|
// resetMocks: false,
|
||||||
|
|
||||||
|
// Reset the module registry before running each individual test
|
||||||
|
// resetModules: false,
|
||||||
|
|
||||||
|
// A path to a custom resolver
|
||||||
|
// resolver: undefined,
|
||||||
|
|
||||||
|
// Automatically restore mock state and implementation before every test
|
||||||
|
// restoreMocks: false,
|
||||||
|
|
||||||
|
// The root directory that Jest should scan for tests and modules within
|
||||||
|
// rootDir: undefined,
|
||||||
|
|
||||||
|
// A list of paths to directories that Jest should use to search for files in
|
||||||
|
// roots: [
|
||||||
|
// "<rootDir>"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// Allows you to use a custom runner instead of Jest's default test runner
|
||||||
|
// runner: "jest-runner",
|
||||||
|
|
||||||
|
// The paths to modules that run some code to configure or set up the testing environment before each test
|
||||||
|
// setupFiles: [],
|
||||||
|
|
||||||
|
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||||
|
// setupFilesAfterEnv: [],
|
||||||
|
|
||||||
|
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||||
|
// slowTestThreshold: 5,
|
||||||
|
|
||||||
|
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
||||||
|
// snapshotSerializers: [],
|
||||||
|
|
||||||
|
// The test environment that will be used for testing
|
||||||
|
// testEnvironment: "jest-environment-node",
|
||||||
|
|
||||||
|
// Options that will be passed to the testEnvironment
|
||||||
|
// testEnvironmentOptions: {},
|
||||||
|
|
||||||
|
// Adds a location field to test results
|
||||||
|
// testLocationInResults: false,
|
||||||
|
|
||||||
|
// The glob patterns Jest uses to detect test files
|
||||||
|
// testMatch: [
|
||||||
|
// "**/__tests__/**/*.[jt]s?(x)",
|
||||||
|
// "**/?(*.)+(spec|test).[tj]s?(x)"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||||
|
// testPathIgnorePatterns: [
|
||||||
|
// "\\\\node_modules\\\\"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// The regexp pattern or array of patterns that Jest uses to detect test files
|
||||||
|
// testRegex: [],
|
||||||
|
|
||||||
|
// This option allows the use of a custom results processor
|
||||||
|
// testResultsProcessor: undefined,
|
||||||
|
|
||||||
|
// This option allows use of a custom test runner
|
||||||
|
// testRunner: "jest-circus/runner",
|
||||||
|
|
||||||
|
// A map from regular expressions to paths to transformers
|
||||||
|
// transform: undefined,
|
||||||
|
|
||||||
|
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||||
|
// transformIgnorePatterns: [
|
||||||
|
// "\\\\node_modules\\\\",
|
||||||
|
// "\\.pnp\\.[^\\\\]+$"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||||
|
// unmockedModulePathPatterns: undefined,
|
||||||
|
|
||||||
|
// Indicates whether each individual test should be reported during the run
|
||||||
|
verbose: true,
|
||||||
|
|
||||||
|
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
||||||
|
// watchPathIgnorePatterns: [],
|
||||||
|
|
||||||
|
// Whether to use watchman for file crawling
|
||||||
|
// watchman: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
||||||
Generated
+5104
-2314
File diff suppressed because it is too large.
Load diff
+30
-27
@@ -4,16 +4,15 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npx nodemon ./server",
|
"start": "cross-env PORT=8033 npx nodemon ./server",
|
||||||
"up:prod": "cross-env NODE_ENV=\"production\" node ./server",
|
"up:prod": "cross-env NODE_ENV=\"production\" node ./server",
|
||||||
"deploy:d:stop": "docker-compose down",
|
"deploy:d:stop": "docker compose down",
|
||||||
"deploy:d:build": "docker-compose build",
|
"deploy:d:build": "docker compose build",
|
||||||
"deploy:d:up": "docker-compose up -d",
|
"deploy:d:up": "docker compose up -d",
|
||||||
"redeploy": "npm run deploy:d:stop && npm run deploy:d:build && npm run deploy:d:up",
|
"redeploy": "npm run deploy:d:stop && npm run deploy:d:build && npm run deploy:d:up",
|
||||||
"eslint": "npx eslint ./server",
|
"eslint": "npx eslint ./server",
|
||||||
"eslint:fix": "npx eslint ./server --fix",
|
"eslint:fix": "npx eslint ./server --fix",
|
||||||
"test": "echo \"test complete\"",
|
"test": "jest"
|
||||||
"test:start": "start-server-and-test up:prod 8044 test"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -24,30 +23,34 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://bitbucket.org/online-mentor/multi-stub#readme",
|
"homepage": "https://bitbucket.org/online-mentor/multi-stub#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^5.1.0",
|
"axios": "^1.7.9",
|
||||||
"body-parser": "^1.19.0",
|
"bcrypt": "^5.1.1",
|
||||||
"cookie-parser": "^1.4.5",
|
"body-parser": "^1.20.3",
|
||||||
"cors": "^2.8.5",
|
"cookie-parser": "^1.4.7",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.2.0",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.4.7",
|
||||||
"express": "^4.18.2",
|
"express": "5.0.1",
|
||||||
"express-jwt": "^8.4.1",
|
"express-jwt": "^8.5.1",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.18.1",
|
||||||
"jsdom": "^22.1.0",
|
"jsdom": "^25.0.1",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"mongodb": "^3.6.8",
|
"mongodb": "^6.12.0",
|
||||||
"mysql": "^2.18.1",
|
"mongoose": "^8.9.2",
|
||||||
|
"morgan": "^1.10.0",
|
||||||
"pbkdf2-password": "^1.2.1",
|
"pbkdf2-password": "^1.2.1",
|
||||||
"socket.io": "^4.7.1",
|
"rotating-file-stream": "^3.2.5",
|
||||||
"start-server-and-test": "^1.13.1",
|
"socket.io": "^4.8.1",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^11.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.17.1",
|
"@eslint/js": "^9.17.0",
|
||||||
"eslint": "8.46.0",
|
"@types/node": "22.10.2",
|
||||||
"eslint-config-airbnb-base": "15.0.0",
|
"eslint": "^9.17.0",
|
||||||
"eslint-plugin-import": "2.28.0",
|
"globals": "^15.14.0",
|
||||||
"nodemon": "3.0.1"
|
"jest": "^29.7.0",
|
||||||
|
"mockingoose": "^2.16.2",
|
||||||
|
"nodemon": "3.1.9",
|
||||||
|
"supertest": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`todo list app get list 1`] = `
|
||||||
|
{
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"_id": "670f69b5796ce7a9069da2f7",
|
||||||
|
"created": "2024-10-16T07:22:29.042Z",
|
||||||
|
"id": "670f69b5796ce7a9069da2f7",
|
||||||
|
"items": [],
|
||||||
|
"title": "qqq",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"success": true,
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const { describe, it, expect } = require('@jest/globals')
|
||||||
|
const request = require('supertest')
|
||||||
|
const express = require('express')
|
||||||
|
const mockingoose = require('mockingoose')
|
||||||
|
const { ListModel } = require('../data/model/todo/list')
|
||||||
|
|
||||||
|
const todo = require('../routers/todo/routes')
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
app.use(todo)
|
||||||
|
|
||||||
|
const listExample = {
|
||||||
|
"title": "qqq",
|
||||||
|
"items": [],
|
||||||
|
"_id": "670f69b5796ce7a9069da2f7",
|
||||||
|
"created": "2024-10-16T07:22:29.042Z",
|
||||||
|
"id": "670f69b5796ce7a9069da2f7"
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('todo list app', () => {
|
||||||
|
it('get list', (done) => {
|
||||||
|
mockingoose(ListModel)
|
||||||
|
.toReturn([listExample], 'find')
|
||||||
|
.toReturn(listExample, 'create')
|
||||||
|
|
||||||
|
request(app)
|
||||||
|
.get('/list')
|
||||||
|
.expect(200)
|
||||||
|
.then((response) => {
|
||||||
|
expect(response.body).toMatchSnapshot()
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
exports.TODO_LIST_MODEL_NAME = 'TODO_LIST'
|
||||||
|
exports.TODO_ITEM_MODEL_NAME = 'TODO_ITEM'
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
const { Schema, model } = require('mongoose')
|
||||||
|
|
||||||
|
const { TODO_ITEM_MODEL_NAME } = require('../../const')
|
||||||
|
|
||||||
|
const schema = new Schema({
|
||||||
|
title: String,
|
||||||
|
done: { type: Boolean, default: false },
|
||||||
|
closed: Date,
|
||||||
|
created: {
|
||||||
|
type: Date, default: () => new Date().toISOString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.set('toJSON', {
|
||||||
|
virtuals: true,
|
||||||
|
versionKey: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.virtual('id').get(function () {
|
||||||
|
return this._id.toHexString()
|
||||||
|
})
|
||||||
|
|
||||||
|
exports.ItemModel = model(TODO_ITEM_MODEL_NAME, schema)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
const { Schema, model } = require('mongoose')
|
||||||
|
|
||||||
|
const { TODO_LIST_MODEL_NAME, TODO_ITEM_MODEL_NAME } = require('../../const')
|
||||||
|
|
||||||
|
const schema = new Schema({
|
||||||
|
title: String,
|
||||||
|
created: {
|
||||||
|
type: Date, default: () => new Date().toISOString(),
|
||||||
|
},
|
||||||
|
items: [{ type: Schema.Types.ObjectId, ref: TODO_ITEM_MODEL_NAME }],
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.set('toJSON', {
|
||||||
|
virtuals: true,
|
||||||
|
versionKey: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.virtual('id').get(function () {
|
||||||
|
return this._id.toHexString()
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.method('addItem', async function (itemObjectId) {
|
||||||
|
this.items.push(itemObjectId)
|
||||||
|
await this.save()
|
||||||
|
})
|
||||||
|
|
||||||
|
exports.ListModel = model(TODO_LIST_MODEL_NAME, schema)
|
||||||
@@ -6,6 +6,7 @@ module.exports = (err, req, res, next) => {
|
|||||||
success: false, error: 'Токен авторизации не найден',
|
success: false, error: 'Токен авторизации не найден',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
success: false, error: err.message || 'Что-то пошло не так',
|
success: false, error: err.message || 'Что-то пошло не так',
|
||||||
})
|
})
|
||||||
|
|||||||
+73
-51
@@ -1,73 +1,95 @@
|
|||||||
const express = require('express')
|
const express = require("express")
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require("body-parser")
|
||||||
const cookieParser = require('cookie-parser')
|
const cookieParser = require("cookie-parser")
|
||||||
const session = require('express-session')
|
const session = require("express-session")
|
||||||
|
const morgan = require("morgan")
|
||||||
|
const path = require("path")
|
||||||
|
const rfs = require("rotating-file-stream")
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
const cors = require('cors')
|
require("dotenv").config()
|
||||||
require('dotenv').config()
|
exports.app = app
|
||||||
|
|
||||||
const config = require('../.serverrc')
|
const accessLogStream = rfs.createStream("access.log", {
|
||||||
const { setIo } = require('./io')
|
size: "10M",
|
||||||
|
interval: "1d",
|
||||||
|
compress: "gzip",
|
||||||
|
path: path.join(__dirname, "log"),
|
||||||
|
})
|
||||||
|
|
||||||
|
const errorLogStream = rfs.createStream("error.log", {
|
||||||
|
size: "10M",
|
||||||
|
interval: "1d",
|
||||||
|
compress: "gzip",
|
||||||
|
path: path.join(__dirname, "log"),
|
||||||
|
})
|
||||||
|
|
||||||
|
const config = require("../.serverrc")
|
||||||
|
const { setIo } = require("./io")
|
||||||
|
|
||||||
app.use(cookieParser())
|
app.use(cookieParser())
|
||||||
app.options('*', cors())
|
app.use(
|
||||||
app.use(cors())
|
morgan("combined", {
|
||||||
|
stream: accessLogStream,
|
||||||
|
skip: function (req, res) {
|
||||||
|
return res.statusCode >= 400
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// log all requests to access.log
|
||||||
|
app.use(
|
||||||
|
morgan("combined", {
|
||||||
|
stream: errorLogStream,
|
||||||
|
skip: function (req, res) {
|
||||||
|
console.log('statusCode', res.statusCode, res.statusCode <= 400)
|
||||||
|
return res.statusCode < 400
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const server = setIo(app)
|
const server = setIo(app)
|
||||||
|
|
||||||
const sess = {
|
const sess = {
|
||||||
secret: 'super-secret-key',
|
secret: "super-secret-key",
|
||||||
resave: true,
|
resave: true,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
cookie: {
|
cookie: {},
|
||||||
},
|
|
||||||
}
|
}
|
||||||
if (app.get('env') === 'production') {
|
if (app.get("env") === "production") {
|
||||||
app.set('trust proxy', 1)
|
app.set("trust proxy", 1)
|
||||||
sess.cookie.secure = true
|
sess.cookie.secure = true
|
||||||
}
|
}
|
||||||
app.use(session(sess))
|
app.use(session(sess))
|
||||||
|
|
||||||
app.use(bodyParser.json({
|
app.use(
|
||||||
limit: '50mb',
|
bodyParser.json({
|
||||||
}))
|
limit: "50mb",
|
||||||
app.use(bodyParser.urlencoded({
|
})
|
||||||
limit: '50mb',
|
)
|
||||||
|
app.use(
|
||||||
|
bodyParser.urlencoded({
|
||||||
|
limit: "50mb",
|
||||||
extended: true,
|
extended: true,
|
||||||
}))
|
})
|
||||||
app.use(require('./root'))
|
)
|
||||||
|
app.use(require("./root"))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Добавляйте сюда свои routers.
|
* Добавляйте сюда свои routers.
|
||||||
*/
|
*/
|
||||||
app.use('/lobsters', require('./routers/lobsters'))
|
app.use("/kfu-m-24-1", require("./routers/kfu-m-24-1"))
|
||||||
app.use('/example', require('./routers/example'))
|
app.use("/epja-2024-1", require("./routers/epja-2024-1"))
|
||||||
// app.use('/coder', require('./routers/coder'))
|
app.use("/todo", require("./routers/todo/routes"))
|
||||||
//app.use('/stc-21-03', require('./routers/stc-21-03'))
|
app.use("/dogsitters-finder", require("./routers/dogsitters-finder"))
|
||||||
//app.use('/stc-21', require('./routers/stc'))
|
app.use("/kazan-explore", require("./routers/kazan-explore"))
|
||||||
//app.use('/stc-22-24', require('./routers/stc-22-24'))
|
app.use("/edateam", require("./routers/edateam-legacy"))
|
||||||
// app.use('/bushou-api', require('./routers/bushou'))
|
app.use("/dry-wash", require("./routers/dry-wash"))
|
||||||
|
app.use("/freetracker", require("./routers/freetracker"))
|
||||||
|
app.use("/dhs-testing", require("./routers/dhs-testing"))
|
||||||
|
|
||||||
// app.use('/uryndyklar-api', require('./routers/uryndyklar'))
|
app.use(require("./error"))
|
||||||
// app.use('/neptunium', require('./routers/neptunium'))
|
|
||||||
// app.use('/music-learn', require('./routers/music-learn'))
|
|
||||||
// app.use('/publicium', require('./routers/publicium'))
|
|
||||||
// app.use('/task-boss', require('./routers/task-boss'))
|
|
||||||
// app.use('/car-wash', require('./routers/car-wash'))
|
|
||||||
app.use('/zoom-bar', require('./routers/zoom-bar'))
|
|
||||||
app.use('/r-and-m', require('./routers/r-and-m'))
|
|
||||||
app.use('/my', require('./routers/my'))
|
|
||||||
app.use('/edateam', require('./routers/edateam'))
|
|
||||||
app.use('/webstar-project', require('./routers/webstar-project'))
|
|
||||||
app.use('/dogsitters-finder', require('./routers/dogsitters-finder'))
|
|
||||||
app.use('/dhs-testing', require('./routers/dhs-testing'))
|
|
||||||
//app.use('/basket', require('./routers/basket'))
|
|
||||||
//app.use('/easy-project', require('./routers/easy-project'))
|
|
||||||
//app.use('/sugarbun', require('./routers/sugarbun'))
|
|
||||||
app.use('/epja-2023-2', require('./routers/epja-2023-2'))
|
|
||||||
require('./routers/hub-video')
|
|
||||||
app.use('/school-stage', require('./routers/school-stage'))
|
|
||||||
|
|
||||||
app.use(require('./error'))
|
server.listen(config.port, () =>
|
||||||
|
console.log(`Listening on http://localhost:${config.port}`)
|
||||||
server.listen(config.port, () => console.log(`Listening on http://localhost:${config.port}`))
|
)
|
||||||
File renamed without changes.
+17
-2
@@ -1,17 +1,32 @@
|
|||||||
const router = require('express').Router()
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const router = require('express').Router()
|
||||||
|
const mongoose = require('mongoose')
|
||||||
|
|
||||||
const pkg = require('../package.json')
|
const pkg = require('../package.json')
|
||||||
|
|
||||||
|
require('./utils/mongoose')
|
||||||
const folderPath = path.resolve(__dirname, './routers')
|
const folderPath = path.resolve(__dirname, './routers')
|
||||||
const folders = fs.readdirSync(folderPath)
|
const folders = fs.readdirSync(folderPath)
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
router.get('/', async (req, res) => {
|
||||||
|
// throw new Error('check error message')
|
||||||
res.send(`
|
res.send(`
|
||||||
<h1>multy stub is working v${pkg.version}</h1>
|
<h1>multy stub is working v${pkg.version}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
${folders.map((f) => `<li>${f}</li>`).join('')}
|
${folders.map((f) => `<li>${f}</li>`).join('')}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h2>models</h2>
|
||||||
|
<ul>${
|
||||||
|
(await Promise.all(
|
||||||
|
(await mongoose.modelNames()).map(async (name) => {
|
||||||
|
const count = await mongoose.model(name).countDocuments()
|
||||||
|
return `<li>${name} - ${count}</li>`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)).map(t => t).join(' ')
|
||||||
|
}</ul>
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,35 @@
|
|||||||
const { response } = require('express');
|
|
||||||
|
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
|
|
||||||
router.get("/users", (request, response) => {
|
router.get("/users", (request, response) => {
|
||||||
response.send(require("./json/users.json"))
|
response.send(require("./json/users/users.json"))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post("/auth", (request, response) => {
|
||||||
|
const {phoneNumber, password} = request.body;
|
||||||
|
console.log(phoneNumber, password);
|
||||||
|
if (phoneNumber === '89999999999') {
|
||||||
|
response.send(require("./json/auth/dogsitter.success.json"))
|
||||||
|
}
|
||||||
|
else if (phoneNumber === '89555555555') {
|
||||||
|
response.status(400).send(require("./json/auth/error.json"))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
response.send(require("./json/auth/owner.success.json"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post("/register", (request, response) => {
|
||||||
|
const {firstName, secondName, phoneNumber, password, role} = request.body;
|
||||||
|
console.log(phoneNumber, password, role);
|
||||||
|
if (phoneNumber === '89283244141' || phoneNumber === '89872855893') {
|
||||||
|
response.status(400).send(require("./json/register/error.json"))
|
||||||
|
}
|
||||||
|
else if (role === 'dogsitter') {
|
||||||
|
response.send(require("./json/register/dogsitter.success.json"))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
response.send(require("./json/register/owner.success.json"))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 1,
|
||||||
|
"phoneNumber": 89283244141,
|
||||||
|
"firstName": "Вася",
|
||||||
|
"secondName": "Пупкин",
|
||||||
|
"role": "dogsitter",
|
||||||
|
"location": "Россия, республика Татарстан, Казань, улица Пушкина, 12",
|
||||||
|
"price": 1500,
|
||||||
|
"aboutMe": "Я люблю собак"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"error": "Пользователь не найден"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 3,
|
||||||
|
"phoneNumber": 89872855893,
|
||||||
|
"firstName": "Гадий",
|
||||||
|
"secondName": "Петрович",
|
||||||
|
"role": "owner"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 5,
|
||||||
|
"phoneNumber": 89555555555,
|
||||||
|
"firstName": "Масяня",
|
||||||
|
"secondName": "Карлова",
|
||||||
|
"role": "dogsitter",
|
||||||
|
"location": "Россия, республика Татарстан, Казань, улица Пушкина, 12",
|
||||||
|
"price": 100,
|
||||||
|
"aboutMe": "Все на свете - собаки"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"error": "Пользователь с таким номером телефона уже существует"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 6,
|
||||||
|
"phoneNumber": 89888888888,
|
||||||
|
"firstName": "Генадий",
|
||||||
|
"secondName": "Паровозов",
|
||||||
|
"role": "owner"
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-5
@@ -2,7 +2,6 @@
|
|||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"phone_number": 89283244141,
|
"phone_number": 89283244141,
|
||||||
"password": "1234",
|
|
||||||
"first_name": "Вася",
|
"first_name": "Вася",
|
||||||
"second_name": "Пупкин",
|
"second_name": "Пупкин",
|
||||||
"role": "dogsitter",
|
"role": "dogsitter",
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"phone_number": 89272844541,
|
"phone_number": 89272844541,
|
||||||
"password": "1234",
|
|
||||||
"first_name": "Ваня",
|
"first_name": "Ваня",
|
||||||
"second_name": "Пуськин",
|
"second_name": "Пуськин",
|
||||||
"role": "dogsitter",
|
"role": "dogsitter",
|
||||||
@@ -24,7 +22,6 @@
|
|||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"phone_number": 89872855893,
|
"phone_number": 89872855893,
|
||||||
"password": "12345",
|
|
||||||
"first_name": "Гадий",
|
"first_name": "Гадий",
|
||||||
"second_name": "Петрович",
|
"second_name": "Петрович",
|
||||||
"role": "owner"
|
"role": "owner"
|
||||||
@@ -32,10 +29,9 @@
|
|||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"phone_number": 89872844591,
|
"phone_number": 89872844591,
|
||||||
"password": "12345",
|
|
||||||
"first_name": "Галкин",
|
"first_name": "Галкин",
|
||||||
"second_name": "Максим",
|
"second_name": "Максим",
|
||||||
"role": ["owner", "dogsitter"],
|
"role": "dogsitter",
|
||||||
"location": "Россия, республика Татарстан, Казань, проспект Ямашева, 83",
|
"location": "Россия, республика Татарстан, Казань, проспект Ямашева, 83",
|
||||||
"price": 1000000,
|
"price": 1000000,
|
||||||
"about_me": "Миллион алых роз"
|
"about_me": "Миллион алых роз"
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
const router = require('express').Router()
|
||||||
|
const {MasterModel} = require('./model/master')
|
||||||
|
const mongoose = require("mongoose")
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/masters', async (req, res,next) => {
|
||||||
|
try {
|
||||||
|
const master = await MasterModel.find({})
|
||||||
|
res.status(200).send({success: true, body: master})
|
||||||
|
} catch (error) {
|
||||||
|
next(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.delete('/masters/:id', async (req, res,next) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
if (!mongoose.Types.ObjectId.isValid(id)){
|
||||||
|
throw new Error('ID is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const master = await MasterModel.findByIdAndDelete(id, {
|
||||||
|
new: true,
|
||||||
|
});
|
||||||
|
if (!master) {
|
||||||
|
throw new Error('master not found')
|
||||||
|
}
|
||||||
|
res.status(200).send({success: true, body: master})
|
||||||
|
} catch (error) {
|
||||||
|
next(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/masters', async (req, res,next) => {
|
||||||
|
|
||||||
|
const {name, phone} = req.body
|
||||||
|
|
||||||
|
if (!name || !phone ){
|
||||||
|
throw new Error('Enter name and phone')
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const master = await MasterModel.create({name, phone})
|
||||||
|
res.status(200).send({success: true, body: master})
|
||||||
|
} catch (error) {
|
||||||
|
next(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.patch('/masters/:id', async (req, res, next) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
if (!mongoose.Types.ObjectId.isValid(id)) {
|
||||||
|
throw new Error('ID is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, phone } = req.body;
|
||||||
|
|
||||||
|
if (!name && !phone) {
|
||||||
|
throw new Error('Enter name and phone')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const updateData = {};
|
||||||
|
if (name) updateData.name = name;
|
||||||
|
if (phone) updateData.phone = phone;
|
||||||
|
|
||||||
|
const master = await MasterModel.findByIdAndUpdate(
|
||||||
|
id,
|
||||||
|
updateData,
|
||||||
|
{ new: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!master) {
|
||||||
|
throw new Error('master not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send({ success: true, body: master });
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const router = require('express').Router()
|
||||||
|
|
||||||
|
router.post('/orders', (req, res) => {
|
||||||
|
res
|
||||||
|
.status(200)
|
||||||
|
.send(require(`./json/arm-orders/success.json`))
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const router = require('express').Router()
|
||||||
|
const armMasterRouter = require('./arm-master')
|
||||||
|
const armOrdersRouter = require('./arm-orders')
|
||||||
|
|
||||||
|
|
||||||
|
router.use('/arm', armMasterRouter)
|
||||||
|
router.use('/arm', armOrdersRouter)
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"id": "masters1",
|
||||||
|
"name": "Иван Иванов",
|
||||||
|
"schedule": [ {
|
||||||
|
"id": "order1",
|
||||||
|
"startWashTime": "2024-11-24T10:30:00.000Z",
|
||||||
|
"endWashTime": "2024-11-24T16:30:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "order2",
|
||||||
|
"startWashTime": "2024-11-24T11:30:00.000Z",
|
||||||
|
"endWashTime": "2024-11-24T17:30:00.000Z"
|
||||||
|
}],
|
||||||
|
"phone": "+7 900 123 45 67"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "masters12",
|
||||||
|
"name": "Иван Иванов",
|
||||||
|
"schedule": [ {
|
||||||
|
"id": "order1",
|
||||||
|
"startWashTime": "2024-11-24T10:30:00.000Z",
|
||||||
|
"endWashTime": "2024-11-24T16:30:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "order2",
|
||||||
|
"startWashTime": "2024-11-24T11:30:00.000Z",
|
||||||
|
"endWashTime": "2024-11-24T17:30:00.000Z"
|
||||||
|
}],
|
||||||
|
"phone": "+7 900 123 45 67"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"id": "order1",
|
||||||
|
"carNumber": "A123BC",
|
||||||
|
"startWashTime": "2024-11-24T10:30:00.000Z",
|
||||||
|
"endWashTime": "2024-11-24T16:30:00.000Z",
|
||||||
|
"orderDate": "2024-11-24T08:41:46.366Z",
|
||||||
|
"status": "progress",
|
||||||
|
"phone": "79001234563",
|
||||||
|
"location": "Казань, ул. Баумана, 1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "order2",
|
||||||
|
"carNumber": "A245BC",
|
||||||
|
"startWashTime": "2024-11-24T11:30:00.000Z",
|
||||||
|
"endWashTime": "2024-11-24T17:30:00.000Z",
|
||||||
|
"orderDate": "2024-11-24T07:40:46.366Z",
|
||||||
|
"status": "progress",
|
||||||
|
"phone": "79001234567",
|
||||||
|
"location": "Казань, ул. Баумана, 43"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const { Schema, model } = require('mongoose')
|
||||||
|
|
||||||
|
const schema = new Schema({
|
||||||
|
name: {type: String, required: true},
|
||||||
|
phone: {type: String, required: true,unique: true,},
|
||||||
|
created: {
|
||||||
|
type: Date, default: () => new Date().toISOString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.set('toJSON', {
|
||||||
|
virtuals: true,
|
||||||
|
versionKey: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.virtual('id').get(function () {
|
||||||
|
return this._id.toHexString()
|
||||||
|
})
|
||||||
|
|
||||||
|
exports.MasterModel = model('dry-wash-master', schema)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
const { Schema, model } = require('mongoose')
|
||||||
|
|
||||||
|
const schema = new Schema({
|
||||||
|
startWashTime: {type: String, required: true},
|
||||||
|
endWashTime: {type: String, required: true},
|
||||||
|
orderDate: {type: String, required: true},
|
||||||
|
location: {type: String, required: true},
|
||||||
|
phone: {type: String, required: true},
|
||||||
|
status: {type: String, required: true},
|
||||||
|
carNumber: {type: String, required: true},
|
||||||
|
created: {
|
||||||
|
type: Date, default: () => new Date().toISOString(),
|
||||||
|
},
|
||||||
|
updated: {
|
||||||
|
type: Date, default: () => new Date().toISOString(),
|
||||||
|
},
|
||||||
|
master: {type: Schema.Types.ObjectId, ref: 'dry-wash-master'},
|
||||||
|
notes: String,
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.set('toJSON', {
|
||||||
|
virtuals: true,
|
||||||
|
versionKey: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
schema.virtual('id').get(function () {
|
||||||
|
return this._id.toHexString()
|
||||||
|
})
|
||||||
|
|
||||||
|
exports.OrderModel = model('dry-wash-order', schema)
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"_postman_id": "e91fbcf7-3c7b-420d-a49e-4dbb6199c14a",
|
||||||
|
"name": "dry-wash",
|
||||||
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||||
|
"_exporter_id": "27705820"
|
||||||
|
},
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "arm",
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "create master",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"name\":\"Anto234\",\n \"phone\": \"89172420577\"\n}",
|
||||||
|
"options": {
|
||||||
|
"raw": {
|
||||||
|
"language": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{host}}/arm/master",
|
||||||
|
"host": [
|
||||||
|
"{{host}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"arm",
|
||||||
|
"master"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get masters",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{host}}/arm/master-list",
|
||||||
|
"host": [
|
||||||
|
"{{host}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"arm",
|
||||||
|
"master-list"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "delete master",
|
||||||
|
"request": {
|
||||||
|
"method": "DELETE",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "{{host}}/arm/masters/{{id}}",
|
||||||
|
"host": [
|
||||||
|
"{{host}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"arm",
|
||||||
|
"masters",
|
||||||
|
"{{id}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "update master",
|
||||||
|
"request": {
|
||||||
|
"method": "PATCH",
|
||||||
|
"header": [],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"name\":\"Anto234\",\n \"phone\": \"89172420577\"\n}",
|
||||||
|
"options": {
|
||||||
|
"raw": {
|
||||||
|
"language": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{host}}/arm/masters/{{id}}",
|
||||||
|
"host": [
|
||||||
|
"{{host}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"arm",
|
||||||
|
"masters",
|
||||||
|
"{{id}}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
const router = require('express').Router();
|
||||||
|
|
||||||
|
router.get('/recipe-data', (request, response) => {
|
||||||
|
response.send(require('./json/recipe-data/success.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/userpage-data', (req, res)=>{
|
||||||
|
res.send(require('./json/userpage-data/success.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/homepage-data', (req, res)=>{
|
||||||
|
res.send(require('./json/homepage-data/success.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
{
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"src": "pancakes_meat",
|
||||||
|
"alt": "Фотография блинчиков с мясом, сыром и луком",
|
||||||
|
"href": "?=dish01",
|
||||||
|
"name": "Блинчики с мясом, сыром и лучком",
|
||||||
|
"category": [
|
||||||
|
"Ужины"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "cheesecakes",
|
||||||
|
"alt": "Фотография сырников из творога",
|
||||||
|
"href": "?=dish02",
|
||||||
|
"name": "Сырники из творога",
|
||||||
|
"category": [
|
||||||
|
"Завтраки"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "borsch",
|
||||||
|
"alt": "Фотография борща",
|
||||||
|
"href": "?=dish03",
|
||||||
|
"name": "Борщ",
|
||||||
|
"category": [
|
||||||
|
"Супы"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "vareniki",
|
||||||
|
"alt": "Фотография вареников",
|
||||||
|
"href": "?=dish04",
|
||||||
|
"name": "Ленивые вареники",
|
||||||
|
"category": [
|
||||||
|
"Ужины"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "rice_porridge",
|
||||||
|
"alt": "Фотография рисовой каши",
|
||||||
|
"href": "?=dish05",
|
||||||
|
"name": "Рисовая каша",
|
||||||
|
"category": [
|
||||||
|
"Завтраки"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "cutlets",
|
||||||
|
"alt": "Фотография котлет по-киевски",
|
||||||
|
"href": "?=dish06",
|
||||||
|
"name": "Котлеты по-киевски",
|
||||||
|
"category": [
|
||||||
|
"Обеды"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "draniki",
|
||||||
|
"alt": "Фотография драников",
|
||||||
|
"href": "?=dish07",
|
||||||
|
"name": "Драники",
|
||||||
|
"category": [
|
||||||
|
"Обеды"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "meringue",
|
||||||
|
"alt": "Фотография безе",
|
||||||
|
"href": "?=dish08",
|
||||||
|
"name": "Безе",
|
||||||
|
"category": [
|
||||||
|
"Выпечка и десерты"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "goulash",
|
||||||
|
"alt": "Фотография гуляша",
|
||||||
|
"href": "?=dish09",
|
||||||
|
"name": "Гуляш",
|
||||||
|
"category": [
|
||||||
|
"Мясо"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "pancakes_cherries",
|
||||||
|
"alt": "Фотография блинчиков с вишней и творожным сыром",
|
||||||
|
"href": "?=dish10",
|
||||||
|
"name": "Блинчики с вишней и творожным сыром",
|
||||||
|
"category": [
|
||||||
|
"Завтраки"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "canned_soup",
|
||||||
|
"alt": "Фотография супа из рыбных консервов",
|
||||||
|
"href": "?=dish11",
|
||||||
|
"name": "Суп из рыбных консервов",
|
||||||
|
"category": [
|
||||||
|
"Супы"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "salad",
|
||||||
|
"alt": "Фотография салата",
|
||||||
|
"href": "?=dish12",
|
||||||
|
"name": "Салат \"Весенний\"",
|
||||||
|
"category": [
|
||||||
|
"Салаты"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,147 @@
|
|||||||
|
const adminRouter = require('express').Router()
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const { TOKEN } = require('../const')
|
||||||
|
require('dotenv').config()
|
||||||
|
|
||||||
|
const dataFilePath = path.join(__dirname, '../data.json')
|
||||||
|
let data = require('../data.json')
|
||||||
|
|
||||||
|
const verifyToken = (req, res, next) => {
|
||||||
|
const token = req.headers['authorization']
|
||||||
|
if (token === TOKEN) {
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
res.status(403).send({ 'status': 'Failed', 'data': 'Invalid token' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveData = (data) => {
|
||||||
|
fs.writeFileSync(dataFilePath, JSON.stringify(data, null, 2), 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
adminRouter.post('/edit/nickname', verifyToken, (req, res) => {
|
||||||
|
const { name, colored } = req.body
|
||||||
|
if (!name || !colored) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Nickname is required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
data.nickname = { name, colored }
|
||||||
|
saveData(data)
|
||||||
|
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': 'Nickname updated successfully' })
|
||||||
|
})
|
||||||
|
|
||||||
|
adminRouter.post('/edit/tech-stack', verifyToken, (req, res) => {
|
||||||
|
const { techStack } = req.body
|
||||||
|
if (!techStack || !Array.isArray(techStack)) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Valid tech stack is required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
data.techStack = techStack
|
||||||
|
saveData(data)
|
||||||
|
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': 'Tech stack updated successfully' })
|
||||||
|
})
|
||||||
|
|
||||||
|
adminRouter.post('/edit/city', verifyToken, (req, res) => {
|
||||||
|
const { city } = req.body
|
||||||
|
if (!city) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'City is required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValid = typeof city === 'object' && 'name' in city && 'href' in city
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'City must contain href and name' })
|
||||||
|
}
|
||||||
|
|
||||||
|
data.city = city
|
||||||
|
saveData(data)
|
||||||
|
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': 'City updated successfully' })
|
||||||
|
})
|
||||||
|
|
||||||
|
adminRouter.post('/edit/github-repo', verifyToken, (req, res) => {
|
||||||
|
const { github } = req.body
|
||||||
|
if (!github) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Github is required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValid = typeof github === 'object' && 'author' in github && 'repo' in github
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Github must contain author and repo' })
|
||||||
|
}
|
||||||
|
|
||||||
|
data.githubRepo = github
|
||||||
|
saveData(data)
|
||||||
|
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': 'Github updated successfully' })
|
||||||
|
})
|
||||||
|
|
||||||
|
adminRouter.post('/edit/nav-links', verifyToken, (req, res) => {
|
||||||
|
const { navLinks } = req.body
|
||||||
|
if (!navLinks || !Array.isArray(navLinks)) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Valid navLinks are required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValid = navLinks.every(link =>
|
||||||
|
link && typeof link === 'object' && 'href' in link && 'title' in link
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Each navLink must contain href and title' })
|
||||||
|
}
|
||||||
|
|
||||||
|
data.navLinks = navLinks
|
||||||
|
saveData(data)
|
||||||
|
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': 'Navigation links updated successfully' })
|
||||||
|
})
|
||||||
|
|
||||||
|
adminRouter.post('/edit/links', verifyToken, (req, res) => {
|
||||||
|
const { links } = req.body
|
||||||
|
if (!links || !Array.isArray(links)) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Valid links are required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValid = links.every(link =>
|
||||||
|
link && typeof link === 'object' && 'href' in link && 'title' in link
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Each link must contain href and title' })
|
||||||
|
}
|
||||||
|
|
||||||
|
data.links = links
|
||||||
|
saveData(data)
|
||||||
|
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': 'Links updated successfully' })
|
||||||
|
})
|
||||||
|
|
||||||
|
adminRouter.post('/edit/projects', verifyToken, (req, res) => {
|
||||||
|
const { projects } = req.body
|
||||||
|
if (!projects) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'Projects are required' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectFields = ['id', 'title', 'description', 'link', 'techStack', 'image']
|
||||||
|
|
||||||
|
const isValidProject = (project) => {
|
||||||
|
return projectFields.every(field => field && field in project)
|
||||||
|
}
|
||||||
|
|
||||||
|
const allProjectsValid = projects.every(project => isValidProject(project))
|
||||||
|
|
||||||
|
if (!allProjectsValid) {
|
||||||
|
return res.status(400).send({ 'status': 'Failed', 'data': 'All projects must contain ' + projectFields.join(", ") })
|
||||||
|
}
|
||||||
|
|
||||||
|
data.projects = projects
|
||||||
|
saveData(data)
|
||||||
|
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': 'Projects updated successfully' })
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = adminRouter
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
const authRouter = require('express').Router()
|
||||||
|
const { TOKEN } = require('../const')
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = authRouter
|
||||||
|
|
||||||
|
authRouter.post('/login', (req, res) => {
|
||||||
|
const { email, password } = req.body
|
||||||
|
console.log(`Login with email=${email} and password=${password}`)
|
||||||
|
|
||||||
|
if (email === 'admin@admin.admin' && password === 'admin') {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': `${TOKEN}` })
|
||||||
|
} else {
|
||||||
|
res.status(401).send({ 'status': 'Failed!', 'data': 'Invalid email or password' })
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
const TOKEN = "ASDFGHJKLLKJHGFDSDFGHJKJHGF"
|
||||||
|
|
||||||
|
module.exports = { TOKEN }
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
{
|
||||||
|
"nickname": {
|
||||||
|
"name": "supercool",
|
||||||
|
"colored": "nickname"
|
||||||
|
},
|
||||||
|
"techStack": [
|
||||||
|
"React",
|
||||||
|
"Next.js",
|
||||||
|
"Svelte",
|
||||||
|
"SvelteKit",
|
||||||
|
"HTML",
|
||||||
|
"CSS",
|
||||||
|
"JavaScript",
|
||||||
|
"TypeScript",
|
||||||
|
"TailwindCSS",
|
||||||
|
"Styled-Components",
|
||||||
|
"Framer-Motion",
|
||||||
|
"shadcn-ui",
|
||||||
|
"Ant-Design",
|
||||||
|
"ESLint",
|
||||||
|
"Prettier",
|
||||||
|
"husky",
|
||||||
|
"lint-staged",
|
||||||
|
"Redux",
|
||||||
|
"RTK Query",
|
||||||
|
"Tanstack Query",
|
||||||
|
"Python",
|
||||||
|
"FastApi",
|
||||||
|
"Flask",
|
||||||
|
"SQLite",
|
||||||
|
"PostgreSQL",
|
||||||
|
"MongoDB",
|
||||||
|
"SQLAlchemy",
|
||||||
|
"Alembic",
|
||||||
|
"PyPy",
|
||||||
|
"poetry",
|
||||||
|
"pylint",
|
||||||
|
"GitHub Actions",
|
||||||
|
"GitLab CI/CD",
|
||||||
|
"Docker",
|
||||||
|
"Git"
|
||||||
|
],
|
||||||
|
"githubRepo": {
|
||||||
|
"author": "MishaBlin",
|
||||||
|
"repo": "EPJA_portfolio_app"
|
||||||
|
},
|
||||||
|
"city": {
|
||||||
|
"name": "Innopolis",
|
||||||
|
"href": "https://ru.wikipedia.org/wiki/Иннополис"
|
||||||
|
},
|
||||||
|
"navLinks": [
|
||||||
|
{
|
||||||
|
"href": "#about",
|
||||||
|
"title": "About"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "#projects",
|
||||||
|
"title": "Projects"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "mailto:svyatoslavsvyatkin@yandex.ru",
|
||||||
|
"title": "Mail"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://t.me/dmhd6219",
|
||||||
|
"title": "Telegram"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://github.com/dmhd6219",
|
||||||
|
"title": "GitHub"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://last.fm/user/dmhd",
|
||||||
|
"title": "LastFm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://pay.cloudtips.ru/p/02da9349",
|
||||||
|
"title": "Buy me a coffee"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"projects": [
|
||||||
|
{
|
||||||
|
"title": "Elasticsearch",
|
||||||
|
"description": "Elasticsearch is a distributed search and analytics engine, scalable data store and vector database optimized for speed and relevance on production-scale workloads.",
|
||||||
|
"link": "https://github.com/elastic/elasticsearch",
|
||||||
|
"techStack": [
|
||||||
|
"Java",
|
||||||
|
"Groovy"
|
||||||
|
],
|
||||||
|
"image": "https://datascientest.com/en/files/2023/04/Elasticsearch.jpg",
|
||||||
|
"id": "elasticsearch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "React-native",
|
||||||
|
"description": "React Native brings React's declarative UI framework to iOS and Android. With React Native, you use native UI controls and have full access to the native platform.",
|
||||||
|
"link": "https://github.com/facebook/react-native",
|
||||||
|
"techStack": [
|
||||||
|
"C++",
|
||||||
|
"Javascript",
|
||||||
|
"Kotlin"
|
||||||
|
],
|
||||||
|
"image": "https://www.simplilearn.com/ice9/free_resources_article_thumb/React_Native_Tutorial.jpg",
|
||||||
|
"id": "react-native"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Zarr",
|
||||||
|
"description": "Zarr is a Python package providing an implementation of compressed, chunked, N-dimensional arrays, designed for use in parallel computing. See the documentation for more information.",
|
||||||
|
"link": "https://github.com/zarr-developers/zarr-python",
|
||||||
|
"techStack": [
|
||||||
|
"Python"
|
||||||
|
],
|
||||||
|
"image": "https://raw.githubusercontent.com/zarr-developers/community/main/logos/logo2.png",
|
||||||
|
"id": "zarr"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
const authRouter = require('./auth')
|
||||||
|
const adminRouter = require('./admin')
|
||||||
|
const rootRouter = require('./root')
|
||||||
|
|
||||||
|
const router = require('express').Router()
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
|
|
||||||
|
router.use(`/auth`, authRouter)
|
||||||
|
router.use(`/admin`, adminRouter)
|
||||||
|
router.use(`/`, rootRouter)
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
const rootRouter = require('express').Router()
|
||||||
|
const data = require('../data.json')
|
||||||
|
|
||||||
|
rootRouter.get('/get/nickname', (req, res) => {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': data.nickname })
|
||||||
|
})
|
||||||
|
|
||||||
|
rootRouter.get('/get/tech-stack', (req, res) => {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': data.techStack })
|
||||||
|
})
|
||||||
|
|
||||||
|
rootRouter.get('/get/github-repo', (req, res) => {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': data.githubRepo })
|
||||||
|
})
|
||||||
|
|
||||||
|
rootRouter.get('/get/city', (req, res) => {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': data.city })
|
||||||
|
})
|
||||||
|
|
||||||
|
rootRouter.get('/get/nav-links', (req, res) => {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': data.navLinks })
|
||||||
|
})
|
||||||
|
|
||||||
|
rootRouter.get('/get/links', (req, res) => {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': data.links })
|
||||||
|
})
|
||||||
|
|
||||||
|
rootRouter.get('/get/projects', (req, res) => {
|
||||||
|
res.status(200).send({ 'status': 'OK', 'data': data.projects })
|
||||||
|
})
|
||||||
|
|
||||||
|
rootRouter.get('/get/projects/:id', (req, res) => {
|
||||||
|
const { id } = req.params
|
||||||
|
const project = data.projects.find(p => p.id === id)
|
||||||
|
|
||||||
|
if (project) {
|
||||||
|
res.status(200).send({ status: 'OK', data: project })
|
||||||
|
} else {
|
||||||
|
res.status(404).send({ status: 'NOT_FOUND', message: 'Project not found' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = rootRouter
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const plantsRouter = require('./plants/getPlants')
|
||||||
|
const calendarRouter = require('./plants_calendar/index')
|
||||||
|
|
||||||
|
const router = require('express').Router()
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
|
|
||||||
|
router.use('/plants',plantsRouter)
|
||||||
|
router.use('/plants_calendar',calendarRouter)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
const CONFIG = {
|
||||||
|
CLIENT_ID: 'kD2JXj1faSCYAWdT4B069wQAx89CZAkXmzTinRvH',
|
||||||
|
CLIENT_SECRET: 'bJq7Uiwua52tHiLP80N60hALNtQX2wcE4Mj6yNA9OzG2iZbgHuqyeAs6WSWX6MNJdfv0Nqzb7OHta8qPZr4zxWBLTauleaMfraln3xFEvbXLDpi1Lcrwe7DxfgsQQ1E4',
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CONFIG
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
const express = require ('express')
|
||||||
|
const axios = require ('axios')
|
||||||
|
const plantsRouter = express.Router ()
|
||||||
|
const CONFIG = require ('./config')
|
||||||
|
|
||||||
|
|
||||||
|
async function getAccessToken () {
|
||||||
|
const formData = new FormData ()
|
||||||
|
formData.append ('grant_type', 'client_credentials')
|
||||||
|
formData.append ('client_id', CONFIG.CLIENT_ID)
|
||||||
|
formData.append ('client_secret', CONFIG.CLIENT_SECRET)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post (
|
||||||
|
'https://open.plantbook.io/api/v1/token/',
|
||||||
|
formData,
|
||||||
|
{
|
||||||
|
headers: {'Content-Type': 'multipart/form-data'},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (response.data && response.data.access_token) {
|
||||||
|
console.log ('Access token retrieved:', response.data.access_token)
|
||||||
|
return response.data.access_token
|
||||||
|
} else {
|
||||||
|
console.error ('Error: access_token not found in response')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error (
|
||||||
|
'Error fetching access token:',
|
||||||
|
error.response ? error.response.data : error.message
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchPlantData (plantId) {
|
||||||
|
const accessToken = await getAccessToken ()
|
||||||
|
if (!accessToken) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await axios.get (
|
||||||
|
`https://open.plantbook.io/api/v1/plant/detail/${encodeURIComponent (plantId)}/`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return response.data
|
||||||
|
} catch (error) {
|
||||||
|
console.error (
|
||||||
|
'Error fetching plant data:',
|
||||||
|
error.response ? error.response.data : error.message
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plantsRouter.get ('/list', async (req, res) => {
|
||||||
|
const accessToken = await getAccessToken ()
|
||||||
|
if (!accessToken) {
|
||||||
|
res.status (500).send ({message: 'Error obtaining access token'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const alias = req.query.alias || 'monstera'
|
||||||
|
const response = await axios.get (
|
||||||
|
'https://open.plantbook.io/api/v1/plant/search',
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
alias: alias,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const plantsList = response.data.results
|
||||||
|
|
||||||
|
const plants = await Promise.all (
|
||||||
|
plantsList.map (async plant => {
|
||||||
|
const plantDetails = await fetchPlantData (plant.pid)
|
||||||
|
return {
|
||||||
|
id: plant.pid,
|
||||||
|
alias: plant.alias,
|
||||||
|
display_name: plant.display_name,
|
||||||
|
image_url: plantDetails ? plantDetails.image_url : null,
|
||||||
|
max_light: plantDetails ? plantDetails.max_light : null,
|
||||||
|
min_light: plantDetails ? plantDetails.min_light : null,
|
||||||
|
max_temp: plantDetails ? plantDetails.max_temp : null,
|
||||||
|
min_temp: plantDetails ? plantDetails.min_temp : null,
|
||||||
|
max_env_humid: plantDetails ? plantDetails.max_env_humid : null,
|
||||||
|
min_env_humid: plantDetails ? plantDetails.min_env_humid : null,
|
||||||
|
max_soil_moist: plantDetails ? plantDetails.max_soil_moist : null,
|
||||||
|
min_soil_moist: plantDetails ? plantDetails.min_soil_moist : null,
|
||||||
|
max_soil_ec: plantDetails ? plantDetails.max_soil_ec : null,
|
||||||
|
min_soil_ec: plantDetails ? plantDetails.min_soil_ec : null,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
res.send ({results: plants})
|
||||||
|
} catch (error) {
|
||||||
|
console.error (
|
||||||
|
'Error fetching plant list:',
|
||||||
|
error.response ? error.response.data : error.message
|
||||||
|
)
|
||||||
|
res.status (500).send ({message: 'Error fetching plant list'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
plantsRouter.get ('/:id', async (req, res) => {
|
||||||
|
const plantId = req.params.id
|
||||||
|
const plantData = await fetchPlantData (plantId)
|
||||||
|
|
||||||
|
if (plantData) {
|
||||||
|
const detailedPlantData = {
|
||||||
|
id: plantData.pid,
|
||||||
|
display_name: plantData.display_name,
|
||||||
|
alias: plantData.alias,
|
||||||
|
max_light: plantData.max_light,
|
||||||
|
min_light: plantData.min_light,
|
||||||
|
max_temperature: plantData.max_temp,
|
||||||
|
min_temperature: plantData.min_temp,
|
||||||
|
max_humidity: plantData.max_env_humid,
|
||||||
|
min_humidity: plantData.min_env_humid,
|
||||||
|
max_soil_moisture: plantData.max_soil_moist,
|
||||||
|
min_soil_moisture: plantData.min_soil_moist,
|
||||||
|
max_soil_ec: plantData.max_soil_ec,
|
||||||
|
min_soil_ec: plantData.min_soil_ec,
|
||||||
|
image_url: plantData.image_url,
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send (detailedPlantData)
|
||||||
|
} else {
|
||||||
|
res.status (404).send ({message: 'Plant not found'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = plantsRouter
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
const express = require('express')
|
||||||
|
|
||||||
|
const plantsRouter = express.Router()
|
||||||
|
|
||||||
|
const plants = [
|
||||||
|
{
|
||||||
|
name: "Rose",
|
||||||
|
image: "https://ervanarium.com.br/wp-content/uploads/2019/03/cactus-3142589_1920.jpg",
|
||||||
|
frequency: 3,
|
||||||
|
startDate: "2024-10-09",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sunflower",
|
||||||
|
image: "https://avatars.mds.yandex.net/i?id=31da587c9aabc83ad3615023f91d7284781be06c-10701700-images-thumbs&n=13",
|
||||||
|
frequency: 3,
|
||||||
|
startDate: "2024-10-05",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
const calculateWateringDates = (startDate, frequency) => {
|
||||||
|
const dates = []
|
||||||
|
const start = new Date(startDate)
|
||||||
|
|
||||||
|
for (let i = 0; i < 30; i += frequency) {
|
||||||
|
const nextWateringDate = new Date(start)
|
||||||
|
nextWateringDate.setDate(start.getDate() + i)
|
||||||
|
dates.push(nextWateringDate.toISOString().split('T')[0])
|
||||||
|
}
|
||||||
|
return dates
|
||||||
|
}
|
||||||
|
|
||||||
|
const plantsWithDates = plants.map(plant => ({
|
||||||
|
...plant,
|
||||||
|
wateringDates: calculateWateringDates(plant.startDate, plant.frequency),
|
||||||
|
}))
|
||||||
|
|
||||||
|
plantsRouter.get('/api/plants', (req, res) => {
|
||||||
|
res.json(plantsWithDates)
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = plantsRouter
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
const authRouter = require('express').Router()
|
||||||
|
|
||||||
|
// For creating tokens
|
||||||
|
const jwt = require('jsonwebtoken')
|
||||||
|
|
||||||
|
const { TOKEN_KEY } = require('../key')
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = authRouter
|
||||||
|
|
||||||
|
const { addUserToDB, getUserFromDB } = require('../db')
|
||||||
|
|
||||||
|
|
||||||
|
// Get a user by its id
|
||||||
|
authRouter.get('/:id', (req, res) => {
|
||||||
|
const user = getUserFromDB(req.params.id)
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
res.status(200).send({user})
|
||||||
|
} else {
|
||||||
|
res.status(404).send({message: 'User was not found'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// For login (authorization)
|
||||||
|
authRouter.post('/login', (req, res) => {
|
||||||
|
const { name, password } = req.body
|
||||||
|
|
||||||
|
const user = getUserFromDB(name)
|
||||||
|
|
||||||
|
// Invalid identification
|
||||||
|
if (!user) {
|
||||||
|
res.status(401).send({message: 'Invalid credentials (id)'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid authentication
|
||||||
|
if (!password || password !== user.password) {
|
||||||
|
res.status(401).send({message: 'Invalid credentials (password)'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, authorization
|
||||||
|
const token = jwt.sign({id: name}, TOKEN_KEY, {
|
||||||
|
expiresIn: '1h'
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).send({token})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
authRouter.post('/reg', (req, res) => {
|
||||||
|
const { name, password, nickname } = req.body
|
||||||
|
|
||||||
|
const user = getUserFromDB(name)
|
||||||
|
|
||||||
|
// Invalid identification
|
||||||
|
if (user) {
|
||||||
|
res.status(409).send({message: 'Such id already exists'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name || !password || !nickname) {
|
||||||
|
res.status(401).send({message: 'Empty or invalid fields'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to 'DB'
|
||||||
|
const newUser = {id: name, password: password, nickname: nickname}
|
||||||
|
addUserToDB(newUser)
|
||||||
|
|
||||||
|
res.status(200).send({user: newUser})
|
||||||
|
})
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"nickname": "Alice Johnson",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "alice"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Bob Smith",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "bobsm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Charlie Brown",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "charl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "David Clark",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "david"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Eve Adams",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "evead"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Frank Wright",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "frank"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Grace Lee",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "grace"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Hannah Scott",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "hanna"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Ian Davis",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "ianda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nickname": "Jill Thompson",
|
||||||
|
"password": "1234",
|
||||||
|
"id": "jillt"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
const changeRouter = require('express').Router()
|
||||||
|
|
||||||
|
module.exports = changeRouter
|
||||||
|
|
||||||
|
const { getUserFromDB, deleteUserFromDB, addUserToDB } = require('../db')
|
||||||
|
|
||||||
|
|
||||||
|
changeRouter.post('/nickname', (req, res) => {
|
||||||
|
const { id, newNickname } = req.body
|
||||||
|
|
||||||
|
const user = getUserFromDB(id)
|
||||||
|
|
||||||
|
// Invalid identification
|
||||||
|
if (!user) {
|
||||||
|
res.status(401).send({message: 'Invalid credentials (id)'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedUser = {
|
||||||
|
"nickname": newNickname,
|
||||||
|
"password": user.password,
|
||||||
|
"id": user.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the old one
|
||||||
|
deleteUserFromDB(id)
|
||||||
|
|
||||||
|
// Insert updated
|
||||||
|
addUserToDB(updatedUser)
|
||||||
|
|
||||||
|
res.status(200).send({})
|
||||||
|
})
|
||||||
|
|
||||||
|
changeRouter.post('/password', (req, res) => {
|
||||||
|
const { id, newPassword } = req.body
|
||||||
|
|
||||||
|
const user = getUserFromDB(id)
|
||||||
|
|
||||||
|
// Invalid identification
|
||||||
|
if (!user) {
|
||||||
|
res.status(401).send({message: 'Invalid credentials (id)'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the old one
|
||||||
|
deleteUserFromDB(id)
|
||||||
|
|
||||||
|
// Insert updated
|
||||||
|
const updatedUser = {
|
||||||
|
"nickname": user.nickname,
|
||||||
|
"password": newPassword,
|
||||||
|
"id": user.id
|
||||||
|
}
|
||||||
|
addUserToDB(updatedUser)
|
||||||
|
|
||||||
|
res.status(200).send({})
|
||||||
|
})
|
||||||
|
|
||||||
|
changeRouter.delete('/:id', (req, res) => {
|
||||||
|
const { id } = req.params
|
||||||
|
|
||||||
|
deleteUserFromDB(id)
|
||||||
|
})
|
||||||
|
|
||||||
@@ -0,0 +1,662 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "bobsm",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Hello Bob!",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "bobsm",
|
||||||
|
"timestamp": "09.10.2024 07:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Hey Alice, how are you?",
|
||||||
|
"senderId": "bobsm",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 07:05:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I'm good, thanks for asking.",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "bobsm",
|
||||||
|
"timestamp": "09.10.2024 07:10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Glad to hear!",
|
||||||
|
"senderId": "bobsm",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 07:15:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "charl",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "How's the project going?",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 07:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "It's coming along, almost done!",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 07:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "That's great to hear!",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 07:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Thanks for checking in.",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 07:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "david",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Did you get the files?",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 07:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, I did. Thank you!",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 07:45:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "You're welcome.",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 07:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Let me know if you need anything else.",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 07:55:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "frank",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Can you review this document for me?",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 08:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Sure, I'll take a look.",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 08:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Thanks, much appreciated!",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 08:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "No problem.",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 08:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "grace",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Hey Grace, let's meet up for coffee!",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 08:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Sounds good, when are you free?",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 08:45:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "How about tomorrow afternoon?",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 08:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Works for me!",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 08:55:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "hanna",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Hannah, do you have a moment?",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 09:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Sure, what's up?",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 09:05:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Just wanted to check on the report.",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 09:10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I'll send it soon.",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 09:15:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "ianda",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Ian, have you completed the review?",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 09:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, I sent my feedback.",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 09:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Thanks for that.",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 09:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Anytime!",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 09:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "jillt",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Jill, let's schedule a catch-up meeting.",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "jillt",
|
||||||
|
"timestamp": "09.10.2024 09:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Sounds good, when works for you?",
|
||||||
|
"senderId": "jillt",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 09:45:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Tomorrow afternoon?",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "jillt",
|
||||||
|
"timestamp": "09.10.2024 09:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "That works for me!",
|
||||||
|
"senderId": "jillt",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 09:55:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "alice",
|
||||||
|
"id2": "evead",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Eve, did you send the schedule?",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "evead",
|
||||||
|
"timestamp": "09.10.2024 10:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, just sent it.",
|
||||||
|
"senderId": "evead",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 10:05:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Thanks, much appreciated!",
|
||||||
|
"senderId": "alice",
|
||||||
|
"recipientId": "evead",
|
||||||
|
"timestamp": "09.10.2024 10:10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "No problem!",
|
||||||
|
"senderId": "evead",
|
||||||
|
"recipientId": "alice",
|
||||||
|
"timestamp": "09.10.2024 10:15:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "bobsm",
|
||||||
|
"id2": "charl",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "How's everything going?",
|
||||||
|
"senderId": "bobsm",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 10:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Pretty good, how about you?",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "bobsm",
|
||||||
|
"timestamp": "09.10.2024 10:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Can't complain!",
|
||||||
|
"senderId": "bobsm",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 10:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Glad to hear that.",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "bobsm",
|
||||||
|
"timestamp": "09.10.2024 10:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "bobsm",
|
||||||
|
"id2": "david",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Can you send the report?",
|
||||||
|
"senderId": "bobsm",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 10:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I'll send it in an hour.",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "bobsm",
|
||||||
|
"timestamp": "09.10.2024 10:45:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Perfect, thanks.",
|
||||||
|
"senderId": "bobsm",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 10:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "No problem.",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "bobsm",
|
||||||
|
"timestamp": "09.10.2024 10:55:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "charl",
|
||||||
|
"id2": "evead",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Hey Eve, how's it going?",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "evead",
|
||||||
|
"timestamp": "09.10.2024 11:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Good, how about you?",
|
||||||
|
"senderId": "evead",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 11:05:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Can't complain!",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "evead",
|
||||||
|
"timestamp": "09.10.2024 11:10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Glad to hear.",
|
||||||
|
"senderId": "evead",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 11:15:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "charl",
|
||||||
|
"id2": "frank",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Do you have time to talk today?",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 11:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I have a meeting, but I can chat afterward.",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 11:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Sounds good.",
|
||||||
|
"senderId": "charl",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 11:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I'll message you after.",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "charl",
|
||||||
|
"timestamp": "09.10.2024 11:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "david",
|
||||||
|
"id2": "frank",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Did you review the document?",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 11:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, it's all good.",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 11:45:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Great, thanks for the quick turnaround!",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 11:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "No worries!",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 11:55:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "david",
|
||||||
|
"id2": "grace",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Grace, can you send the updated schedule?",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 12:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, I'll send it in a few minutes.",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 12:05:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Thanks, much appreciated!",
|
||||||
|
"senderId": "david",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 12:10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "You're welcome!",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "david",
|
||||||
|
"timestamp": "09.10.2024 12:15:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "frank",
|
||||||
|
"id2": "grace",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "How are you today?",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 12:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I'm doing well, thanks for asking.",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 12:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Glad to hear that.",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 12:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "How about you?",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 12:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "frank",
|
||||||
|
"id2": "hanna",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Did you attend the meeting?",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 12:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, it was productive.",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 12:45:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Good to hear!",
|
||||||
|
"senderId": "frank",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 12:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Indeed, lots to follow up on.",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "frank",
|
||||||
|
"timestamp": "09.10.2024 12:55:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "grace",
|
||||||
|
"id2": "hanna",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Can we meet later today?",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 01:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Sure, what's a good time?",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 01:05:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "How about 3?",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 01:10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Works for me.",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 01:15:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "grace",
|
||||||
|
"id2": "ianda",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Ian, did you get the message I sent?",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 01:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, I'll respond soon.",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 01:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Thanks, appreciate it!",
|
||||||
|
"senderId": "grace",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 01:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "You're welcome!",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "grace",
|
||||||
|
"timestamp": "09.10.2024 01:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "hanna",
|
||||||
|
"id2": "ianda",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Ian, do you have a minute?",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 01:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, what do you need?",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 01:45:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Just a quick update on the project.",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 01:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I'll email you the details.",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 01:55:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "hanna",
|
||||||
|
"id2": "jillt",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Jill, can we talk tomorrow?",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "jillt",
|
||||||
|
"timestamp": "09.10.2024 02:00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Yes, I'm free after 2.",
|
||||||
|
"senderId": "jillt",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 02:05:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Perfect, see you then.",
|
||||||
|
"senderId": "hanna",
|
||||||
|
"recipientId": "jillt",
|
||||||
|
"timestamp": "09.10.2024 02:10:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Looking forward to it.",
|
||||||
|
"senderId": "jillt",
|
||||||
|
"recipientId": "hanna",
|
||||||
|
"timestamp": "09.10.2024 02:15:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id1": "ianda",
|
||||||
|
"id2": "jillt",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"data": "Jill, I have the files you requested.",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "jillt",
|
||||||
|
"timestamp": "09.10.2024 02:20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Thanks, please send them over.",
|
||||||
|
"senderId": "jillt",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 02:25:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "I'll send them right now.",
|
||||||
|
"senderId": "ianda",
|
||||||
|
"recipientId": "jillt",
|
||||||
|
"timestamp": "09.10.2024 02:30:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "Great, thanks again!",
|
||||||
|
"senderId": "jillt",
|
||||||
|
"recipientId": "ianda",
|
||||||
|
"timestamp": "09.10.2024 02:35:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
const chatRouter = require('express').Router()
|
||||||
|
|
||||||
|
module.exports = chatRouter
|
||||||
|
|
||||||
|
const { getChatFromDB, getUsersChats, addChatToDB, getUserFromDB,
|
||||||
|
addMessageToChat} = require('../db')
|
||||||
|
|
||||||
|
chatRouter.get('/item/:id1/:id2', (req, res) => {
|
||||||
|
const { id1, id2 } = req.params
|
||||||
|
|
||||||
|
if (id1 === id2) {
|
||||||
|
res.status(400).send({message: 'Ids should be different'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const chat = getChatFromDB(id1, id2)
|
||||||
|
|
||||||
|
if (chat) {
|
||||||
|
res.status(200).send({chat})
|
||||||
|
} else {
|
||||||
|
res.status(404).send({message: 'Chat was not found'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
chatRouter.post('/item/:id1/:id2', (req, res) => {
|
||||||
|
const { id1, id2 } = req.params
|
||||||
|
|
||||||
|
if (id1 === id2) {
|
||||||
|
res.status(400).send({message: 'Ids should be different'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const chat = getChatFromDB(id1, id2)
|
||||||
|
|
||||||
|
if (chat) {
|
||||||
|
// Chat already exists
|
||||||
|
res.status(200).send({chat})
|
||||||
|
} else {
|
||||||
|
if (!getUserFromDB(id1) || !getUserFromDB(id2)) {
|
||||||
|
res.status(404).send({message: 'Such interlocutor does not exist'})
|
||||||
|
} else {
|
||||||
|
// Creating new chat
|
||||||
|
const newChat = {
|
||||||
|
id1: id1,
|
||||||
|
id2: id2,
|
||||||
|
messages: []
|
||||||
|
}
|
||||||
|
|
||||||
|
addChatToDB(newChat)
|
||||||
|
|
||||||
|
res.status(200).send({newChat})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
chatRouter.get('/list/:id', (req, res) => {
|
||||||
|
const { id } = req.params
|
||||||
|
|
||||||
|
const userChats = getUsersChats(id)
|
||||||
|
|
||||||
|
if (!userChats) {
|
||||||
|
res.status(404).send({message: 'Error with retrieving chats'})
|
||||||
|
} else {
|
||||||
|
res.status(200).send({chats: userChats})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
chatRouter.post('/message/:sender/:receiver', (req, res) => {
|
||||||
|
const { sender, receiver } = req.params
|
||||||
|
const { message } = req.body
|
||||||
|
|
||||||
|
const chat = getChatFromDB(sender, receiver)
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
// Chat already exists
|
||||||
|
res.status(400).send({message: "Such chat does not exist"})
|
||||||
|
} else {
|
||||||
|
if (!getUserFromDB(sender) || !getUserFromDB(receiver)) {
|
||||||
|
res.status(404).send({message: 'Such people do not exist'})
|
||||||
|
} else {
|
||||||
|
// Add new message
|
||||||
|
addMessageToChat(chat, message)
|
||||||
|
res.status(200).send({})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
// Read already defined users (pseudo-DB)
|
||||||
|
const users = require('./auth/users.json')
|
||||||
|
const chats = require('./chat/chats.json')
|
||||||
|
|
||||||
|
const getUserFromDB = (userID) => {
|
||||||
|
if (!userID) {return false}
|
||||||
|
|
||||||
|
// Accessing 'DB'
|
||||||
|
const user = users.find((user) => user.id === userID)
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
return user
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteUserFromDB = (userID) => {
|
||||||
|
const index = users.findIndex(item => item.id === userID)
|
||||||
|
if (index !== -1) {
|
||||||
|
users.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addUserToDB = (user) => {
|
||||||
|
users.push(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getChatFromDB = (firstID, secondID) => {
|
||||||
|
if (!firstID || !secondID) {return false}
|
||||||
|
|
||||||
|
// Accessing 'DB'
|
||||||
|
const chat = chats.find((item) =>
|
||||||
|
(item.id1 === firstID && item.id2 === secondID) || (item.id1 === secondID && item.id2 === firstID))
|
||||||
|
|
||||||
|
if (chat) {
|
||||||
|
return chat
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUsersChats = (userID) => {
|
||||||
|
if (!userID) {return false}
|
||||||
|
|
||||||
|
const userChats = chats.filter((chat) => (chat.id1 === userID || chat.id2 === userID))
|
||||||
|
|
||||||
|
if (userChats) {
|
||||||
|
return userChats
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addMessageToChat = (chat, msg) => {
|
||||||
|
chat.messages.push(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteChatFromDB = (firstID, secondID) => {
|
||||||
|
const index = chats.findIndex(item =>
|
||||||
|
(item.id1 === firstID && item.id2 === secondID) || (item.id1 === secondID && item.id2 === firstID))
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
chats.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addChatToDB = (chat) => {
|
||||||
|
chats.push(chat)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {users, chats, getUserFromDB, getChatFromDB, addUserToDB,
|
||||||
|
deleteUserFromDB, addChatToDB, deleteChatFromDB, getUsersChats, addMessageToChat}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
const changeRouter = require("./change")
|
||||||
|
const authRouter = require("./auth")
|
||||||
|
const chatRouter = require("./chat")
|
||||||
|
|
||||||
|
const router = require('express').Router()
|
||||||
|
|
||||||
|
const delay = require('./middlewares/delay')
|
||||||
|
const verify = require('./middlewares/verify')
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
|
|
||||||
|
// router.use(delay(300));
|
||||||
|
// router.use('/books', delay, booksRouter);
|
||||||
|
|
||||||
|
router.use('/auth', authRouter)
|
||||||
|
router.use('/change', verify, changeRouter)
|
||||||
|
router.use('/chat', verify, chatRouter)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
const TOKEN_KEY = '5frv12e4few3r'
|
||||||
|
|
||||||
|
module.exports = { TOKEN_KEY }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const delay = (ms = 1000) => (req, res, next) => {
|
||||||
|
setTimeout(next, ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = delay
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
const jwt = require('jsonwebtoken')
|
||||||
|
|
||||||
|
const { TOKEN_KEY } = require('../key')
|
||||||
|
|
||||||
|
function verifyToken(req, res, next) {
|
||||||
|
const token = req.headers['authorization']?.split(' ')[1]
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
return res.status(401).send({ message: 'No token provided' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify token
|
||||||
|
jwt.verify(token, TOKEN_KEY, (err, decoded) => {
|
||||||
|
if (err) {
|
||||||
|
return res.status(401).send({ message: 'Unauthorized' })
|
||||||
|
}
|
||||||
|
|
||||||
|
next() // Proceed to the next middleware or route
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = verifyToken
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
const { Router } = require('express')
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
router.use('/enterfront', require('./enterfront/index'))
|
||||||
|
|
||||||
|
router.use('/cats', require('./cats/index'))
|
||||||
|
|
||||||
|
router.use('/ecliptica', require('./ecliptica/index'))
|
||||||
|
|
||||||
|
router.use('/sdk', require('./sdk/index'))
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
const router = require('express').Router();
|
||||||
|
const { v4: uuidv4 } = require('uuid');
|
||||||
|
|
||||||
|
const workout1 = {
|
||||||
|
id: uuidv4(),
|
||||||
|
title: "Toned upper body",
|
||||||
|
exercises: [
|
||||||
|
{ title: "Push ups", repsOrDuration: 12, isTimeBased: false },
|
||||||
|
{ title: "Plank", repsOrDuration: 4, isTimeBased: true },
|
||||||
|
{ title: "Bicep curl", repsOrDuration: 12, isTimeBased: false, weight: 5 },
|
||||||
|
{ title: "Bicep curl", repsOrDuration: 12, isTimeBased: false, weight: 5 },
|
||||||
|
{ title: "Bicep curl", repsOrDuration: 12, isTimeBased: false, weight: 5 },
|
||||||
|
{ title: "Bicep curl", repsOrDuration: 12, isTimeBased: false, weight: 5 },
|
||||||
|
],
|
||||||
|
tags: ['Weights', 'Arms', 'Abs', 'Chest', 'Back']
|
||||||
|
};
|
||||||
|
|
||||||
|
const workout2 = {
|
||||||
|
id: uuidv4(),
|
||||||
|
title: "Tom Platz's legs",
|
||||||
|
exercises: [
|
||||||
|
{ title: "Squats", repsOrDuration: 12, isTimeBased: false, weight: 40 },
|
||||||
|
{ title: "Leg Press", repsOrDuration: 4, isTimeBased: false, weight: 65 },
|
||||||
|
{ title: "Lunges", repsOrDuration: 2, isTimeBased: true }
|
||||||
|
],
|
||||||
|
tags: ['Weights', 'Legs']
|
||||||
|
};
|
||||||
|
|
||||||
|
const workout3 = {
|
||||||
|
id: uuidv4(),
|
||||||
|
title: "HIIT",
|
||||||
|
exercises: [
|
||||||
|
{ title: "Jumping rope", repsOrDuration: 100, isTimeBased: false },
|
||||||
|
{ title: "Burpees", repsOrDuration: 3, isTimeBased: true },
|
||||||
|
{ title: "Jumping Jacks", repsOrDuration: 50, isTimeBased: false }
|
||||||
|
],
|
||||||
|
tags: ['Cardio']
|
||||||
|
}
|
||||||
|
|
||||||
|
const savedWorkouts = [workout1, workout3];
|
||||||
|
|
||||||
|
const trainingWorkouts = [workout2];
|
||||||
|
|
||||||
|
router.post('/workout', (req, res) => {
|
||||||
|
const newWorkout = { ...req.body, id: uuidv4() };
|
||||||
|
savedWorkouts.push(newWorkout);
|
||||||
|
res.status(201).json(newWorkout);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/workouts', (req, res) => {
|
||||||
|
res.json(savedWorkouts);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/training/workout', (req, res) => {
|
||||||
|
const newWorkout = { ...req.body, id: uuidv4() };
|
||||||
|
trainingWorkouts.push(newWorkout);
|
||||||
|
res.status(201).json(newWorkout);
|
||||||
|
});
|
||||||
|
|
||||||
|
const trainings = [{ id: uuidv4(), calories: 450, date: new Date("Thu Oct 03 2024 10:05:24 GMT+0300 (Moscow Standard Time)"), emoji: "fuzzy", hours: 1, minutes: 30, isWorkoutSaved: true, workout: workout1.id }];
|
||||||
|
|
||||||
|
const days = [
|
||||||
|
new Date("Thu Oct 03 2024 10:05:24 GMT+0300 (Moscow Standard Time)"),
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
router.post('/training', (req, res) => {
|
||||||
|
const newTraining = { ...req.body, id: uuidv4() };
|
||||||
|
trainings.push(newTraining);
|
||||||
|
days.push(newTraining.date);
|
||||||
|
res.status(201).json(newTraining);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/training', (req, res) => {
|
||||||
|
const { date } = req.query;
|
||||||
|
if (!date) {
|
||||||
|
return res.status(400).json({ message: 'Date query parameter is required' });
|
||||||
|
}
|
||||||
|
const formattedDate = new Date(date);
|
||||||
|
const result = trainings.find(t => new Date(t.date).toDateString() === formattedDate.toDateString());
|
||||||
|
if (result) {
|
||||||
|
res.json(result);
|
||||||
|
} else {
|
||||||
|
res.status(404).json({ message: 'Training not found for the specified date' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/training/workout', (req, res) => {
|
||||||
|
const { id } = req.query;
|
||||||
|
if (!id) {
|
||||||
|
return res.status(400).json({ message: 'Id query parameter is required' });
|
||||||
|
}
|
||||||
|
const result = trainingWorkouts.find(w => w.id === id);
|
||||||
|
if (result) {
|
||||||
|
res.json(result);
|
||||||
|
} else {
|
||||||
|
res.status(404).json({ message: 'Training with such workout not found' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/workout', (req, res) => {
|
||||||
|
const { id } = req.query;
|
||||||
|
if (!id) {
|
||||||
|
return res.status(400).json({ message: 'Id query parameter is required' });
|
||||||
|
}
|
||||||
|
const result = savedWorkouts.find(w => w.id === id);
|
||||||
|
if (result) {
|
||||||
|
res.json(result);
|
||||||
|
} else {
|
||||||
|
res.status(404).json({ message: 'Workout not found' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/trainings', (req, res) => {
|
||||||
|
res.json(trainings);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/days', (req, res) => {
|
||||||
|
res.json(days);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const router = require('express').Router()
|
|
||||||
|
|
||||||
const first = router.get('/first', (req, res) => {
|
|
||||||
res.send({
|
|
||||||
success: true,
|
|
||||||
warnings: [{
|
|
||||||
title: 'Внимание',
|
|
||||||
text: 'Данный api создан для примера!',
|
|
||||||
}],
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Этот эндпоинт будет доступен по адресу http://89.223.91.151:8080/multystub/example/first
|
|
||||||
*/
|
|
||||||
})
|
|
||||||
|
|
||||||
router.use('/example-api', first)
|
|
||||||
|
|
||||||
module.exports = router
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
const Router = require('express').Router;
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
const timer = (_req, _res, next) => {
|
||||||
|
setTimeout(() => next(), 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use(timer)
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/active',
|
||||||
|
(req, res) =>
|
||||||
|
res.send(require(`./json/active-order-success.json`))
|
||||||
|
)
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/history',
|
||||||
|
(req, res) =>
|
||||||
|
res.send(require(`./json/history-success.json`))
|
||||||
|
)
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
"Не получилось получить заказ с id = 123123"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"body": {
|
||||||
|
"id": "1212",
|
||||||
|
"createdAt": "2024-11-29 13:24:08",
|
||||||
|
"updatedAt": "2024-11-29 13:24:10",
|
||||||
|
"status": "in_progress",
|
||||||
|
"timeline": [
|
||||||
|
{
|
||||||
|
"color": "gray",
|
||||||
|
"children": "Москва"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children": "Владимир, 25.10.2024 18:02"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children": "Нижний новгород, 25.10.2024 12:21"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children": "Казань, 25.10.2024 03:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"statistics": [
|
||||||
|
{
|
||||||
|
"key": "address-from",
|
||||||
|
"value": "г. Казань, ул Ильи Давыдова, стр. 87а"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "address-to",
|
||||||
|
"value": "г. Москва, ул. Тверская, д. 12"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "delivery",
|
||||||
|
"value": "26.10.2024 23:08"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "cost",
|
||||||
|
"value": "100500₽"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customer",
|
||||||
|
"value": "ООО \"Сидоров\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"body": {
|
||||||
|
"history": []
|
||||||
|
},
|
||||||
|
"errors": [
|
||||||
|
"Что-то пошло не так"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"body": {
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"key": 1,
|
||||||
|
"number": "12324",
|
||||||
|
"cost": 15000,
|
||||||
|
"dateEnd": 1685998800000,
|
||||||
|
"customer": "ООО \"Иванов\"",
|
||||||
|
"cityFrom": "Псков",
|
||||||
|
"cityTo": "Мурманск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 2,
|
||||||
|
"number": "12323",
|
||||||
|
"cost": 10000,
|
||||||
|
"dateEnd": 1686085200000,
|
||||||
|
"customer": "ООО \"Попов\"",
|
||||||
|
"cityFrom": "Астрахань",
|
||||||
|
"cityTo": "Ставрополь"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 3,
|
||||||
|
"number": "12325",
|
||||||
|
"cost": 12000,
|
||||||
|
"dateEnd": 1686171600000,
|
||||||
|
"customer": "ООО \"Сидоров\"",
|
||||||
|
"cityFrom": "Москва",
|
||||||
|
"cityTo": "Казань"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 4,
|
||||||
|
"number": "12326",
|
||||||
|
"cost": 9000,
|
||||||
|
"dateEnd": 1686258000000,
|
||||||
|
"customer": "ООО \"Петров\"",
|
||||||
|
"cityFrom": "Новосибирск",
|
||||||
|
"cityTo": "Томск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 5,
|
||||||
|
"number": "12327",
|
||||||
|
"cost": 13000,
|
||||||
|
"dateEnd": 1686344400000,
|
||||||
|
"customer": "ООО \"Смирнов\"",
|
||||||
|
"cityFrom": "Омск",
|
||||||
|
"cityTo": "Тюмень"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 6,
|
||||||
|
"number": "12328",
|
||||||
|
"cost": 14000,
|
||||||
|
"dateEnd": 1686430800000,
|
||||||
|
"customer": "ООО \"Кузнецов\"",
|
||||||
|
"cityFrom": "Саратов",
|
||||||
|
"cityTo": "Самара"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 7,
|
||||||
|
"number": "12329",
|
||||||
|
"cost": 11000,
|
||||||
|
"dateEnd": 1686517200000,
|
||||||
|
"customer": "ООО \"Васильев\"",
|
||||||
|
"cityFrom": "Краснодар",
|
||||||
|
"cityTo": "Сочи"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 8,
|
||||||
|
"number": "12330",
|
||||||
|
"cost": 8000,
|
||||||
|
"dateEnd": 1686603600000,
|
||||||
|
"customer": "ООО \"Зайцев\"",
|
||||||
|
"cityFrom": "Пермь",
|
||||||
|
"cityTo": "Екатеринбург"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 9,
|
||||||
|
"number": "12331",
|
||||||
|
"cost": 7000,
|
||||||
|
"dateEnd": 1686690000000,
|
||||||
|
"customer": "ООО \"Морозов\"",
|
||||||
|
"cityFrom": "Челябинск",
|
||||||
|
"cityTo": "Уфа"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 10,
|
||||||
|
"number": "12332",
|
||||||
|
"cost": 16000,
|
||||||
|
"dateEnd": 1686776400000,
|
||||||
|
"customer": "ООО \"Павлов\"",
|
||||||
|
"cityFrom": "Волгоград",
|
||||||
|
"cityTo": "Ростов-на-Дону"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 11,
|
||||||
|
"number": "12333",
|
||||||
|
"cost": 9000,
|
||||||
|
"dateEnd": 1686862800000,
|
||||||
|
"customer": "ООО \"Фролов\"",
|
||||||
|
"cityFrom": "Калининград",
|
||||||
|
"cityTo": "Смоленск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 12,
|
||||||
|
"number": "12334",
|
||||||
|
"cost": 15500,
|
||||||
|
"dateEnd": 1686949200000,
|
||||||
|
"customer": "ООО \"Богданов\"",
|
||||||
|
"cityFrom": "Нижний Новгород",
|
||||||
|
"cityTo": "Киров"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 13,
|
||||||
|
"number": "12335",
|
||||||
|
"cost": 13500,
|
||||||
|
"dateEnd": 1687035600000,
|
||||||
|
"customer": "ООО \"Григорьев\"",
|
||||||
|
"cityFrom": "Тверь",
|
||||||
|
"cityTo": "Ярославль"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 14,
|
||||||
|
"number": "12336",
|
||||||
|
"cost": 12500,
|
||||||
|
"dateEnd": 1687122000000,
|
||||||
|
"customer": "ООО \"Дмитриев\"",
|
||||||
|
"cityFrom": "Сургут",
|
||||||
|
"cityTo": "Ханты-Мансийск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 15,
|
||||||
|
"number": "12337",
|
||||||
|
"cost": 14500,
|
||||||
|
"dateEnd": 1687208400000,
|
||||||
|
"customer": "ООО \"Михайлов\"",
|
||||||
|
"cityFrom": "Иркутск",
|
||||||
|
"cityTo": "Братск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 16,
|
||||||
|
"number": "12338",
|
||||||
|
"cost": 10500,
|
||||||
|
"dateEnd": 1687294800000,
|
||||||
|
"customer": "ООО \"Романов\"",
|
||||||
|
"cityFrom": "Владивосток",
|
||||||
|
"cityTo": "Хабаровск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 17,
|
||||||
|
"number": "12339",
|
||||||
|
"cost": 9500,
|
||||||
|
"dateEnd": 1687381200000,
|
||||||
|
"customer": "ООО \"Федоров\"",
|
||||||
|
"cityFrom": "Якутск",
|
||||||
|
"cityTo": "Магадан"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 18,
|
||||||
|
"number": "12340",
|
||||||
|
"cost": 8500,
|
||||||
|
"dateEnd": 1687467600000,
|
||||||
|
"customer": "ООО \"Жуков\"",
|
||||||
|
"cityFrom": "Симферополь",
|
||||||
|
"cityTo": "Севастополь"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 19,
|
||||||
|
"number": "12341",
|
||||||
|
"cost": 11500,
|
||||||
|
"dateEnd": 1687554000000,
|
||||||
|
"customer": "ООО \"Николаев\"",
|
||||||
|
"cityFrom": "Барнаул",
|
||||||
|
"cityTo": "Бийск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": 20,
|
||||||
|
"number": "12342",
|
||||||
|
"cost": 10000,
|
||||||
|
"dateEnd": 1687640400000,
|
||||||
|
"customer": "ООО \"Орлов\"",
|
||||||
|
"cityFrom": "Кемерово",
|
||||||
|
"cityTo": "Новокузнецк"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const router = require('express').Router();
|
||||||
|
|
||||||
|
router.use('/performer', require('./dashboard-performer'))
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
const router = require('express').Router();
|
||||||
|
//const loginMiddleware = require('../middleware/login-middleware');
|
||||||
|
|
||||||
|
// First page
|
||||||
|
router.get('/getInfoAboutKazan', (request, response) => {
|
||||||
|
response.send(require('./json/first/info-about-kazan/success.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/getNews', (request, response) => {
|
||||||
|
response.send(require('./json/first/news/success.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Sport page
|
||||||
|
router.get('/getSportData', (request, response) => {
|
||||||
|
response.send(require('./json/sport/sport-data.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Places page
|
||||||
|
router.get('/getPlacesData', (request, response) => {
|
||||||
|
response.send(require('./json/places/places-data.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Transport page
|
||||||
|
router.get('/getInfoAboutTransportPage', (request, response) => {
|
||||||
|
response.send(require('./json/transport/info-about-page.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/getBus', (request, response) => {
|
||||||
|
response.send(require('./json/transport/bus-numbers.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/getTral', (request, response) => {
|
||||||
|
response.send(require('./json/transport/tral-numbers.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/getEvents', (request, response) => {
|
||||||
|
response.send(require('./json/transport/events-calendar.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/getTripSchedule', (request, response) => {
|
||||||
|
response.send(require('./json/transport/trip-schedule/success.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get('/getInfoAboutInstitutions', (request, response) => {
|
||||||
|
response.send(require('./json/transport/info-about-institutions.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Education page
|
||||||
|
router.get('/getInfoAboutKFU', (request, response) => {
|
||||||
|
response.send(require('./json/education/info-about-kfu.json'))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Login
|
||||||
|
router.post('/entrance', (request, response) => {
|
||||||
|
const { email, password } = request.body.entranceData;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const users = require('../json/users-information/success.json');
|
||||||
|
const user = users.data.find(user => user.email === email && user.password === password);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return response.status(401).send('Неверные учетные данные');
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseObject = {
|
||||||
|
email: user.email,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.cardId){
|
||||||
|
responseObject.cardId = user.cardId || "";
|
||||||
|
}
|
||||||
|
return response.json(responseObject);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ошибка чтения файла:', error);
|
||||||
|
response.status(500).send('Внутренняя ошибка сервера');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.post('/registration', async (request, response) => {
|
||||||
|
const { email, password, confirmPassword } = request.body.registerData;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (password !== confirmPassword) {
|
||||||
|
return response.status(400).send('Пароли не совпадают!');
|
||||||
|
}
|
||||||
|
const users = require('../json/users-information/success.json');
|
||||||
|
|
||||||
|
const existingUser = users.data.find(user => user.email === email);
|
||||||
|
|
||||||
|
if (existingUser) {
|
||||||
|
return response.status(400).send('Пользователь с такой почтой уже существует!');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json({ email: email});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ошибка регистрации пользователя:', error);
|
||||||
|
response.status(500).send('Внутренняя ошибка сервера');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
Whitespace-only changes.
@@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
"Казанский (Приволжский) федеральный университет (полное наименование — федеральное государственное автономное образовательное учреждение высшего образования «Казанский (Приволжский) федеральный университет», тат. Казан (Идел буе) федераль университеты) — высшее учебное заведение в Казани, один из старейших российских университетов (основан в 1804 году) и один из десяти федеральных университетов (с 2010 года).",
|
||||||
|
"В состав университетского учебно-научного комплекса входят научная библиотека, научно-исследовательские институты химии, математики и механики, 7 музеев, ботанический сад, астрономические обсерватории, центр информационных технологий, издательство, центр и лаборатория оперативной полиграфии, культурно-спортивный комплекс, спортивно-оздоровительный лагерь и другие подразделения."
|
||||||
|
]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"Казань — древний город с богатой историей, где слились воедино культуры Востока и Запада. Подобно драгоценному камню, сияющему в ожерелье городов России, Казань покоряет своей красотой и многообразием. Её красивая архитектура и гостеприимные жители создают уютную атмосферу, привлекающую туристов со всего мира."
|
||||||
|
]
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"image": "new1",
|
||||||
|
"title": "На предприятиях в Казани объявили эвакуацию",
|
||||||
|
"text": "В Казани на некоторых предприятиях объявлена необходимость эвакуации. Об этом сообщили в пресс-службе главы Татарстана. «В отдельных районах Казани на предприятиях объявлена необходимость эвакуации», — сообщили в пресс-службе главы Татарстана. Информацию передает ТАСС. Telegram-канал Shot пишет об эвакуации сотрудников химической компании «Казаньоргсинтез»."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"image": "new2",
|
||||||
|
"title": "В Казани обсудили взаимодействие детей с гаджетами",
|
||||||
|
"text": "В Казани состоялась конференция, посвящённая проблемам воспитания в эпоху технического прогресса. Участники встречи, среди которых психологи, педагоги и родители, обсудили методы противодействия гаджетозависимости и возможности использования технологий для развития молодёжи. «Ничего плохого нет в том, что ребёнок сидит в телефоне. Главное — правильно его направить», - поделилась своим опытом Альфия Валеева, педагог с 16-летним стажем."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3",
|
||||||
|
"image": "new3",
|
||||||
|
"title": "Казанский УНИКС проиграл ЦСКА, счёт в серии 0-3",
|
||||||
|
"text": "В третьем матче финала Единой лиги ВТБ ЦСКА на своей площадке оказался сильнее УНИКСа — 80:72. Счет в серии стал 3−0 в пользу ЦСКА. Если армейцы выиграют еще раз, то станут чемпионами. В отличие от предыдущей игры казанцы уверенно начали. Первую четверть они выиграли 17:13, а на старте второй вели 21:13. Однако ЦСКА быстро сравнял счет, а затем вышел вперед. "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4",
|
||||||
|
"image": "new4",
|
||||||
|
"title": "Синоптики предупредили о грозе и сильном ветре в Казани",
|
||||||
|
"text": "Сегодня вечером в Татарстане, включая Казань, ожидаются гроза и сильный юго-западный ветер порывами 15–20 м/с, местами – до 23 м/с. Об этом предупреждает Гидрометцентр РТ."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5",
|
||||||
|
"image": "new5",
|
||||||
|
"title": "Между столицей РТ и аэропортом запустят дополнительные рейсы",
|
||||||
|
"text": "На маршруте Казань – Аэропорт – Казань два дня будут курсировать дополнительные пригородные поезда. Это связано с проведением концертов в МВЦ «Казань Экспо». Дополнительные поезда проследуют без промежуточных остановок, сообщили в пресс-службе АО «Содружество»."
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"type": "Достопримечательности",
|
||||||
|
"image": "kremlin",
|
||||||
|
"head": "Кремль",
|
||||||
|
"text": "Строительство кремля продолжалось с X по XVI век. После завоевания Казани Иваном Грозным в 1552 году татарский кремль был разрушен. На его месте псковские зодчие построили мощные белокаменные стены, оставив лишь некоторые фрагменты старого сооружения. В XVIII веке кремль потерял военное значение, но долго оставался административным и культурным центром Поволжья."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"image": "kulsharif",
|
||||||
|
"head": "Мечеть Кул-Шариф",
|
||||||
|
"text": "Это одна из визитных карточек Казани. Кроме того, Кул-Шариф ещё и главная джума-мечеть Татарстана. Её возведение началось в 1996 году для восстановления важной архитектурной реликвии Казанского ханства, разрушенной войсками Ивана Грозного в 1552 году. Мечеть получила название в честь последнего имама Казани Кул-Шарифа."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3",
|
||||||
|
"image": "suumbike",
|
||||||
|
"head": "Башня Сююмбике",
|
||||||
|
"text": "Сооружение впервые упоминается в документах 1703 года, однако точных сведений ни о дате постройки, ни о происхождении названия нет. По одной из версий, это была сторожевая башня, потому что с её вершины хорошо просматриваются окрестности, а также реки Казанка и Волга."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4",
|
||||||
|
"type": "Активный отдых",
|
||||||
|
"image": "cyrc",
|
||||||
|
"head": "Казанский цирк",
|
||||||
|
"text": "Один из ярких памятников советского модернизма. Издалека здание цирка напоминает летающую тарелку. Такую «космическую» форму он получил после масштабной реконструкции 1967 года. Тогда для строительства применили авангардные архитектурные и инженерные решения."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5",
|
||||||
|
"image": "park",
|
||||||
|
"head": "Экстрим-парк УРАМ",
|
||||||
|
"text": "УРАМ — самый большой экстрим-парк в России, который состоит из двух частей — открытой и крытой. Уличная часть, объединяющая профессиональные экстрим-зоны и места для прогулок, открылась летом 2020 года и стала одним из самых популярных общественных пространств Казани, а также местом, где спортсмены готовились к соревнованиями мирового масштаба, например, к Олимпиаде в Токио."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6",
|
||||||
|
"image": "zoo",
|
||||||
|
"head": "Зоопарк Река-Замбези",
|
||||||
|
"text": "Зоопарк «Река Замбези» Казанский зооботсад - один из старейших зооботсадов в Европе. Увлекательное путешествие в мир животных и растений. Это уникальное место, где посетители могут насладиться богатством флоры и фауны. Он предлагает разнообразные экспозиции, включая животных различных континентов, от экзотических видов до местных жителей."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7",
|
||||||
|
"type": "Театры и музеи",
|
||||||
|
"head": "Театр кукол Экият",
|
||||||
|
"text": "Театр кукол Экият в Казани представляет уникальное сочетание традиционного и современного искусства. Он известен своими яркими постановками, привлекающими внимание как детей, так и взрослых. Расположенный в центре города, он стал неотъемлемой частью культурной жизни региона.",
|
||||||
|
"image": "akiyat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8",
|
||||||
|
"head": "Театр оперы и балета",
|
||||||
|
"text": "Театр оперы и балета в Казани является вершиной музыкального и театрального искусства в регионе. С его помощью зрители могут наслаждаться высококлассными оперными постановками и великолепными балетными представлениями, которые оставляют незабываемые впечатления.",
|
||||||
|
"image": "opera"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9",
|
||||||
|
"head": "Театр им. К.Тинчурина",
|
||||||
|
"text": "Театр имени Тинчурина воплощает традиции классического искусства, предлагая зрителям широкий выбор спектаклей, начиная от драм и комедий до мюзиклов и балетов. История театра имени К. Тинчурина насчитывает десятилетия искусства и культурного наследия.",
|
||||||
|
"image": "tinchurina"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "10",
|
||||||
|
"type": "Еда и напитки",
|
||||||
|
"head": "Тюбетей",
|
||||||
|
"text": "«Тюбетей» - это уютное заведение в Казани, предлагающее посетителям широкий выбор блюд татарской кухни в атмосфере гостеприимства и комфорта. Здесь можно насладиться татарскими блюдами, такими как чак-чак, шашлык, манты и другие.",
|
||||||
|
"image": "tubetey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "11",
|
||||||
|
"head": "MORE & MORE",
|
||||||
|
"text": "Этот ресторан специализируется на морепродуктах и рыбе. Ресторан More & More – концептуальный проект от ALBA GROUP с акцентом на seafood and wine. По казанским меркам место дорогое, но блюда и ингредиенты оправдывают стоимость",
|
||||||
|
"image": "more"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "12",
|
||||||
|
"head": "Палома Кантина",
|
||||||
|
"text": "«Палома Кантина» — это мексиканское кафе. Его открыли основатели петербургского бара El Copitas, который попал в мировой рейтинг The World’s 50 Best Bars. Если в Казани вы почувствуете себя одиноко, захотите ярких красок, вам сюда.",
|
||||||
|
"image": "paloma"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"type": "Баскетбол",
|
||||||
|
"title": "УНИКС ",
|
||||||
|
"text": "Баскетбольный клуб УНИКС — российский мужской баскетбольный клуб. Основан в 1991 году. Представляет город Казань, столицу Республики Татарстан. Выступает в Профессиональной баскетбольной лиге. «УНИКС» расшифровывается как «Университет — Культура — Спорт».",
|
||||||
|
"logo": "unics_logo",
|
||||||
|
"logo_alt": "Логотип УНИКСа",
|
||||||
|
"image": "unics_img",
|
||||||
|
"img_alt": "Фотография игроков УНИКСа с первым чемпионским кубком единой Лиги ВТБ",
|
||||||
|
"link": "https://www.unics.ru/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"title": "Казаночка ",
|
||||||
|
"text": "Казаночка участвует в женской баскетбольной суперлиге и представляет город Казань на национальном уровне. «Казаночка» играет важную роль в развитии женского баскетбола в регионе и активно соревнуется на международной арене.",
|
||||||
|
"logo": "kazanochka_logo",
|
||||||
|
"logo_alt": "Логотип спортивного клуба Казаночка",
|
||||||
|
"image": "kazanochka_img",
|
||||||
|
"img_alt": "Фотография игроков Казаночки",
|
||||||
|
"link": "https://bckazanochka.ru/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3",
|
||||||
|
"type": "Хоккей",
|
||||||
|
"title": "Ак Барс ",
|
||||||
|
"text": "Хоккейный клуб «Ак Барс» из Казани — это один из наиболее известных и успешных профессиональных хоккейных клубов в России. Он был основан в 1956 году и является членом Континентальной Хоккейной Лиги (КХЛ), самой престижной лиги в России и одной из сильнейших в мире.",
|
||||||
|
"logo": "akbars_logo",
|
||||||
|
"logo_alt": "Логотип Ак Барса",
|
||||||
|
"image": "akbars_img",
|
||||||
|
"img_alt": "Фотография игроков Ак Барса",
|
||||||
|
"link": "https://www.ak-bars.ru/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4",
|
||||||
|
"title": "Динамо-Ак Барс ",
|
||||||
|
"text": "«Динамо-Казань» — команда по хоккею с мячом из Казани. Играет в суперлиге чемпионата России. Действующий чемпион России.",
|
||||||
|
"logo": "hockey_dinamo_logo",
|
||||||
|
"logo_alt": "Логотип Динамо-Казань",
|
||||||
|
"image": "hockey_dinamo_img",
|
||||||
|
"img_alt": "Фотография игроков Динамо-Казань",
|
||||||
|
"link": "https://hcdinamo-kazan.ru/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5",
|
||||||
|
"type": "Футбол",
|
||||||
|
"title": "Рубин ",
|
||||||
|
"text": "«Рубин» (тат. Рубин Казан футбол төркеме) — российский футбольный клуб из Казани. Один из ведущих российских футбольных клубов второй половины 2000-х годов. Ведёт свою историю с 1936 года, но официальной датой основания считается 1958 год.",
|
||||||
|
"logo": "rubin_logo",
|
||||||
|
"logo_alt": "Логотип Рубина",
|
||||||
|
"image": "rubin_img",
|
||||||
|
"img_alt": "Фотография игроков Рубина",
|
||||||
|
"link": "https://www.rubin-kazan.ru/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6",
|
||||||
|
"type": "Волейбол",
|
||||||
|
"title": "Зенит-Казань ",
|
||||||
|
"text": "«Зенит» (Казань) — российский мужской волейбольный клуб. Основан в 2000 году, до 2004 года назывался «Динамо», с 2005 по июнь 2008 года — «Динамо-Таттрансгаз». 4-кратный чемпион России, 3-кратный обладатель Кубка России, победитель Лиги чемпионов сезонов 2007/08 и 2011/12 годов. Основные цвета: бело-синие.",
|
||||||
|
"logo": "zenit_logo",
|
||||||
|
"logo_alt": "Логотип Зенита",
|
||||||
|
"image": "zenit_img",
|
||||||
|
"img_alt": "Фотография игроков Зенита",
|
||||||
|
"link": "https://zenit-kazan.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7",
|
||||||
|
"title": "Динамо-Ак Барс ",
|
||||||
|
"text": "«Динамо-Казань» Казань (до 2008 — «Казаночка») — российский женский волейбольный клуб.",
|
||||||
|
"logo": "vol_dinamo_logo",
|
||||||
|
"logo_alt": "Логотип Динамо-Казань",
|
||||||
|
"image": "vol_dinamo_img",
|
||||||
|
"img_alt": "Фотография игроков Динамо-Казань",
|
||||||
|
"link": "https://dinamo-kazan.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8",
|
||||||
|
"type": "Водное поло",
|
||||||
|
"title": "Синтез ",
|
||||||
|
"text": "Толчком развития водного поло в Казани стало строительство первого в Республике 50-ти метрового плавательного бассейна «Оргсинтез», закончившееся в 1973 году. Именно на базе бассейна «Оргсинтез» и была создана взрослая команда «Синтез», добившаяся права играть в первой группе чемпионата РСФСР.",
|
||||||
|
"logo": "waterpolo_logo",
|
||||||
|
"logo_alt": "Логотип Синтеза",
|
||||||
|
"image": "waterpolo_img",
|
||||||
|
"img_alt": "Фотография игроков Синтеза",
|
||||||
|
"link": "https://www.sintez-kazan.ru/index.php/ru/"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
"10a",
|
||||||
|
11,
|
||||||
|
15,
|
||||||
|
18,
|
||||||
|
22,
|
||||||
|
23,
|
||||||
|
25,
|
||||||
|
28,
|
||||||
|
"28a",
|
||||||
|
29,
|
||||||
|
30,
|
||||||
|
31,
|
||||||
|
33,
|
||||||
|
34,
|
||||||
|
35,
|
||||||
|
"35a",
|
||||||
|
36,
|
||||||
|
"36a",
|
||||||
|
37,
|
||||||
|
40,
|
||||||
|
42,
|
||||||
|
43,
|
||||||
|
45,
|
||||||
|
46,
|
||||||
|
47,
|
||||||
|
49,
|
||||||
|
53,
|
||||||
|
54,
|
||||||
|
55,
|
||||||
|
56,
|
||||||
|
60,
|
||||||
|
62,
|
||||||
|
63,
|
||||||
|
68,
|
||||||
|
70,
|
||||||
|
71,
|
||||||
|
72,
|
||||||
|
74,
|
||||||
|
75,
|
||||||
|
77,
|
||||||
|
78,
|
||||||
|
84,
|
||||||
|
"84a",
|
||||||
|
88,
|
||||||
|
89,
|
||||||
|
"89a",
|
||||||
|
90,
|
||||||
|
91,
|
||||||
|
93,
|
||||||
|
94
|
||||||
|
]
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"month": "ЯНВАРЬ",
|
||||||
|
"name": "Республиканский фестиваль народного творчества «Кукморские валенки» #ItekFest",
|
||||||
|
"body": "Программа фестиваля традиционно включает творческие номера от команд-участников и представление ростовых фигур в форме пары валенок. На фестивале работают торговые ряды, где можно приобрести знаменитые кукморские валенки и другие сувениры, изготовленные местными умельцами.",
|
||||||
|
"place": "Кукморский район, г.Кукмор"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Международный оперный фестиваль им.Федора Шаляпина",
|
||||||
|
"month": "ФЕВРАЛЬ",
|
||||||
|
"body": "Один из культурных брендов Республики Татарстан. В традиционной фестивальной программе – спектакли, в которых выступал сам великий бас Федор Шаляпин.",
|
||||||
|
"place": "г.Казань, Татарский академический государственный театр оперы и балета им.М.Джалиля"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Фестиваль креативных санок SUNNYФЕСТ",
|
||||||
|
"body": "Со всех городов республики и даже других регионов России сюда съезжаются санки разных форм и размеров. Презентовав созданные своими руками невообразимые конструкции, участники пробуют их в деле – скатываются с горы, на ходу разыгрывая сценки или исполняя песни. Также зрителей ждут ярмарка, тематические фотосессии и прочие зимние забавы.",
|
||||||
|
"place": "Мамадышский район, г.Мамадыш"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "III спортивно-исторический фестиваль «Кыш Батыр. Не просто Зимние игры»",
|
||||||
|
"body": "На площадке фестиваля пройдут соревнования по лыжным гонкам и по историческому биатлону среди разных возрастных категорий, победителей лыжных гонок определят по 16 номинациям. Также гостей фестиваля ждет спортивная зарядка под зажигательную музыку, танцы, стрельба из лука и арбалета, метание топориков, поднятие штанги, приседание с коромыслами, бои на импровизированных мечах.",
|
||||||
|
"place": "г.Казань, Горкинско-Ометьевский лес"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "МАРТ",
|
||||||
|
"name": "Масленица",
|
||||||
|
"body": "Яркая и веселая Масленица с песнями, танцами, играми, угощениями и, конечно, сжиганием чучела проходит во многих городах Татарстана – в Казани (на озере Лебяжье), на острове-граде Свияжск, в Алексеевском, в Чистополе.",
|
||||||
|
"place": "Города Татарстана"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "АПРЕЛЬ",
|
||||||
|
"name": "Международный фестиваль «Рахлинские сезоны»",
|
||||||
|
"body": "Фестиваль «Рахлинские сезоны» посвящен памяти первого художественного руководителя и главного дирижера Государственного симфонического оркестра Татарстана Н.Рахлина.",
|
||||||
|
"place": "г.Казань, Большой концертный зал имени Сайдашева"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "МАЙ",
|
||||||
|
"name": "Международный фестиваль классического балета им. Рудольфа Нуриева",
|
||||||
|
"body": "Крупнейший фестиваль балетного искусства, один из старейших в России. С 1993 года носит имя величайшего танцовщика XX века Рудольфа Нуриева, принявшего участие в фестивале в 1992 году.",
|
||||||
|
"place": "г.Казань, Татарский академический государственный театр оперы и балета им. М. Джалиля"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Фестиваль русского фольклора «Каравон»",
|
||||||
|
"body": "Программа фольклорного праздника включает красочное театрализованное представление, игры и забавы, выставку-продажу изделий народных ремесел. Кульминацией праздника становится общий дружный хоровод.",
|
||||||
|
"place": "Лаишевский район, с. Никольское"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Религиозный праздник «Изге Болгар жиены»",
|
||||||
|
"body": "Торжественные мероприятия, посвященные годовщине принятия ислама Волжскими Булгарами в 922 году, на которые съезжаются тысячи верующих из разных регионов России и стран мира.",
|
||||||
|
"place": "Спасский район, г.Болгар"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ак Барс Банк Казанский марафон",
|
||||||
|
"body": "Участники марафона, который проходит с 2015 года, увидят главные достопримечательности Казани, расположенные на всем протяжении соревновательной трассы. На выбор предлагаются четыре дистанции: 3 км, 10 км, 21,1 км, 42,2 км, отдельные старты запланированы для самых юных спортсменов.",
|
||||||
|
"place": "г.Казань"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Международный фестиваль медиаискусства «НУР»",
|
||||||
|
"body": "Участники фестиваля создают медиаарт-работы с помощью света, звука, компьютерных технологий и дополненной реальности в десятках казанских локаций. Кроме инсталляций, выставок цифрового искусства и аудиовизуальных перформансов, на фестивале организуются образовательная программа с лекциями, воркшопами и медиалабораториями, ночная музыкальная программа.",
|
||||||
|
"place": "г.Казань"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Татарский национальный праздник «Сабантуй»",
|
||||||
|
"month": "ИЮНЬ",
|
||||||
|
"body": "Праздник проходит в три этапа. В первую субботу по окончании весеннего сева – в селах и деревнях республики, через неделю – в крупных городах Татарстана, а еще через неделю – в столице проходит главный Сабантуй. В районах Казани организуются майданы для проведения состязаний, площадки для выступления мастеров культуры и искусств Татарстана, народные гулянья. На центральном ипподроме города проводятся скачки.",
|
||||||
|
"place": "Города Татарстана"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Международный музыкальный фестиваль Бориса Березовского «Летние вечера в Елабуге»",
|
||||||
|
"body": "Этот фестиваль проводится в формате open-air (на открытом воздухе). Художественным руководителем проекта является заслуженный артист России Борис Березовский. Помимо него участие в фестивале принимают известные музыканты, оркестры и коллективы.",
|
||||||
|
"place": "Елабужский район, г.Елабуга, Шишкинские пруды"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Фестиваль колокольного звона и русской песни «Алексеевские перезвоны»",
|
||||||
|
"body": "Фестиваль – визитная карточка Алексеевского района. Музыкальная часть фестиваля включает звон-концерт лучших звонарей России и других стран, выступления авторов и исполнителей духовной и народной музыки, фольклорных и танцевальных коллективов различных жанров. Также гостей фестивальной площадки ждут ярмарка «Город мастеров», где можно приобрести сувениры, созданные мастерами-ремесленниками, мастер-классы по изготовлению изделий декоративно-прикладного творчества, детские активности.",
|
||||||
|
"place": "Алексеевский район, пгт. Алексеевское, Соборная площадь"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Республиканский фестиваль марийской культуры «Семык»",
|
||||||
|
"body": "«Семык» – один из любимых традиционных праздников марийцев, знаменующий начало летнего праздничного цикла. На фестивале неизменно присутствуют элементы марийской культуры: национальные костюмы, инструментальная музыка, народные песни, танцы, игры, традиционная кухня.",
|
||||||
|
"place": "Мамадышский район, с.Большая Шия"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Фестиваль чувашей Закамья «Учук»",
|
||||||
|
"body": "Фестиваль проводится ежегодно с 2006 года в последнюю субботу июня. Во время праздника недалеко от фестивальной площадки старейшинами села варится традиционная каша на родниковой воде. Затем проходят специальные моления с просьбой о дожде для посевов. После молебна приготовленную ритуальную кашу дождя раздают всем присутствующим.",
|
||||||
|
"place": "Альметьеввский район, с.Старое Суркино"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Республиканский удмуртский праздник «Гырон Быдтон»",
|
||||||
|
"body": "Праздник традиционно проводится после завершения весенней пахоты и сева яровых, перед сенокосом. Гостей праздника угощают ритуальной кашей, которая варится на кострах. Национальный напиток – кумышку – гостям полагается пить из чаши, прикрепленной к концу посоха, который держит в руках хозяйка. Гость руками к чаше и посоху не прикасается, так что приходится выпивать «до дна».",
|
||||||
|
"place": "Менделеевский район, с.Енабердино"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Республиканский праздник мордовской культуры «Валда шинясь»",
|
||||||
|
"body": "Праздник приурочен ко дню летнего солнцестояния, отражающему мифологические представления мордовского народа о мире. Праздник объединяет в себе два основных субэтноса мордовского народа – эрзя и мокшу, а также уникальную этнографическую группу мокшан-каратаев, проживающих в Камско-Устьинском районе Татарстана. Праздник традиционно проходит на большой поляне, где презентуется мордовская национальная культура – быт, обряды, национальная кухня.",
|
||||||
|
"place": "Тетюшский район, с. Кильдюшево"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "День рыбака",
|
||||||
|
"month": "ИЮЛЬ",
|
||||||
|
"body": "Праздник проходит в Тетюшах, где День города и День рыбака отмечают одновременно, весело и задорно. В этот день гостей ждут театрализованные представления, конкурс на самый крупный улов, танцы и песни, богатый рыбный стол.",
|
||||||
|
"place": "Тетюшский район, г. Тетюши"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Республиканский праздник чувашской культуры «Уяв»",
|
||||||
|
"body": "Уяв – старинный чувашский обрядовый праздник, бережно хранимый и передаваемый из поколения в поколение, с особыми ритуалами, хороводами народными забавами и игрищами. На площадках майдана также можно увидеть выставку изделий декоративно-прикладного искусства, поучаствовать в мастер-классах, оценить творческие состязания частушечников и гармонистов.",
|
||||||
|
"place": "Алькеевский район, с. Сиктерме"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Республиканский праздник культуры кряшен «Питрау»",
|
||||||
|
"body": "«Питрау» – один из важных обрядовых праздников кряшен. Он приходится на самую макушку лета и олицетворяет переход на новый календарный цикл. После Петрова дня массово выходят на сенокос.",
|
||||||
|
"place": "Мамадышский район, с. Зюри"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Республиканский праздник славянской культуры «Иван Купала»",
|
||||||
|
"body": "«Иван Купала» – народный праздник восточных славян, посвященный летнему солнцестоянию и наивысшему расцвету природы. Праздник воссоздает традиционные купальские обряды – плетение венков, гадание на венках, украшение купальского дерева – березы, зажигание купальского костра и прыжки через него. Для участников праздника работают интерактивные площадки, ярмарка товаров народно-художественных промыслов, мастер-классы по плетению венков, изготовлению оберегов, кукол, талисманов.",
|
||||||
|
"place": "Зеленодольский район"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Всероссийский фестиваль «Скорлупино»",
|
||||||
|
"body": "Фестиваль - визитная карточка Пестречинского района. Ежегодно на празднике устанавливается необычный гастрономический рекорд. Результат предоставляется возможность продегустировать всем гостям. Традиционно программа фестиваля включает ярмарку народных художественных промыслов с мастер-классами от ремесленников, яркие тематические фотозоны, забавные игры с призами, музыкальные площадки.",
|
||||||
|
"place": "Пестречинский район"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Фестиваль современной татарской культуры «Печән базары»",
|
||||||
|
"body": "В день проведения колоритного фестиваля, погружающего в татарскую культуру, работает ярмарка мастеров, где можно приобрести аутентичные и необычные подарки и сувениры на память о Татарстане: одежду, аксессуары и украшения с татарским орнаментом, посуду ручной работы, игрушки, натуральную косметику и многое другое. Также гостей фестиваля ждут лекции, концертная программа, мастер-классы для детей и другие активности, которые помогут узнать много интересного о Татарстане и его культуре.",
|
||||||
|
"place": "г.Казань, Старо-татарская слобода, набережная озера Кабан"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Фестиваль «Ага-Базар»",
|
||||||
|
"body": "Идея фестиваля - в возрождении традиций «Восточного базара», который находился в пригороде средневекового Болгара и считался торгово-ремесленным и культурным центром Волжской Булгарии. На фестивале можно услышать этноколлективы, посетить национальные подворья, чтобы познакомиться с обычаями и традициями народов Поволжья. Одна из центральных площадок - стилизованный средневековый рынок Волжской Булгарии, на котором можно было приобрести товары ручной работы.",
|
||||||
|
"place": "Спасский район, г.Болгар, Болгарский музей-заповедник"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Международный этнический фестиваль «Крутушка»",
|
||||||
|
"month": "АВГУСТ",
|
||||||
|
"body": "Фестиваль проводится для истинных ценителей качественной этнической музыки и живого фольклорного наследия. По традиции здесь можно поучаствовать в разнообразных мастер-классах: научиться танцам разных народов, основам игры на традиционных инструментах, изготовить собственными руками изделия из глины, кожи, войлока, лозы, дерева, бисера и бересты",
|
||||||
|
"place": "г.Казань, пос.Крутушка"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Всероссийская Спасская ярмарка",
|
||||||
|
"body": "В ярмарке принимают участие более 1000 мастеров декоративно-прикладного искусства, художественного творчества и народных промыслов из 150 городов и поселений России и других стран. Проходят выступления фольклорных и цирковых коллективов, работают национальные подворья, «Город мастеров».",
|
||||||
|
"place": "Елабужский район, г.Елабуга"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Музейно-фольклорный праздник «Яблочный Спас в Красновидово»",
|
||||||
|
"body": "Издревле село Красновидово славилось своими плодоносными яблоневыми садами. Основа праздника – это концертная программа с выступлением вокального ансамбля «Оберег» и творческих коллективов Республики Татарстан. Также в программе мероприятия и проведение мастер-классов по изготовлению предметов народных промыслов.",
|
||||||
|
"place": "Камско-Устьинский район, село Красновидово"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "День Казани и Республики Татарстан",
|
||||||
|
"body": "Главный праздник для жителей Татарстана: он широко отмечается во всех городах республики, а казанцы в этот день, 30 августа, справляют еще и день города. На многочисленных праздничных площадках проводятся театрализованные представления, концерты, мотошоу, конкурсы. Завершается день праздничным салютом.",
|
||||||
|
"place": "г.Казань и города Татарстана"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Казанский международный фестиваль мусульманского кино",
|
||||||
|
"month": "СЕНТЯБРЬ",
|
||||||
|
"body": "Фестиваль проходит в столице Татарстана с 2005 года. В программу фестиваля отбираются фильмы, отражающие общечеловеческие ценности и культурные традиции, несущие идеи веротерпимости и гуманизма вне зависимости от вероисповедания автора. Помимо основной, зрителей ожидает обширная внеконкурсная программа, которая представит зрителям лучшие образцы российского игрового, документального и анимационного кино, ретроспективные и тематические программы.",
|
||||||
|
"place": "г.Казань"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Казанский национальный полумарафон",
|
||||||
|
"body": "На полумарафоне традиционно проходят забеги на дистанциях в 3, 10, 21,1 км, а также детский старт TIMERKIDS для юных спортсменов в разных возрастных категориях. Старт и финиш организуются у стадиона «Ак Барс Арена».",
|
||||||
|
"place": "г.Казань"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Международный фестиваль современной музыки им. Софии Губайдулиной Concordia",
|
||||||
|
"month": "НОЯБРЬ",
|
||||||
|
"body": "Фестиваль проходит с 2011 года. Он носит имя известного российского композитора, автора более сотни симфонических произведений Софии Губайдуллиной. Главное направление фестиваля — современная музыка. Традиционно на фестивале звучат и творения самой Софии Губайдуллиной.",
|
||||||
|
"place": "г.Казань, Большой концертный зал имени Сайдашева"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "«КышДаКар-фест»",
|
||||||
|
"month": "ДЕКАБРЬ",
|
||||||
|
"body": "Новогодний фестиваль открывает свои двери в конце декабря и продолжает работу все новогодние праздники. Нарядные домики традиционно устанавливаются возле главной городской елки у Центра семьи «Казан». Все желающие могут попробовать необычные лакомства, оценить национальную кухню, приобрести сувениры и принять участие в кулинарных мастер-классах. На фестивале свою продукцию представляют индивидуальные предприниматели, самозанятые и фермеры из районов Татарстана.",
|
||||||
|
"place": "г.Казань"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
"Наиболее развитая сеть в городе – автобусная. Она обеспечивает беспересадочные перевозки пассажиров между всеми районами города.",
|
||||||
|
"Трамвайная и троллейбусная маршрутная сеть образует радиально-кольцевую систему. Трамвайным и троллейбусным транспортом обслуживаются все районы города.",
|
||||||
|
"Метрополитен г. Казани – современный, высококомфортабельный и скоростной вид транспорта. Поезда, оснащенные новейшими системами автоматики, позволяют на высоком уровне обслуживать пассажиров.",
|
||||||
|
"Казань также обладает различными туристическими объектами, такими как пешеходные улицы, парки и набережные, которые часто становятся популярными местами для прогулок и отдыха."
|
||||||
|
]
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
12,
|
||||||
|
13
|
||||||
|
]
|
||||||
@@ -0,0 +1,450 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"from": "Речной порт",
|
||||||
|
"to": "жилой массив Дербышки",
|
||||||
|
"route_length": "18,03 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:24. Отправление в последний рейс А — 22:32. Отправление в последний рейс Б — 21:27. Интервал движения: утро — 6,9 мин, вечер — 7,3 мин.",
|
||||||
|
"operating_mode_weekend": " В выходные: начало движения — 5:30. Отправление в последний рейс А — 22:44. Отправление в последний рейс Б — 21:55. Интервал движения 7,5 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"from": "Станция метро «Аметьево»",
|
||||||
|
"to": "ул.Привокзальная",
|
||||||
|
"route_length": "20,9 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:40. Отправление в последний рейс А — 21:54. Отправление в последний рейс Б — 21:01. Интервал движения 8,5 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:40. Отправление в последний рейс А — 21:34. Отправление в последний рейс Б — 20:32. Интервал движения 9 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4",
|
||||||
|
"from": "Жилой массив Ферма-2",
|
||||||
|
"to": "жилой массив Новая Сосновка",
|
||||||
|
"route_length": "24,59 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 21:02. Отправление в последний рейс Б — 20:50. Интервал движения 14,8 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 21:07. Отправление в последний рейс Б — 21:20. Интервал движения 22 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5",
|
||||||
|
"from": "ЦУМ",
|
||||||
|
"to": "ул.Халитова",
|
||||||
|
"route_length": "27,42 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:43. Отправление в последний рейс А — 22:05. Отправление в последний рейс Б — 20:45. Интервал движения: утро 6,7 мин, вечер 7 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:31. Отправление в последний рейс А — 22:15. Отправление в последний рейс Б — 21:03. Интервал движения 7,6 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6",
|
||||||
|
"from": "Речной порт",
|
||||||
|
"to": "жилой массив Северный",
|
||||||
|
"route_length": "20,9 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:00. Отправление в последний рейс А — 22:24. Отправление в последний рейс Б — 21:32. Интервал движения 7,8 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:45. Отправление в последний рейс А — 22:07. Отправление в последний рейс Б — 21:20. Интервал движения 8,4 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9",
|
||||||
|
"from": "Жилой массив Дербышки",
|
||||||
|
"to": "жилой массив Аки",
|
||||||
|
"route_length": "4,52 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 19:10. Отправление в последний рейс Б — 19:40.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 19:10. Отправление в последний рейс Б — 19:40."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "10",
|
||||||
|
"from": "Ул.Серова",
|
||||||
|
"to": "ул.Академика Губкина (кольцевой)",
|
||||||
|
"route_length": "15,3 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:20. Отправление в последний рейс А — 22:12. Отправление в последний рейс Б — 23:04. Интервал движения 5,7 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 22:30. Интервал движения 7,1 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "10a",
|
||||||
|
"from": "Ул.Серова",
|
||||||
|
"to": "ул.Академика Губкина (кольцевой)",
|
||||||
|
"route_length": "14,82 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:19. Отправление в последний рейс А — 21:52. Отправление в последний рейс Б — 22:23. Интервал движения 5,9 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 21:55. Отправление в последний рейс Б — 22:25. Интервал движения 7,2 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "11",
|
||||||
|
"from": "Жилой массив Дербышки",
|
||||||
|
"to": "жилой массив Малые Дербышки",
|
||||||
|
"route_length": "10,56 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 18:45. Отправление в последний рейс Б — 19:10.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 18:45. Отправление в последний рейс Б — 19:10."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "15",
|
||||||
|
"from": "Комбинат «Здоровье»",
|
||||||
|
"to": "ул.Адоратского",
|
||||||
|
"route_length": "10,38 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 22:51. Отправление в последний рейс Б — 22:22. Интервал движения 6 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 22:50. Отправление в последний рейс Б — 22:30. Интервал движения 7 мин.99"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "18",
|
||||||
|
"from": "Ул.Северополюсная",
|
||||||
|
"to": "переулок Дуслык",
|
||||||
|
"route_length": "31,41 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 4:50. Отправление в последний рейс А — 22:01. Отправление в последний рейс Б — 20:20. Интервал движения 8,5 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:40. Отправление в последний рейс А — 21:58. Отправление в последний рейс Б — 20:14. Интервал движения 10,2 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "22",
|
||||||
|
"from": "Ул.Можайского",
|
||||||
|
"to": "жилой массив Ферма-2",
|
||||||
|
"route_length": "24,45 км",
|
||||||
|
"operating_mode_weekdays": "5:30. Отправление в последний рейс А — 21:38. Отправление в последний рейс Б — 20:34. Интервал движения: утро 7,1 мин, вечер 7,4 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:40. Отправление в последний рейс А — 21:19. Отправление в последний рейс Б — 20:01. Интервал движения 10,1 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "23",
|
||||||
|
"from": "Ул.Р.Яхина",
|
||||||
|
"to": "жилой массив Мирный",
|
||||||
|
"route_length": "13,58 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:20. Отправление в последний рейс А — 22:11. Отправление в последний рейс Б — 21:40. Интервал движения: утро 12,9 мин, вечер 15,1 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:20. Отправление в последний рейс А — 21:05. Отправление в последний рейс Б — 21:13. Интервал движения 15 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "25",
|
||||||
|
"from": "Ул.Техническая",
|
||||||
|
"to": "жилой массив Дербышки",
|
||||||
|
"route_length": "20,66 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 19:30. Отправление в последний рейс Б — 18:30. Интервал движения 13,2 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:10. Отправление в последний рейс А — 18:10. Отправление в последний рейс Б — 17:50. Интервал движения 20 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "28",
|
||||||
|
"from": "ЦПКиО",
|
||||||
|
"to": "ул.Короленко (кольцевой)",
|
||||||
|
"route_length": "8,81 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 21:45. Отправление в последний рейс Б — 22:02. Интервал движения 7,6 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 21:38. Отправление в последний рейс Б — 22:01. Интервал движения 15 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "28a",
|
||||||
|
"from": "Чеховский рынок",
|
||||||
|
"to": "ул.Короленко (кольцевой)",
|
||||||
|
"route_length": "10,74 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 22:01. Интервал движения 8 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 22:01. Интервал движения 15 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "29",
|
||||||
|
"from": "Строительный институт",
|
||||||
|
"to": "ул.Гудованцева",
|
||||||
|
"route_length": "17,23 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 22:30. Отправление в последний рейс Б — 21:40. Интервал движения 7,2 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 22:30. Отправление в последний рейс Б — 21:40. Интервал движения 9,2 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "30",
|
||||||
|
"from": "Переулок Дуслык",
|
||||||
|
"to": "станция Лагерная",
|
||||||
|
"route_length": "27,05 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 4:38. Отправление в последний рейс А — 21:24. Отправление в последний рейс Б — 22:40. Интервал движения: утро 6,6 мин, вечер 6,8 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:01. Отправление в последний рейс А — 20:56. Отправление в последний рейс Б — 22:18. Интервал движения 8,1 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "31",
|
||||||
|
"from": "Магазин «IKEA»",
|
||||||
|
"to": "жилой массив Старое Победилово",
|
||||||
|
"route_length": "29,48 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:15. Отправление в последний рейс А — 22:10. Отправление в последний рейс Б — 21:46. Интервал движения: утро 6,6 мин, вечер 6,8 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 22:10. Отправление в последний рейс Б — 21:51. Интервал движения 8 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "33",
|
||||||
|
"from": "Ул.Ленинградская",
|
||||||
|
"to": "жилой массив Ферма-2",
|
||||||
|
"route_length": "99999",
|
||||||
|
"operating_mode_weekdays": "88888",
|
||||||
|
"operating_mode_weekend": "99999"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "34",
|
||||||
|
"from": "Жилой массив Ферма-2",
|
||||||
|
"to": "ДК им.Саид-Галеева",
|
||||||
|
"route_length": "25,39 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:25. Отправление в последний рейс А — 18:51. Отправление в последний рейс Б — 19:59. Интервал движения 14,8 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 17:44. Отправление в последний рейс Б — 18:48. Интервал движения 17,5 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "35",
|
||||||
|
"from": "Станция метро «Площадь Г.Тукая»",
|
||||||
|
"to": "ул.Гаврилова (кольцевой)",
|
||||||
|
"route_length": "14,33 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 22:26. Отправление в последний рейс Б — 21:35. Интервал движения 7 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 22:15. Отправление в последний рейс Б — 21:21. Интервал движения 9,4 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "35a",
|
||||||
|
"from": "Станция метро «Площадь Г.Тукая»",
|
||||||
|
"to": "Авторынок (кольцевой)",
|
||||||
|
"route_length": "14,06 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 22:37. Отправление в последний рейс Б — 21:45. Интервал движения утро 6,4 мин, вечер 6,9 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 22:20. Отправление в последний рейс Б — 21:30. Интервал движения 9 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "36",
|
||||||
|
"from": "Вещевой рынок",
|
||||||
|
"to": "Осиново",
|
||||||
|
"route_length": "29,9 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:14. Отправление в последний рейс А — 21:42. Отправление в последний рейс Б — 20:28. Интервал движения: утро 6,8 мин, вечер 7,1 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 21:41. Отправление в последний рейс Б — 20:21. Интервал движения 11 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "36a",
|
||||||
|
"from": "Жилой массив Залесный",
|
||||||
|
"to": "Новониколаевский",
|
||||||
|
"route_length": "14,98 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 19:00. Отправление в последний рейс Б — 19:15.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 19:00. Отправление в последний рейс Б — 19:15."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "37",
|
||||||
|
"from": "Жилой массив Ферма-2",
|
||||||
|
"to": "жилой массив Сухая Река",
|
||||||
|
"route_length": "30,26 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 4:58. Отправление в последний рейс А — 21:47. Отправление в последний рейс Б — 21:32. Интервал движения 10 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 21:48. Отправление в последний рейс Б — 20:54. Интервал движения 13,7 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "40",
|
||||||
|
"from": "Ул.Гаврилова",
|
||||||
|
"to": "кафе «Ак Барс»",
|
||||||
|
"route_length": "19,5 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 20:00. Отправление в последний рейс Б — 20:55.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 20:00. Отправление в последний рейс Б — 20:00."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "42",
|
||||||
|
"from": "КДК им.Ленина",
|
||||||
|
"to": "жилой массив Борисоглебское",
|
||||||
|
"route_length": "8,56 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 19:10. Отправление в последний рейс Б -19:40.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 19:10. Отправление в последний рейс Б 19:40."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "43",
|
||||||
|
"from": "Ул. Химическая",
|
||||||
|
"to": "ул.Техническая",
|
||||||
|
"route_length": "27,37 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:00. Отправление в последний рейс А — 21:45. Отправление в последний рейс Б — 21:45. Интервал движения 7,9 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:12. Отправление в последний рейс А — 20:32. Отправление в последний рейс Б — 22:02. Интервал движения 11,3 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "45",
|
||||||
|
"from": "Жилой массив Ферма-2",
|
||||||
|
"to": "Су Анасы",
|
||||||
|
"route_length": "39,28 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 4:57. Отправление в последний рейс А — 22:01. Отправление в последний рейс Б — 22:17. Интервал движения утро 7,1 мин, вечер 7,9 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:00. Отправление в последний рейс А — 21:46. Отправление в последний рейс Б — 22:00. Интервал движения 7,6 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "46",
|
||||||
|
"from": "Жилой комплекс «Экопарк „Дубрава“»",
|
||||||
|
"to": "Профилакторий",
|
||||||
|
"route_length": "41,42 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:20. Отправление в последний рейс А — 22:19. Отправление в последний рейс Б — 21:46. Интервал движения 7,1 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:45. Отправление в последний рейс А — 22:01. Отправление в последний рейс Б — 22:01. Интервал движения 8,1 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "47",
|
||||||
|
"from": "Ул.Батыршина",
|
||||||
|
"to": "Деревня Универсиады",
|
||||||
|
"route_length": "20,67 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 21:48. Отправление в последний рейс Б — 22:51. Интервал движения 6,6 мин",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 21:18. Отправление в последний рейс Б — 22:20. Интервал движения 8,2 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "49",
|
||||||
|
"from": "Вещевой рынок",
|
||||||
|
"to": "станция Лагерная",
|
||||||
|
"route_length": "21,52 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 20:48. Отправление в последний рейс Б — 19:48. Интервал движения утро 8,3 мин, вечер 8,9 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 20:43. Отправление в последний рейс Б — 19:50. Интервал движения 11,4 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "53",
|
||||||
|
"from": "Речной порт",
|
||||||
|
"to": "ул.Ленинградская",
|
||||||
|
"route_length": "16,73 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 22:10. Отправление в последний рейс Б — 21:14. Интервал движения 9,1 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:20. Отправление в последний рейс А — 21:41. Отправление в последний рейс Б — 20:47. Интервал движения 12,4 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "54",
|
||||||
|
"from": "Речной порт",
|
||||||
|
"to": "ул.Гаврилова",
|
||||||
|
"route_length": "13,14 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 22:26. Отправление в последний рейс Б — 21:41. Интервал движения 5,6 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 22:20. Отправление в последний рейс Б — 21:35. Интервал движения 9,1 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "55",
|
||||||
|
"from": "39-й квартал",
|
||||||
|
"to": "жилой комплекс «Лесной городок»",
|
||||||
|
"route_length": "22,22 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:35. Отправление в последний рейс А — 22:02. Отправление в последний рейс Б — 22:22. Интервал движения 8,7 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 22:02. Отправление в последний рейс Б — 22:02. Интервал движения 15 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "56",
|
||||||
|
"from": "Ул.Р.Яхина",
|
||||||
|
"to": "жилой массив Петровский",
|
||||||
|
"route_length": "17,10 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:40. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 20:46.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:50. Отправление в последний рейс А — 18:11. Отправление в последний рейс Б — 19:05."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "60",
|
||||||
|
"from": "Ул. Химическая",
|
||||||
|
"to": "жилой массив Дербышки",
|
||||||
|
"route_length": "26,62 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:15. Отправление в последний рейс А — 22:15. Отправление в последний рейс Б — 21:08. Интервал движения утро 7,7 мин, вечер 8,5 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:15. Отправление в последний рейс А — 21:55. Отправление в последний рейс Б — 20:43. Интервал движения 8,2 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "62",
|
||||||
|
"from": "ДВВС",
|
||||||
|
"to": "жилой комплекс «Салават Купере»",
|
||||||
|
"route_length": "29,33 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:00. Отправление в последний рейс А — 21:00. Отправление в последний рейс Б — 21:19. Интервал движения 12,5 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 21:06. Отправление в последний рейс Б — 20:06. Интервал движения 12 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "63",
|
||||||
|
"from": "Ул.Комиссара Габишева",
|
||||||
|
"to": "жилой массив Левченко",
|
||||||
|
"route_length": "30,90 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:45. Отправление в последний рейс А — 21:20. Отправление в последний рейс Б — 22:41. Интервал движения 8,6 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 20:56. Отправление в последний рейс Б — 22:26. Интервал движения 11,5 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "68",
|
||||||
|
"from": "Ж/д вокзал",
|
||||||
|
"to": "ул.Иман",
|
||||||
|
"route_length": "20,87 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:00. Отправление в последний рейс А — 21:47. Отправление в последний рейс Б — 20:46. Интервал движения 10 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:00. Отправление в последний рейс А — 21:14. Отправление в последний рейс Б — 20:15. Интервал движения 12,5 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "70",
|
||||||
|
"from": "Чеховский рынок",
|
||||||
|
"to": "жилой комплекс «Весна»",
|
||||||
|
"route_length": "11,09 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:50. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 21:00.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:50. Отправление в последний рейс А — 21:21. Отправление в последний рейс Б — 20:39."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "71",
|
||||||
|
"from": "Городская клиническая больница №5",
|
||||||
|
"to": "жилой массив Константиновка",
|
||||||
|
"route_length": "17,29 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 21:35. Отправление в последний рейс Б — 20:53.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 20:45."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "72",
|
||||||
|
"from": "Площадь Вахитова",
|
||||||
|
"to": "Профилакторий",
|
||||||
|
"route_length": "27,33 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:40. Отправление в последний рейс А — 22:25. Отправление в последний рейс Б — 21:59.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:10. Отправление в последний рейс А — 20:45. Отправление в последний рейс Б — 20:14."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "74",
|
||||||
|
"from": "ДВВС",
|
||||||
|
"to": "10-й микрорайон",
|
||||||
|
"route_length": "22,39 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 21:47. Отправление в последний рейс Б — 20:45.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 21:40. Отправление в последний рейс Б — 20:38."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "75",
|
||||||
|
"from": "Комбинат «Здоровье»",
|
||||||
|
"to": "Универсам-2",
|
||||||
|
"route_length": "11,60 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:40. Отправление в последний рейс А — 22:25. Отправление в последний рейс Б — 21:59.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:10. Отправление в последний рейс А — 20:45. Отправление в последний рейс Б — 20:14."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "77",
|
||||||
|
"from": "Переулок Дуслык",
|
||||||
|
"to": "Нефтебаза",
|
||||||
|
"route_length": "28,10 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 4:45. Отправление в последний рейс А — 19:23. Отправление в последний рейс Б — 20:20.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:00. Отправление в последний рейс А — 19:03. Отправление в последний рейс Б — 20:22."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "78",
|
||||||
|
"from": "Ул.Волгоградская",
|
||||||
|
"to": "жилой массив Крутушка",
|
||||||
|
"route_length": " 18,74 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 19:35. Отправление в последний рейс Б — 20:20.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 19:35. Отправление в последний рейс Б — 20:20."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "84",
|
||||||
|
"from": "Ул. Халитова",
|
||||||
|
"to": "жилой массив Чебакса",
|
||||||
|
"route_length": "15,32 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:15. Отправление в последний рейс А — 17:10. Отправление в последний рейс Б — 18:00.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:15. Отправление в последний рейс А — 17:10. Отправление в последний рейс Б — 18:00."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "84a",
|
||||||
|
"from": "Ул. Халитова",
|
||||||
|
"to": "жилой массив Чебакса",
|
||||||
|
"route_length": "17,48 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:15. Отправление в последний рейс А — 17:10. Отправление в последний рейс Б — 18:00.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:15. Отправление в последний рейс А — 17:10. Отправление в последний рейс Б — 18:00."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "88",
|
||||||
|
"from": "Жилой массив Дербышки",
|
||||||
|
"to": "жилой массив Кульсеитово",
|
||||||
|
"route_length": "9,69 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 22:05. Отправление в последний рейс Б — 20:57. Интервал движения утро 7,4 мин, вечер 7,7 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 20:00. Интервал движения 9,4 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "89",
|
||||||
|
"from": "Ул.Академика Сахарова",
|
||||||
|
"to": "ул.Гудованцева",
|
||||||
|
"route_length": "27,98 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:18. Отправление в последний рейс А — 22:13. Отправление в последний рейс Б — 21:04. Интервал движения 7,3 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 22:11. Отправление в последний рейс Б — 20:40. Интервал движения 9,1 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "90",
|
||||||
|
"from": "Станция метро «Площадь Г.Тукая»",
|
||||||
|
"to": "Куюки",
|
||||||
|
"route_length": "22,02 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 21:10. Отправление в последний рейс Б — 20:13. Интервал движения 13,8 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:45. Отправление в последний рейс А — 21:10. Отправление в последний рейс Б — 20:04. Интервал движения 19 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "91",
|
||||||
|
"from": "ЦУМ",
|
||||||
|
"to": "Высокая Гора (АРЗ)",
|
||||||
|
"route_length": "26,71 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 5:30. Отправление в последний рейс А — 22:05. Отправление в последний рейс Б — 20:57. Интервал движения утро 7,4 мин, вечер 7,7 мин.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 5:30. Отправление в последний рейс А — 21:30. Отправление в последний рейс Б — 20:00. Интервал движения 9,4 мин."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "93",
|
||||||
|
"from": "КДК им.Ленина",
|
||||||
|
"to": "н.п.Берновые Ковали",
|
||||||
|
"route_length": "21,20 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 18:10. Отправление в последний рейс Б — 18:55.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 16:30. Отправление в последний рейс Б — 17:15."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "94",
|
||||||
|
"from": "остановка Дубравная",
|
||||||
|
"to": "жилой массив Привольный",
|
||||||
|
"route_length": "6,65 км",
|
||||||
|
"operating_mode_weekdays": "Будни: начало движения — 6:00. Отправление в последний рейс А — 19:30. Отправление в последний рейс Б — 20:00.",
|
||||||
|
"operating_mode_weekend": "В выходные: начало движения — 6:00. Отправление в последний рейс А — 19:30. Отправление в последний рейс Б — 20:00."
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "Kamila",
|
||||||
|
"email": "kamila@gmail.com",
|
||||||
|
"password": "qwerty"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Liliya",
|
||||||
|
"email": "liliya@mail.ru",
|
||||||
|
"password": "12121"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Guzel",
|
||||||
|
"email": "guzel@gmail.com",
|
||||||
|
"password": "12345"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Labeyrie",
|
||||||
|
"email": "superlu@unics.ru",
|
||||||
|
"password": "qwertyqwe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ismael Bako",
|
||||||
|
"email": "bako@unics.ru",
|
||||||
|
"password": "21"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"description": "1000 часто используемых",
|
||||||
|
"imageFilename": "kart1.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"description": "10 слов в Data Science",
|
||||||
|
"imageFilename": "kart1.jpg"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"words": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"word": "Tech",
|
||||||
|
"definition": "short for technical, relating to the knowledge, machines, or methods used in science and industry. Tech is a whole industry, which includes IT",
|
||||||
|
"examples": [
|
||||||
|
"“As a DevOps engineer I have been working in Tech since 2020.”"
|
||||||
|
],
|
||||||
|
"synonyms": ["IT"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"word": "career path",
|
||||||
|
"definition": "the series of jobs or roles that constitute a person's career, especially one in a particular field",
|
||||||
|
"examples": [
|
||||||
|
"“Technology is an evolving field with a variety of available career paths.”"
|
||||||
|
],
|
||||||
|
"synonyms": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"words": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"word": "Machine Learning",
|
||||||
|
"translation": "Машинное обучение",
|
||||||
|
"definition": "An approach to artificial intelligence where computers learn from data without being explicitly programmed.",
|
||||||
|
"synonyms": ["Trainable Algorithms", "Automated Learning"],
|
||||||
|
"examples": [
|
||||||
|
"We used machine learning techniques to forecast product demand.",
|
||||||
|
"The movie recommendation system is based on machine learning algorithms.",
|
||||||
|
"Machine learning helped improve the accuracy of speech recognition in our application."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"word": "Neural Network",
|
||||||
|
"translation": "Нейронная сеть",
|
||||||
|
"definition": "A mathematical model inspired by the structure and function of biological neural networks, consisting of interconnected nodes organized in layers that can process information.",
|
||||||
|
"synonyms": ["Artificial Neural Network", "Deep Neural Network"],
|
||||||
|
"examples": [
|
||||||
|
"To process large amounts of data, we created a deep learning neural network.",
|
||||||
|
"This neural network is capable of generating realistic images.",
|
||||||
|
"Using neural networks significantly improved the quality of text translation."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"word": "Algorithm",
|
||||||
|
"translation": "Алгоритм",
|
||||||
|
"definition": "A step-by-step procedure or set of instructions for solving a problem or performing a computation.",
|
||||||
|
"synonyms": ["Procedure", "Method"],
|
||||||
|
"examples": [
|
||||||
|
"The algorithm we developed quickly finds the optimal delivery route.",
|
||||||
|
"This algorithm sorts an array with a minimal number of operations.",
|
||||||
|
"Encryption algorithms ensure secure transmission of data over the internet."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"word": "Data Model",
|
||||||
|
"translation": "Модель данных",
|
||||||
|
"definition": "An abstract representation of the structure of data, describing how data is organized and related to each other.",
|
||||||
|
"synonyms": ["Data Structure", "Schema"],
|
||||||
|
"examples": [
|
||||||
|
"Our data model allows us to efficiently manage relationships between customers and orders.",
|
||||||
|
"The data model was designed considering scalability and performance requirements.",
|
||||||
|
"This data model is used for storing information about social network users."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"word": "Regression",
|
||||||
|
"translation": "Регрессия",
|
||||||
|
"definition": "A statistical method used to determine the relationship between one variable and others.",
|
||||||
|
"synonyms": ["Linear Regression", "Nonlinear Regression"],
|
||||||
|
"examples": [
|
||||||
|
"We applied linear regression to analyze the impact of advertising campaigns on sales.",
|
||||||
|
"Results from the regression analysis showed a strong correlation between customer age and purchase frequency.",
|
||||||
|
"Regression helped us assess how changes in environmental conditions affect crop yield."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"word": "Clustering",
|
||||||
|
"translation": "Кластеризация",
|
||||||
|
"definition": "The process of grouping similar objects into clusters so that objects within the same cluster are more similar to each other than to those in other clusters.",
|
||||||
|
"synonyms": ["Grouping", "Segmentation"],
|
||||||
|
"examples": [
|
||||||
|
"Clustering allowed us to divide customers into several groups according to their purchasing behavior.",
|
||||||
|
"Clustering methods are used to automatically group news by topic.",
|
||||||
|
"As a result of clustering, several market segments were identified, each with its own characteristics."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"word": "Supervised Learning",
|
||||||
|
"translation": "Обучение с учителем",
|
||||||
|
"definition": "A type of machine learning where the algorithm learns from labeled data, meaning data for which correct answers are known.",
|
||||||
|
"synonyms": ["Controlled Learning", "Labeled Classification"],
|
||||||
|
"examples": [
|
||||||
|
"Supervised learning is used to classify emails as spam or not-spam.",
|
||||||
|
"This approach was used to create a model that predicts real estate prices based on multiple parameters.",
|
||||||
|
"Supervised learning helps diagnose diseases at early stages through medical data analysis."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"word": "Data Labeling",
|
||||||
|
"translation": "Разметка данных",
|
||||||
|
"definition": "The process of assigning labels or classes to data so it can be used in supervised learning.",
|
||||||
|
"synonyms": ["Data Annotation", "Tagging"],
|
||||||
|
"examples": [
|
||||||
|
"Before starting model training, we labeled the data by assigning each photo an animal category.",
|
||||||
|
"Data labeling includes marking user reviews as positive or negative.",
|
||||||
|
"Text documents were labeled with special tags for subsequent analysis."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"word": "Hyperparameters",
|
||||||
|
"translation": "Гиперпараметры",
|
||||||
|
"definition": "Parameters that define the structure and behavior of a machine learning model, set before the learning process begins.",
|
||||||
|
"synonyms": ["Model Settings", "Configuration Parameters"],
|
||||||
|
"examples": [
|
||||||
|
"Optimizing hyperparameters enabled us to enhance the performance of our machine learning model.",
|
||||||
|
"Hyperparameters include settings such as the number of layers in a neural network and the learning rate.",
|
||||||
|
"Choosing the right hyperparameters is crucial for achieving high model accuracy."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"word": "Model Validation",
|
||||||
|
"translation": "Валидация модели",
|
||||||
|
"definition": "The process of evaluating the quality of a model by testing it on new, previously unseen data.",
|
||||||
|
"synonyms": ["Model Testing", "Model Verification"],
|
||||||
|
"examples": [
|
||||||
|
"After completing the training, we validated the model using a test dataset.",
|
||||||
|
"During model validation, its ability to make accurate predictions on new data is checked.",
|
||||||
|
"Validation showed that the model is robust against changes in data and has low generalization error."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
const router = require("express").Router();
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
||||||
|
const data = require("./data/dictionaries.json");
|
||||||
|
const wordsData = require("./data/dictionaryWords.json");
|
||||||
|
|
||||||
|
router.get("/", (req, res) => {
|
||||||
|
res.send(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/:id", (req, res) => {
|
||||||
|
const id = parseInt(req.params.id);
|
||||||
|
const words = wordsData.find((word) => word.id === id);
|
||||||
|
|
||||||
|
if (!words) {
|
||||||
|
return res.status(404).send("Not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send(words);
|
||||||
|
});
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
const router = require("express").Router();
|
||||||
|
|
||||||
|
const dictionariesRouter = require("./dictionaries");
|
||||||
|
module.exports = router;
|
||||||
|
|
||||||
|
const delay =
|
||||||
|
(ms = 1000) =>
|
||||||
|
(req, res, next) => {
|
||||||
|
setTimeout(next, ms);
|
||||||
|
};
|
||||||
|
|
||||||
|
router.use(delay());
|
||||||
|
router.use("/dictionaries", dictionariesRouter);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
const { Router } = require('express')
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
router.use('/eng-it-lean', require('./eng-it-lean/index'))
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,7 +1,7 @@
|
|||||||
const ObjectId = require('mongodb').ObjectID
|
const ObjectId = require('mongodb').ObjectID
|
||||||
const getHash = require('pbkdf2-password')()
|
const getHash = require('pbkdf2-password')()
|
||||||
|
|
||||||
const { getDB } = require('../../utils/mongo')
|
const { getDB } = require('../../../utils/mongo')
|
||||||
|
|
||||||
const USERS_COLLECTION = 'users'
|
const USERS_COLLECTION = 'users'
|
||||||
const LISTS_COLLECTION = 'lists'
|
const LISTS_COLLECTION = 'lists'
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 1330 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user