diff --git a/back/pnpm-lock.yaml b/back/pnpm-lock.yaml index d48a316..a7766ea 100644 --- a/back/pnpm-lock.yaml +++ b/back/pnpm-lock.yaml @@ -29,9 +29,6 @@ importers: '@nestjs/schedule': specifier: ^6.0.0 version: 6.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13) - '@nestjs/serve-static': - specifier: ^4.0.2 - version: 4.0.2(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(express@4.21.2) '@nestjs/typeorm': specifier: ^11.0.0 version: 11.0.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.28(pg@8.16.3)(ts-node@10.9.2(@types/node@22.7.5)(typescript@5.5.4))) @@ -735,22 +732,6 @@ packages: peerDependencies: typescript: '>=4.8.2' - '@nestjs/serve-static@4.0.2': - resolution: {integrity: sha512-cT0vdWN5ar7jDI2NKbhf4LcwJzU4vS5sVpMkVrHuyLcltbrz6JdGi1TfIMMatP2pNiq5Ie/uUdPSFDVaZX/URQ==} - peerDependencies: - '@fastify/static': ^6.5.0 || ^7.0.0 - '@nestjs/common': ^9.0.0 || ^10.0.0 - '@nestjs/core': ^9.0.0 || ^10.0.0 - express: ^4.18.1 - fastify: ^4.7.0 - peerDependenciesMeta: - '@fastify/static': - optional: true - express: - optional: true - fastify: - optional: true - '@nestjs/testing@11.1.13': resolution: {integrity: sha512-bOWP8nLEZAOEEX8jAZGBCc1yU0+nv4g2ipc+QEzkVUe3eEEUKHKaeGafJ3GtDuGavlZKfkXEqflZuICdavu5dQ==} peerDependencies: @@ -1125,10 +1106,6 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -1249,9 +1226,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - array-timsort@1.0.3: resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} @@ -1315,10 +1289,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -1514,10 +1484,6 @@ packages: console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -1529,9 +1495,6 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -1578,14 +1541,6 @@ packages: dayjs@1.11.19: resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1628,10 +1583,6 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -1697,10 +1648,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -1841,10 +1788,6 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} - engines: {node: '>= 0.10.0'} - express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} @@ -1898,10 +1841,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} - finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} @@ -1947,10 +1886,6 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} @@ -2105,10 +2040,6 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -2549,9 +2480,6 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -2587,11 +2515,6 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - mime@2.6.0: resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} engines: {node: '>=4.0.0'} @@ -2644,9 +2567,6 @@ packages: engines: {node: '>=10'} hasBin: true - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2666,10 +2586,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -2810,12 +2726,6 @@ packages: resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} engines: {node: 20 || >=22} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - - path-to-regexp@0.2.5: - resolution: {integrity: sha512-l6qtdDPIkmAmzEO6egquYDfqQGPMRNGjYtrU13HAXb3YSRrt7HSb1sJY0pKp6o2bAa86tSB6iwaW2JbthPKr7Q==} - path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -2939,10 +2849,6 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -2961,10 +2867,6 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} @@ -3067,10 +2969,6 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} @@ -3078,10 +2976,6 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - serve-static@2.2.1: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} @@ -3536,10 +3430,6 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - uuid@11.1.0: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true @@ -4444,14 +4334,6 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/serve-static@4.0.2(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(express@4.21.2)': - dependencies: - '@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2) - path-to-regexp: 0.2.5 - optionalDependencies: - express: 4.21.2 - '@nestjs/testing@11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(@nestjs/platform-express@11.1.13)': dependencies: '@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -4929,12 +4811,6 @@ snapshots: dependencies: event-target-shim: 5.0.1 - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - optional: true - accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -5035,9 +4911,6 @@ snapshots: argparse@2.0.1: {} - array-flatten@1.1.1: - optional: true - array-timsort@1.0.3: {} array-union@2.1.0: {} @@ -5129,24 +5002,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - body-parser@1.20.3: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - optional: true - body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -5340,20 +5195,12 @@ snapshots: console-control-strings@1.1.0: {} - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - optional: true - content-disposition@1.0.1: {} content-type@1.0.5: {} convert-source-map@2.0.0: {} - cookie-signature@1.0.6: - optional: true - cookie-signature@1.2.2: {} cookie@0.7.1: {} @@ -5406,11 +5253,6 @@ snapshots: dayjs@1.11.19: {} - debug@2.6.9: - dependencies: - ms: 2.0.0 - optional: true - debug@4.4.3: dependencies: ms: 2.1.3 @@ -5437,9 +5279,6 @@ snapshots: depd@2.0.0: {} - destroy@1.2.0: - optional: true - detect-libc@2.1.2: {} detect-newline@3.1.0: {} @@ -5489,9 +5328,6 @@ snapshots: emoji-regex@9.2.2: {} - encodeurl@1.0.2: - optional: true - encodeurl@2.0.0: {} enhanced-resolve@5.18.4: @@ -5649,43 +5485,6 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - express@4.21.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - optional: true - express@5.2.1: dependencies: accepts: 2.0.0 @@ -5768,19 +5567,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - optional: true - finalhandler@2.1.1: dependencies: debug: 4.4.3 @@ -5853,9 +5639,6 @@ snapshots: forwarded@0.2.0: {} - fresh@0.5.2: - optional: true - fresh@2.0.0: {} fs-extra@10.1.0: @@ -6036,11 +5819,6 @@ snapshots: human-signals@2.1.0: {} - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - optional: true - iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -6629,9 +6407,6 @@ snapshots: dependencies: fs-monkey: 1.1.0 - merge-descriptors@1.0.3: - optional: true - merge-descriptors@2.0.0: {} merge-stream@2.0.0: {} @@ -6657,9 +6432,6 @@ snapshots: dependencies: mime-db: 1.54.0 - mime@1.6.0: - optional: true - mime@2.6.0: {} mimic-fn@2.1.0: {} @@ -6701,9 +6473,6 @@ snapshots: mkdirp@1.0.4: {} - ms@2.0.0: - optional: true - ms@2.1.3: {} multer@1.4.5-lts.2: @@ -6730,9 +6499,6 @@ snapshots: natural-compare@1.4.0: {} - negotiator@0.6.3: - optional: true - negotiator@1.0.0: {} neo-async@2.6.2: {} @@ -6864,11 +6630,6 @@ snapshots: lru-cache: 11.2.6 minipass: 7.1.2 - path-to-regexp@0.1.12: - optional: true - - path-to-regexp@0.2.5: {} - path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -6966,11 +6727,6 @@ snapshots: pure-rand@6.1.0: {} - qs@6.13.0: - dependencies: - side-channel: 1.1.0 - optional: true - qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -6987,14 +6743,6 @@ snapshots: range-parser@1.2.1: {} - raw-body@2.5.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - optional: true - raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -7100,25 +6848,6 @@ snapshots: semver@7.7.3: {} - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - optional: true - send@1.2.1: dependencies: debug: 4.4.3 @@ -7139,16 +6868,6 @@ snapshots: dependencies: randombytes: 2.1.0 - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - optional: true - serve-static@2.2.1: dependencies: encodeurl: 2.0.0 @@ -7564,9 +7283,6 @@ snapshots: util-deprecate@1.0.2: {} - utils-merge@1.0.1: - optional: true - uuid@11.1.0: {} v8-compile-cache-lib@3.0.1: {} diff --git a/back/src/app.module.ts b/back/src/app.module.ts index d49a1ac..4675578 100644 --- a/back/src/app.module.ts +++ b/back/src/app.module.ts @@ -9,6 +9,7 @@ import { BotModule } from './bot/bot.module'; import { CommonModule } from './common/common.module'; import { validate } from './config/env/validate'; import { DatabaseModule } from './database/database.module'; +import { UsersModule } from './users/users.module'; @Module({ imports: [ @@ -18,6 +19,7 @@ import { DatabaseModule } from './database/database.module'; AdminsModule, AuthModule, AdminConsoleModule, + UsersModule, BotModule, ], controllers: [AppController], diff --git a/back/src/bot/bot.module.ts b/back/src/bot/bot.module.ts index 1e62701..a62e5f6 100644 --- a/back/src/bot/bot.module.ts +++ b/back/src/bot/bot.module.ts @@ -2,11 +2,13 @@ import { Module } from '@nestjs/common'; import { BotService } from './bot.service'; import { ConfigModule } from '@nestjs/config'; import { ScheduleModule } from '@nestjs/schedule'; +import { UsersModule } from '../users/users.module'; @Module({ imports: [ ConfigModule, ScheduleModule.forRoot(), + UsersModule, ], providers: [BotService], exports: [BotService], diff --git a/back/src/bot/bot.service.ts b/back/src/bot/bot.service.ts index 6e85928..499e864 100644 --- a/back/src/bot/bot.service.ts +++ b/back/src/bot/bot.service.ts @@ -1,7 +1,9 @@ import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import { Bot, Context, Keyboard } from 'grammy'; +import { Bot, Keyboard } from 'grammy'; import { ForceReply, InlineKeyboardMarkup, ReplyKeyboardMarkup, ReplyKeyboardRemove } from 'grammy/types'; +import { UsersService } from '../users/users.service'; +import { BotContext } from './types/bot-context.types'; @Injectable() export class BotService { @@ -10,26 +12,59 @@ export class BotService { constructor( private readonly configService: ConfigService, + private readonly usersService: UsersService, ) { const telegramBotToken = this.configService.get('TELEGRAM_BOT_TOKEN'); this.bot = new Bot(telegramBotToken); } public onModuleInit() { + this.bot.use(this.checkUserAuth.bind(this)); + this.bot.command('start', this.onStart.bind(this)); this.bot.start().catch((error) => console.error(':: BOT ERROR:', error)); this._logger.log('BOT STARTED!'); } - private async onStart(ctx: Context) { + private async checkUserAuth(ctx: BotContext, next: () => Promise) { + if (!ctx.from) { + return next(); + } + try { + const user = await this.usersService.findOrCreate({ + id: ctx.from.id, + username: ctx.from.username, + first_name: ctx.from.first_name, + last_name: ctx.from.last_name, + language_code: ctx.from.language_code, + }); + + if (!user.is_active) { + await ctx.reply('❌ Your account has been deactivated. Please contact support.'); + return; + } + + ctx.user = user; + + return next(); + } catch (error) { + this._logger.error(`Error in checkUserAuth: ${error.message}`, error.stack); + return next(); + } + } + + private async onStart(ctx: BotContext) { + try { + const name = ctx.user?.first_name || 'there'; + const keyboard = new Keyboard() .text('Menu') .row() .resized(); - await ctx.reply('Welcome! This bot is under development.', { + await ctx.reply(`Welcome, ${name}! 👋\n\nThis bot is under development.`, { reply_markup: keyboard, }); } catch (error) { @@ -37,27 +72,6 @@ export class BotService { } } - /** - * Send a message to a specific Telegram user. - * - * @param telegramId - Telegram user chat ID (as string) - * @param message - Message text (supports Markdown) - * @param reply_markup - Optional keyboard (inline, reply, or remove) - * @throws Logs error if message sending fails - * - * @example - * ```typescript - * // Simple message - * await botService.sendMessage('123456789', 'Hello!'); - * - * // With inline keyboard - * const keyboard = new InlineKeyboard() - * .text('Button 1', 'data1') - * .row() - * .text('Button 2', 'data2'); - * await botService.sendMessage('123456789', 'Choose:', keyboard); - * ``` - */ public async sendMessage( telegramId: string, message: string, diff --git a/back/src/bot/types/bot-context.types.ts b/back/src/bot/types/bot-context.types.ts new file mode 100644 index 0000000..fdf1542 --- /dev/null +++ b/back/src/bot/types/bot-context.types.ts @@ -0,0 +1,6 @@ +import { Context } from 'grammy'; +import { User } from '../../users/entities/user.entity'; + +export interface BotContext extends Context { + user?: User; +} diff --git a/back/src/database/database.module.ts b/back/src/database/database.module.ts index 16e8627..5566638 100644 --- a/back/src/database/database.module.ts +++ b/back/src/database/database.module.ts @@ -3,6 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Password } from 'src/admins/entities/password.entity'; import { Admin } from 'src/admins/entities/admin.entity'; +import { User } from 'src/users/entities/user.entity'; @Module({ imports: [ @@ -22,6 +23,7 @@ import { Admin } from 'src/admins/entities/admin.entity'; entities: [ Admin, Password, + User, ] }), }), diff --git a/back/src/users/entities/user.entity.ts b/back/src/users/entities/user.entity.ts new file mode 100644 index 0000000..87c4fd6 --- /dev/null +++ b/back/src/users/entities/user.entity.ts @@ -0,0 +1,24 @@ +import { AbstractEntity } from 'src/common/entities/abstract.entity'; +import { Column, Entity, Index } from 'typeorm'; + +@Entity('users') +@Index(['telegram_id'], { unique: true }) +export class User extends AbstractEntity { + @Column({ type: 'bigint', unique: true }) + telegram_id: string; + + @Column({ length: 255, nullable: true, default: null }) + username: string; + + @Column({ length: 255 }) + first_name: string; + + @Column({ length: 255, nullable: true, default: null }) + last_name: string; + + @Column({ length: 10, nullable: true, default: null }) + language_code: string; + + @Column({ default: true }) + is_active: boolean; +} diff --git a/back/src/users/users.module.ts b/back/src/users/users.module.ts new file mode 100644 index 0000000..2c590c7 --- /dev/null +++ b/back/src/users/users.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { UsersService } from './users.service'; +import { User } from './entities/user.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([User])], + providers: [UsersService], + exports: [UsersService], +}) +export class UsersModule {} diff --git a/back/src/users/users.service.ts b/back/src/users/users.service.ts new file mode 100644 index 0000000..e4e1290 --- /dev/null +++ b/back/src/users/users.service.ts @@ -0,0 +1,79 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { User } from './entities/user.entity'; + +@Injectable() +export class UsersService { + private readonly _logger = new Logger(UsersService.name); + + constructor( + @InjectRepository(User) + private userRepository: Repository, + ) {} + + async findOrCreate(telegramUser: { + id: number; + username?: string; + first_name: string; + last_name?: string; + language_code?: string; + }): Promise { + const telegramId = telegramUser.id.toString(); + + let user = await this.userRepository.findOne({ + where: { telegram_id: telegramId }, + }); + + if (user) { + user.username = telegramUser.username || null; + user.first_name = telegramUser.first_name; + user.last_name = telegramUser.last_name || null; + user.language_code = telegramUser.language_code || null; + + user = await this.userRepository.save(user); + this._logger.debug(`Updated user: ${telegramId}`); + } else { + user = this.userRepository.create({ + telegram_id: telegramId, + username: telegramUser.username || null, + first_name: telegramUser.first_name, + last_name: telegramUser.last_name || null, + language_code: telegramUser.language_code || null, + is_active: true, + }); + + user = await this.userRepository.save(user); + this._logger.log(`Created new user: ${telegramId} (${telegramUser.first_name})`); + } + + return user; + } + + async findByTelegramId(telegramId: string): Promise { + return this.userRepository.findOne({ + where: { telegram_id: telegramId }, + }); + } + + async findOneByTelegramId(telegramId: string): Promise { + const user = await this.findByTelegramId(telegramId); + + if (!user) { + throw new Error(`User with telegram_id ${telegramId} not found`); + } + + return user; + } + + async isUserActive(telegramId: string): Promise { + const user = await this.findByTelegramId(telegramId); + return user ? user.is_active : false; + } + + async updateActiveStatus(telegramId: string, isActive: boolean): Promise { + const user = await this.findOneByTelegramId(telegramId); + user.is_active = isActive; + return this.userRepository.save(user); + } +}