Záznamy v UI
This commit is contained in:
260
package-lock.json
generated
260
package-lock.json
generated
@@ -11,7 +11,6 @@
|
||||
"dependencies": {
|
||||
"@kitajs/html": "^4.2.13",
|
||||
"@kitajs/ts-html-plugin": "^4.1.4",
|
||||
"@logdna/tail-file": "^4.0.2",
|
||||
"@minify-html/node": "^0.18.1",
|
||||
"apache-crypt": "^1.2.6",
|
||||
"async-mutex": "^0.5.0",
|
||||
@@ -30,6 +29,7 @@
|
||||
"postgres-migrations": "^5.3.0",
|
||||
"prettier": "^3.8.1",
|
||||
"read": "^5.0.1",
|
||||
"read-last-lines": "^1.8.0",
|
||||
"sass": "^1.98.0",
|
||||
"sharp": "^0.34.5",
|
||||
"superjson": "^2.2.6",
|
||||
@@ -96,16 +96,6 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/cli/node_modules/slash": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
||||
@@ -162,16 +152,6 @@
|
||||
"url": "https://opencollective.com/babel"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.29.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
|
||||
@@ -219,16 +199,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz",
|
||||
@@ -251,16 +221,6 @@
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-regexp-features-plugin": {
|
||||
"version": "7.28.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz",
|
||||
@@ -279,16 +239,6 @@
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-define-polyfill-provider": {
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz",
|
||||
@@ -1597,16 +1547,6 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-modules": {
|
||||
"version": "0.1.6-no-external-plugins",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
|
||||
@@ -2961,15 +2901,6 @@
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@logdna/tail-file": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@logdna/tail-file/-/tail-file-4.0.2.tgz",
|
||||
"integrity": "sha512-aEZF3LanJoewsQ9J1CRk5wvOqvQvw4lhxitSMXz3sQPgfezamzwW+pGvKXxvht7EvJEYSlYPxfSjL6T2bDSEkg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@minify-html/node": {
|
||||
"version": "0.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@minify-html/node/-/node-0.18.1.tgz",
|
||||
@@ -3898,6 +3829,19 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz",
|
||||
@@ -4026,6 +3970,12 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
@@ -4119,16 +4069,6 @@
|
||||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs3": {
|
||||
"version": "0.14.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz",
|
||||
@@ -4164,9 +4104,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.19",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz",
|
||||
"integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==",
|
||||
"version": "2.10.20",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz",
|
||||
"integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -4675,9 +4615,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.339",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.339.tgz",
|
||||
"integrity": "sha512-Is+0BBHJ4NrdpAYiperrmp53pLywG/yV/6lIMTAnhxvzj/Cmn5Q/ogSHC6AKe7X+8kPLxxFk0cs5oc/3j/fxIg==",
|
||||
"version": "1.5.340",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz",
|
||||
"integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -5543,9 +5483,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
|
||||
"integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
@@ -5889,9 +5829,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
||||
"integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
|
||||
"integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5923,6 +5863,18 @@
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
|
||||
@@ -6089,16 +6041,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/pify": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir/node_modules/semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
@@ -6195,6 +6137,17 @@
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0",
|
||||
"object-assign": "^4.0.1",
|
||||
"thenify-all": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
@@ -6296,6 +6249,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
@@ -6579,13 +6541,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
@@ -6695,6 +6657,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/postcss-cli/node_modules/slash": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
|
||||
"integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-cli/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
@@ -7101,6 +7076,25 @@
|
||||
"pify": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache/node_modules/pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/read-last-lines": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/read-last-lines/-/read-last-lines-1.8.0.tgz",
|
||||
"integrity": "sha512-oPL0cnZkhsO2xF7DBrdzVhXSNajPP5TzzCim/2IAjeGb17ArLLTRriI/ceV6Rook3L27mvbrOvLlf9xYYnaftQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mz": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
@@ -7316,15 +7310,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
@@ -7422,6 +7414,18 @@
|
||||
"@img/sharp-win32-x64": "0.34.5"
|
||||
}
|
||||
},
|
||||
"node_modules/sharp/node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -7541,16 +7545,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
|
||||
"integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
|
||||
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
@@ -7680,6 +7681,27 @@
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/thenify": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/thenify-all": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
||||
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"thenify": ">= 3.1.0 < 4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/timestring": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/timestring/-/timestring-7.0.0.tgz",
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
"dependencies": {
|
||||
"@kitajs/html": "^4.2.13",
|
||||
"@kitajs/ts-html-plugin": "^4.1.4",
|
||||
"@logdna/tail-file": "^4.0.2",
|
||||
"@minify-html/node": "^0.18.1",
|
||||
"apache-crypt": "^1.2.6",
|
||||
"async-mutex": "^0.5.0",
|
||||
@@ -75,6 +74,7 @@
|
||||
"postgres-migrations": "^5.3.0",
|
||||
"prettier": "^3.8.1",
|
||||
"read": "^5.0.1",
|
||||
"read-last-lines": "^1.8.0",
|
||||
"sass": "^1.98.0",
|
||||
"sharp": "^0.34.5",
|
||||
"superjson": "^2.2.6",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { loadConfig } from "../src/config.js";
|
||||
import { initDb, postgres } from "../src/db/client.js";
|
||||
import { createUser } from "../src/db/user.js";
|
||||
import { czchanLog } from "../src/lib/logger.js";
|
||||
import { czchanLog } from "../src/lib/log.js";
|
||||
import bcrypt from "bcrypt";
|
||||
import { read } from "read";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { czchanLog } from "../src/lib/logger.js";
|
||||
import { czchanLog } from "../src/lib/log.js";
|
||||
import { readdir, mkdir, writeFile } from "fs/promises";
|
||||
import { parse } from "path";
|
||||
|
||||
@@ -16,7 +16,7 @@ await (async () => {
|
||||
await czchanLog(
|
||||
"build",
|
||||
"info",
|
||||
`Kód ${statusCode}: nalezeno ${images.length} obrázků `,
|
||||
`Nalezeny obrázky pro kód ${statusCode}: celkem ${images.length} `,
|
||||
);
|
||||
|
||||
errorImages[statusCode] = images.sort();
|
||||
|
||||
@@ -9,7 +9,7 @@ import { cachePost } from "./db/cache/post.js";
|
||||
import { cacheRestriction } from "./db/cache/restriction.js";
|
||||
import { cacheUser } from "./db/cache/user.js";
|
||||
import { postgres } from "./db/client.js";
|
||||
import { czchanLog } from "./lib/logger.js";
|
||||
import { czchanLog } from "./lib/log.js";
|
||||
import type {
|
||||
User,
|
||||
Banner,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CzchanConfig } from "../config.js";
|
||||
import { czchanLog } from "../lib/logger.js";
|
||||
import { czchanLog } from "../lib/log.js";
|
||||
import { Pool } from "pg";
|
||||
import { migrate } from "postgres-migrations";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readAllBans } from "../db/ban.js";
|
||||
import { createCIDRIndex, createIndexedCIDR } from "./cidr.js";
|
||||
import { czchanLog } from "./logger.js";
|
||||
import { czchanLog } from "./log.js";
|
||||
import { randomUUID } from "crypto";
|
||||
import { readdir, readFile } from "fs/promises";
|
||||
import ipaddr from "ipaddr.js";
|
||||
|
||||
106
src/lib/log.ts
Normal file
106
src/lib/log.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { CzchanError } from "./error.js";
|
||||
import { appendFile, readdir, stat } from "node:fs/promises";
|
||||
import { join, parse } from "node:path";
|
||||
import readLastLines from "read-last-lines";
|
||||
|
||||
type Log = {
|
||||
name: string;
|
||||
created: Date;
|
||||
modified: Date;
|
||||
size: number;
|
||||
};
|
||||
|
||||
type LogLine = {
|
||||
timestamp: Date;
|
||||
log: string;
|
||||
level: "info" | "warn" | "error";
|
||||
message: string;
|
||||
actor: string;
|
||||
};
|
||||
|
||||
const czchanLog = async (
|
||||
log: string,
|
||||
level: "info" | "warn" | "error",
|
||||
message: string,
|
||||
actor?: string,
|
||||
) => {
|
||||
const now = new Date();
|
||||
const timestamp = now.getTime();
|
||||
|
||||
const consoleLogLine = `[${now.toISOString()}] [${level}] [${log}] (${actor ?? "system"}) ${message}`;
|
||||
const fileLogLine = `${JSON.stringify({
|
||||
timestamp,
|
||||
log,
|
||||
level,
|
||||
message,
|
||||
actor: actor ?? "system",
|
||||
})}\n`;
|
||||
|
||||
switch (level) {
|
||||
case "info":
|
||||
console.info(consoleLogLine);
|
||||
break;
|
||||
case "warn":
|
||||
console.warn(consoleLogLine);
|
||||
break;
|
||||
case "error":
|
||||
console.error(consoleLogLine);
|
||||
break;
|
||||
}
|
||||
|
||||
await appendFile(join("logs", `${log}.jsonl`), fileLogLine);
|
||||
await appendFile(join("logs", `all.jsonl`), fileLogLine);
|
||||
};
|
||||
|
||||
const readLogs = async () => {
|
||||
const result = [];
|
||||
const logs = (await readdir("logs")).map((log) => parse(log).name).sort();
|
||||
|
||||
for (const log of logs) {
|
||||
const stats = await stat(join("logs", `${log}.jsonl`));
|
||||
const name = log;
|
||||
const created = stats.birthtime;
|
||||
const modified = stats.mtime;
|
||||
const size = stats.size;
|
||||
|
||||
result.push({ name, created, modified, size });
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const readLogPage = async (log: string, page: number): Promise<LogLine[]> => {
|
||||
const limit = 100;
|
||||
const offset = page * limit;
|
||||
|
||||
let lines: string;
|
||||
|
||||
try {
|
||||
lines = await readLastLines.read(
|
||||
join("logs", `${log}.jsonl`),
|
||||
offset + limit,
|
||||
);
|
||||
} catch (_) {
|
||||
throw new CzchanError(`Záznam ${log} neexistuje.`, 404);
|
||||
}
|
||||
|
||||
const splitLines = lines.split(/\r\n|\r|\n/g).filter(Boolean);
|
||||
const end = Math.min(splitLines.length, splitLines.length - offset + limit);
|
||||
|
||||
if (end <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return splitLines
|
||||
.slice(-end)
|
||||
.slice(-limit)
|
||||
.map((line) => {
|
||||
const entry = JSON.parse(line);
|
||||
entry.timestamp = new Date(entry.timestamp);
|
||||
return entry as LogLine;
|
||||
})
|
||||
.reverse();
|
||||
};
|
||||
|
||||
export type { Log, LogLine };
|
||||
export { czchanLog, readLogs, readLogPage };
|
||||
@@ -1,30 +0,0 @@
|
||||
import { appendFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
const czchanLog = async (
|
||||
log: string,
|
||||
level: "info" | "warn" | "error",
|
||||
message: string,
|
||||
actor?: string,
|
||||
) => {
|
||||
const now = new Date();
|
||||
const consoleLogLine = `[${now.toISOString()}] [${level}] [${log}] (${actor ?? "system"}) ${message}`;
|
||||
const fileLogLine = `${now.getTime()},${log},${level},${message},${actor ?? "system"}\n`;
|
||||
|
||||
switch (level) {
|
||||
case "info":
|
||||
console.info(consoleLogLine);
|
||||
break;
|
||||
case "warn":
|
||||
console.warn(consoleLogLine);
|
||||
break;
|
||||
case "error":
|
||||
console.error(consoleLogLine);
|
||||
break;
|
||||
}
|
||||
|
||||
await appendFile(join("logs", `${log}.csv`), fileLogLine);
|
||||
await appendFile(join("logs", `all.csv`), fileLogLine);
|
||||
};
|
||||
|
||||
export { czchanLog };
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redis } from "../cache.js";
|
||||
import { czchanLog } from "./logger.js";
|
||||
import { czchanLog } from "./log.js";
|
||||
import minifyHTML from "@minify-html/node";
|
||||
import { readdir, readFile } from "node:fs/promises";
|
||||
import { join, parse } from "node:path";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { redis } from "../cache.js";
|
||||
import { createBan, readBans } from "../db/ban.js";
|
||||
import { rectifyCIDR } from "./ip.js";
|
||||
import { czchanLog } from "./logger.js";
|
||||
import { czchanLog } from "./log.js";
|
||||
import { randomUUID } from "crypto";
|
||||
import ipaddr from "ipaddr.js";
|
||||
import SuperJSON from "superjson";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { loadConfig } from "./config.js";
|
||||
import { initDb } from "./db/client.js";
|
||||
import { CzchanError } from "./lib/error.js";
|
||||
import { initIPLists } from "./lib/ip.js";
|
||||
import { czchanLog } from "./lib/logger.js";
|
||||
import { czchanLog } from "./lib/log.js";
|
||||
import { initPages } from "./lib/page.js";
|
||||
import { pruneBans } from "./tasks/prune_bans.js";
|
||||
import { pruneCaptchas } from "./tasks/prune_captchas.js";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { deleteBan } from "../db/ban.js";
|
||||
import { postgres } from "../db/client.js";
|
||||
import { czchanLog } from "../lib/logger.js";
|
||||
import { czchanLog } from "../lib/log.js";
|
||||
import type { Ban } from "../schema/tables.js";
|
||||
|
||||
const pruneBans = async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redis } from "../cache.js";
|
||||
import { czchanLog } from "../lib/logger.js";
|
||||
import { czchanLog } from "../lib/log.js";
|
||||
import { readdir, unlink } from "fs/promises";
|
||||
import { join, parse } from "path";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
removeUsageFromArray,
|
||||
} from "../db/file_record.js";
|
||||
import { readPosts } from "../db/post.js";
|
||||
import { czchanLog } from "../lib/logger.js";
|
||||
import { czchanLog } from "../lib/log.js";
|
||||
import { bytesToSize } from "../lib/util.js";
|
||||
import type { Banner, Post } from "../schema/tables.js";
|
||||
import { unlink } from "fs/promises";
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
updatePostLooped,
|
||||
} from "../../../db/post.js";
|
||||
import { CzchanError } from "../../../lib/error.js";
|
||||
import { czchanLog } from "../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../lib/permissions.js";
|
||||
import type { Board, Post } from "../../../schema/tables.js";
|
||||
import { ZPostActionsForm } from "../../../schema/validation/post.js";
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
updateBanAppealResponse,
|
||||
} from "../../../../db/ban.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import type { Ban } from "../../../../schema/tables.js";
|
||||
import { BanActionsForm } from "../../../../schema/validation/ban.js";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { deleteBanner, readBanners } from "../../../../db/banner.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import type { Banner } from "../../../../schema/tables.js";
|
||||
import { BannerActionsForm } from "../../../../schema/validation/banner.js";
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
updateBoardName,
|
||||
} from "../../../../db/board.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import type { Board } from "../../../../schema/tables.js";
|
||||
import {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createBanner } from "../../../../db/banner.js";
|
||||
import { addUsageToArray, readFileRecord } from "../../../../db/file_record.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { processFiles } from "../../../../lib/file.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import type { FileRecord } from "../../../../schema/tables.js";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createBoard } from "../../../../db/board.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import { CreateBoardForm } from "../../../../schema/validation/board.js";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readBoard } from "../../../../db/board.js";
|
||||
import { createFilter } from "../../../../db/filter.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import { CreateFilterForm } from "../../../../schema/validation/filter.js";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createNews } from "../../../../db/news.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { formatContent } from "../../../../lib/formatting.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import { CreateNewsForm } from "../../../../schema/validation/news.js";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readBoard } from "../../../../db/board.js";
|
||||
import { createRestriction } from "../../../../db/restriction.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import { CreateRestrictionForm } from "../../../../schema/validation/restriction.js";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createUser } from "../../../../db/user.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import {
|
||||
canUser,
|
||||
canUserApplyRole,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
updateFilterPriority,
|
||||
} from "../../../../db/filter.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import type { Filter } from "../../../../schema/tables.js";
|
||||
import {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { deleteNews, readNews } from "../../../../db/news.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import type { News } from "../../../../schema/tables.js";
|
||||
import { NewsActionsForm } from "../../../../schema/validation/news.js";
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
readRestrictions,
|
||||
} from "../../../../db/restriction.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import type { Restriction } from "../../../../schema/tables.js";
|
||||
import { RestrictionActionsForm } from "../../../../schema/validation/restriction.js";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readBoard, updateBoardConfig } from "../../../../db/board.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import {
|
||||
PrimaryBoardConfigForm,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readNewsPost, updateNews } from "../../../../db/news.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { formatContent } from "../../../../lib/formatting.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../../lib/permissions.js";
|
||||
import { UpdateNewsContentForm } from "../../../../schema/validation/news.js";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readUser, updateUserPermissions } from "../../../../db/user.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import {
|
||||
canUser,
|
||||
canUserActOn,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
updateUserRank,
|
||||
} from "../../../../db/user.js";
|
||||
import { CzchanError } from "../../../../lib/error.js";
|
||||
import { czchanLog } from "../../../../lib/logger.js";
|
||||
import { czchanLog } from "../../../../lib/log.js";
|
||||
import {
|
||||
canUser,
|
||||
canUserActOn,
|
||||
|
||||
101
src/web/routes/mod/log.tsx
Normal file
101
src/web/routes/mod/log.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { CzchanError } from "../../../lib/error.js";
|
||||
import { type LogLine, readLogPage } from "../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../lib/permissions.js";
|
||||
import { zPage } from "../../../schema/validation/common.js";
|
||||
import Page from "../../components/chrome/page.js";
|
||||
import PageBody from "../../components/chrome/page_body.js";
|
||||
import PageHead from "../../components/chrome/page_head.js";
|
||||
import Datetime from "../../components/primitives/datetime.js";
|
||||
import { getCtx, type TemplateCtx } from "../../ctx.js";
|
||||
import logs from "./logs.js";
|
||||
import { type PropsWithChildren } from "@kitajs/html";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
export default async (req: Request, res: Response) => {
|
||||
const ctx = await getCtx(req);
|
||||
|
||||
if (!canUser(ctx.user, CzchanPerm.VIEW_LOGS)) {
|
||||
throw new CzchanError("K tomuto nemáš oprávnění.", 403);
|
||||
}
|
||||
|
||||
const log = req.params.log.toString();
|
||||
const page = zPage.parse(req.query.page ?? "1");
|
||||
const lines = await readLogPage(log, page);
|
||||
const html = Template(ctx, page, log, lines);
|
||||
|
||||
res.send(html);
|
||||
};
|
||||
|
||||
const Template = (
|
||||
ctx: TemplateCtx,
|
||||
page: number,
|
||||
log: string,
|
||||
lines: LogLine[],
|
||||
) => (
|
||||
<Page>
|
||||
<PageHead ctx={ctx} title={`Záznam (${log})`} description="" />
|
||||
<PageBody ctx={ctx}>
|
||||
<h1 class="title center" safe>
|
||||
Záznam ({log})
|
||||
</h1>
|
||||
<hr />
|
||||
<LogNav log={log} page={page} />
|
||||
<hr />
|
||||
<div class="table-wrapper">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Záznam</th>
|
||||
<th>Úroveň</th>
|
||||
<th>Zpráva</th>
|
||||
<th>Činitel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{lines.map((line) => (
|
||||
<tr>
|
||||
<td>
|
||||
<Datetime ctx={ctx} date={line.timestamp} />
|
||||
</td>
|
||||
<td safe>{line.log}</td>
|
||||
<td>{line.level}</td>
|
||||
<td safe>{line.message}</td>
|
||||
<td safe>{line.actor}</td>
|
||||
</tr>
|
||||
))}
|
||||
{logs.length === 0 && (
|
||||
<tr>
|
||||
<td class="center" colspan="5">
|
||||
Nic tady není...
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr />
|
||||
<LogNav log={log} page={page} />
|
||||
<hr />
|
||||
</PageBody>
|
||||
</Page>
|
||||
);
|
||||
|
||||
const LogNav = ({
|
||||
log,
|
||||
page,
|
||||
}: PropsWithChildren<{ log: string; page: number }>) => (
|
||||
<nav class="pagination">
|
||||
[
|
||||
{page === 1 ? (
|
||||
<span>Předchozí</span>
|
||||
) : (
|
||||
<a href={`/mod/log/${log}?page=${page - 1}`}>Předchozí</a>
|
||||
)}
|
||||
] [
|
||||
<b>
|
||||
<a href={`/mod/log/${log}?page=${page}`}>{page}</a>
|
||||
</b>
|
||||
] [<a href={`/mod/log/${log}?page=${page + 1}`}>Další</a>]
|
||||
</nav>
|
||||
);
|
||||
@@ -1,9 +1,12 @@
|
||||
import { CzchanError } from "../../../lib/error.js";
|
||||
import { type Log, readLogs } from "../../../lib/log.js";
|
||||
import { canUser, CzchanPerm } from "../../../lib/permissions.js";
|
||||
import { bytesToSize } from "../../../lib/util.js";
|
||||
import Page from "../../components/chrome/page.js";
|
||||
import PageBody from "../../components/chrome/page_body.js";
|
||||
import PageHead from "../../components/chrome/page_head.js";
|
||||
import ModNav from "../../components/navigation/mod_nav.js";
|
||||
import Datetime from "../../components/primitives/datetime.js";
|
||||
import { getCtx, type TemplateCtx } from "../../ctx.js";
|
||||
import type { Request, Response } from "express";
|
||||
|
||||
@@ -14,20 +17,58 @@ export default async (req: Request, res: Response) => {
|
||||
throw new CzchanError("K tomuto nemáš oprávnění.", 403);
|
||||
}
|
||||
|
||||
const html = Template(ctx);
|
||||
const logs = await readLogs();
|
||||
const html = Template(ctx, logs);
|
||||
|
||||
res.send(html);
|
||||
};
|
||||
|
||||
const Template = (ctx: TemplateCtx) => (
|
||||
const Template = (ctx: TemplateCtx, logs: Log[]) => (
|
||||
<Page>
|
||||
<PageHead ctx={ctx} title="Záznamy" description="" />
|
||||
<PageBody ctx={ctx}>
|
||||
<h1 class="title center">Záznamy</h1>
|
||||
<p class="subtitle center">[TBI]</p>
|
||||
<hr />
|
||||
<ModNav ctx={ctx} />
|
||||
<hr />
|
||||
<div class="table-wrapper">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Záznam</th>
|
||||
<th>Vytvořen</th>
|
||||
<th>Upraven</th>
|
||||
<th>Velikost</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{logs.map((log) => (
|
||||
<tr>
|
||||
<td>
|
||||
<a href={`/mod/log/${log.name}`} safe>
|
||||
{log.name}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<Datetime ctx={ctx} date={log.created} />
|
||||
</td>
|
||||
<td>
|
||||
<Datetime ctx={ctx} date={log.modified} />
|
||||
</td>
|
||||
<td safe>{bytesToSize(log.size)}</td>
|
||||
</tr>
|
||||
))}
|
||||
{logs.length === 0 && (
|
||||
<tr>
|
||||
<td class="center" colspan="4">
|
||||
Nic tady není...
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr />
|
||||
</PageBody>
|
||||
</Page>
|
||||
);
|
||||
|
||||
@@ -15,14 +15,18 @@ export default async (req: Request, res: Response) => {
|
||||
throw new CzchanError(`Stránka ${pageName} neexistuje`, 404);
|
||||
}
|
||||
|
||||
const html = Template(ctx, pageHtml);
|
||||
const html = Template(ctx, pageName, pageHtml);
|
||||
|
||||
res.send(html);
|
||||
};
|
||||
|
||||
const Template = (ctx: TemplateCtx, pageHtml: string) => (
|
||||
const Template = (ctx: TemplateCtx, pageName: string, pageHtml: string) => (
|
||||
<Page>
|
||||
<PageHead ctx={ctx} title="Přihlásit se" description="" />
|
||||
<PageHead
|
||||
ctx={ctx}
|
||||
title={`${ctx.config.site.ui.name} - Stránka (${pageName})`}
|
||||
description=""
|
||||
/>
|
||||
<PageBody ctx={ctx}>{pageHtml as "safe"}</PageBody>
|
||||
</Page>
|
||||
);
|
||||
|
||||
@@ -24,6 +24,7 @@ import modEditUserPermissions from "../routes/mod/edit/user_permissions.js";
|
||||
import modFilters from "../routes/mod/filters.js";
|
||||
import modIndex from "../routes/mod/index.js";
|
||||
import modIP from "../routes/mod/ip.js";
|
||||
import modLog from "../routes/mod/log.js";
|
||||
import modLogs from "../routes/mod/logs.js";
|
||||
import modNews from "../routes/mod/news.js";
|
||||
import modPostInfo from "../routes/mod/post_info.js";
|
||||
@@ -45,6 +46,7 @@ const registerModRoutes = (router: Router) => {
|
||||
router.get("/mod/restrictions", e(modRestrictions));
|
||||
router.get("/mod/filters", e(modFilters));
|
||||
router.get("/mod/logs", e(modLogs));
|
||||
router.get("/mod/log/:log", e(modLog));
|
||||
|
||||
// Mod info
|
||||
router.get("/mod/ip/:ip", e(modIP));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CzchanError } from "../../lib/error.js";
|
||||
import { czchanLog } from "../../lib/logger.js";
|
||||
import { czchanLog } from "../../lib/log.js";
|
||||
import Page from "../components/chrome/page.js";
|
||||
import PageBody from "../components/chrome/page_body.js";
|
||||
import PageHead from "../components/chrome/page_head.js";
|
||||
|
||||
@@ -20,7 +20,7 @@ const autoUpdate = () => {
|
||||
const infoContainer = $("#update-info-container");
|
||||
|
||||
infoContainer.append(
|
||||
'<hr><div class="updater"><span id="update-info"></span> <a href="javascript:void(0)" id="update">[Aktualizovat]</a> <label>[ Auto? <input type="checkbox" id="do-update" checked=""> ]</label></div>',
|
||||
'<hr><nav class="updater"><span id="update-info"></span> <a href="javascript:void(0)" id="update">[Aktualizovat]</a> <label>[ Auto? <input type="checkbox" id="do-update" checked=""> ]</label></nav>',
|
||||
);
|
||||
|
||||
let seconds = 0;
|
||||
|
||||
Reference in New Issue
Block a user