Adding ability to restore content on user unban. (#4845)

* Adding ability to restore content on user unban.

- Fixes #4721

* Fixing api tests.

* Fix package.json

* Fixing lemmy-js-client dep.

* Adding API test for restoring content.
This commit is contained in:
Dessalines 2024-09-18 09:11:42 -04:00 committed by GitHub
parent b26aaac523
commit 2b3fd70afd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 239 additions and 168 deletions

View file

@ -27,7 +27,7 @@
"eslint": "^9.8.0", "eslint": "^9.8.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"jest": "^29.5.0", "jest": "^29.5.0",
"lemmy-js-client": "0.19.5-alpha.1", "lemmy-js-client": "0.20.0-alpha.4",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
"typescript": "^5.5.4", "typescript": "^5.5.4",

View file

@ -13,37 +13,37 @@ importers:
version: 29.5.12 version: 29.5.12
'@types/node': '@types/node':
specifier: ^22.0.2 specifier: ^22.0.2
version: 22.5.1 version: 22.3.0
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: ^8.0.0 specifier: ^8.0.0
version: 8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4) version: 8.1.0(@typescript-eslint/parser@8.1.0(eslint@9.9.0)(typescript@5.5.4))(eslint@9.9.0)(typescript@5.5.4)
'@typescript-eslint/parser': '@typescript-eslint/parser':
specifier: ^8.0.0 specifier: ^8.0.0
version: 8.0.0(eslint@9.9.1)(typescript@5.5.4) version: 8.1.0(eslint@9.9.0)(typescript@5.5.4)
eslint: eslint:
specifier: ^9.8.0 specifier: ^9.8.0
version: 9.9.1 version: 9.9.0
eslint-plugin-prettier: eslint-plugin-prettier:
specifier: ^5.1.3 specifier: ^5.1.3
version: 5.2.1(eslint@9.9.1)(prettier@3.3.3) version: 5.2.1(eslint@9.9.0)(prettier@3.3.3)
jest: jest:
specifier: ^29.5.0 specifier: ^29.5.0
version: 29.7.0(@types/node@22.5.1) version: 29.7.0(@types/node@22.3.0)
lemmy-js-client: lemmy-js-client:
specifier: 0.19.5-alpha.1 specifier: 0.20.0-alpha.4
version: 0.19.5-alpha.1 version: 0.20.0-alpha.4
prettier: prettier:
specifier: ^3.2.5 specifier: ^3.2.5
version: 3.3.3 version: 3.3.3
ts-jest: ts-jest:
specifier: ^29.1.0 specifier: ^29.1.0
version: 29.2.5(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.5.1))(typescript@5.5.4) version: 29.2.4(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.3.0))(typescript@5.5.4)
typescript: typescript:
specifier: ^5.5.4 specifier: ^5.5.4
version: 5.5.4 version: 5.5.4
typescript-eslint: typescript-eslint:
specifier: ^8.0.0 specifier: ^8.0.0
version: 8.0.0(eslint@9.9.1)(typescript@5.5.4) version: 8.1.0(eslint@9.9.0)(typescript@5.5.4)
packages: packages:
@ -228,16 +228,16 @@ packages:
resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint/config-array@0.18.0': '@eslint/config-array@0.17.1':
resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/eslintrc@3.1.0': '@eslint/eslintrc@3.1.0':
resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.9.1': '@eslint/js@9.9.0':
resolution: {integrity: sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==} resolution: {integrity: sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.4': '@eslint/object-schema@2.1.4':
@ -396,8 +396,8 @@ packages:
'@types/jest@29.5.12': '@types/jest@29.5.12':
resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==}
'@types/node@22.5.1': '@types/node@22.3.0':
resolution: {integrity: sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==} resolution: {integrity: sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==}
'@types/stack-utils@2.0.3': '@types/stack-utils@2.0.3':
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
@ -408,8 +408,8 @@ packages:
'@types/yargs@17.0.32': '@types/yargs@17.0.32':
resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
'@typescript-eslint/eslint-plugin@8.0.0': '@typescript-eslint/eslint-plugin@8.1.0':
resolution: {integrity: sha512-STIZdwEQRXAHvNUS6ILDf5z3u95Gc8jzywunxSNqX00OooIemaaNIA0vEgynJlycL5AjabYLLrIyHd4iazyvtg==} resolution: {integrity: sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
@ -419,8 +419,8 @@ packages:
typescript: typescript:
optional: true optional: true
'@typescript-eslint/parser@8.0.0': '@typescript-eslint/parser@8.1.0':
resolution: {integrity: sha512-pS1hdZ+vnrpDIxuFXYQpLTILglTjSYJ9MbetZctrUawogUsPdz31DIIRZ9+rab0LhYNTsk88w4fIzVheiTbWOQ==} resolution: {integrity: sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
@ -429,12 +429,12 @@ packages:
typescript: typescript:
optional: true optional: true
'@typescript-eslint/scope-manager@8.0.0': '@typescript-eslint/scope-manager@8.1.0':
resolution: {integrity: sha512-V0aa9Csx/ZWWv2IPgTfY7T4agYwJyILESu/PVqFtTFz9RIS823mAze+NbnBI8xiwdX3iqeQbcTYlvB04G9wyQw==} resolution: {integrity: sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@8.0.0': '@typescript-eslint/type-utils@8.1.0':
resolution: {integrity: sha512-mJAFP2mZLTBwAn5WI4PMakpywfWFH5nQZezUQdSKV23Pqo6o9iShQg1hP2+0hJJXP2LnZkWPphdIq4juYYwCeg==} resolution: {integrity: sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@ -442,12 +442,12 @@ packages:
typescript: typescript:
optional: true optional: true
'@typescript-eslint/types@8.0.0': '@typescript-eslint/types@8.1.0':
resolution: {integrity: sha512-wgdSGs9BTMWQ7ooeHtu5quddKKs5Z5dS+fHLbrQI+ID0XWJLODGMHRfhwImiHoeO2S5Wir2yXuadJN6/l4JRxw==} resolution: {integrity: sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.0.0': '@typescript-eslint/typescript-estree@8.1.0':
resolution: {integrity: sha512-5b97WpKMX+Y43YKi4zVcCVLtK5F98dFls3Oxui8LbnmRsseKenbbDinmvxrWegKDMmlkIq/XHuyy0UGLtpCDKg==} resolution: {integrity: sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@ -455,14 +455,14 @@ packages:
typescript: typescript:
optional: true optional: true
'@typescript-eslint/utils@8.0.0': '@typescript-eslint/utils@8.1.0':
resolution: {integrity: sha512-k/oS/A/3QeGLRvOWCg6/9rATJL5rec7/5s1YmdS0ZU6LHveJyGFwBvLhSRBv6i9xaj7etmosp+l+ViN1I9Aj/Q==} resolution: {integrity: sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
'@typescript-eslint/visitor-keys@8.0.0': '@typescript-eslint/visitor-keys@8.1.0':
resolution: {integrity: sha512-oN0K4nkHuOyF3PVMyETbpP5zp6wfyOvm7tWhTMfoqxSSsPmJIh6JNASuZDlODE8eE+0EB9uar+6+vxr9DBTYOA==} resolution: {integrity: sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
acorn-jsx@5.3.2: acorn-jsx@5.3.2:
@ -512,8 +512,8 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'} engines: {node: '>=8'}
async@3.2.6: async@3.2.5:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==}
babel-jest@29.7.0: babel-jest@29.7.0:
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
@ -741,8 +741,8 @@ packages:
resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@9.9.1: eslint@9.9.0:
resolution: {integrity: sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==} resolution: {integrity: sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -916,10 +916,6 @@ packages:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'} engines: {node: '>=10.17.0'}
ignore@5.3.1:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'}
ignore@5.3.2: ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
@ -1179,8 +1175,8 @@ packages:
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
engines: {node: '>=6'} engines: {node: '>=6'}
lemmy-js-client@0.19.5-alpha.1: lemmy-js-client@0.20.0-alpha.4:
resolution: {integrity: sha512-GOhaiTQzrpwdmc3DFYemT2SmNmpuQJe2BWUms9QOzdYlkA1WZ0uu7axPE3s+T5OOxfy7K9Q2gsLe72dcVSlffw==} resolution: {integrity: sha512-MuVE8u/IFz59ks2vxOUXMRU8x6SIz3Keu4zRhmhNt+n+gI25JAggsTDrtxVCBtrqBhFEe+a3PdXdwm+fXbs0Dw==}
leven@3.1.0: leven@3.1.0:
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
@ -1412,6 +1408,11 @@ packages:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true hasBin: true
semver@7.6.2:
resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
engines: {node: '>=10'}
hasBin: true
semver@7.6.3: semver@7.6.3:
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1517,8 +1518,8 @@ packages:
peerDependencies: peerDependencies:
typescript: '>=4.2.0' typescript: '>=4.2.0'
ts-jest@29.2.5: ts-jest@29.2.4:
resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} resolution: {integrity: sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==}
engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -1556,8 +1557,8 @@ packages:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'} engines: {node: '>=10'}
typescript-eslint@8.0.0: typescript-eslint@8.1.0:
resolution: {integrity: sha512-yQWBJutWL1PmpmDddIOl9/Mi6vZjqNCjqSGBMQ4vsc2Aiodk0SnbQQWPXbSy0HNuKCuGkw1+u4aQ2mO40TdhDQ==} resolution: {integrity: sha512-prB2U3jXPJLpo1iVLN338Lvolh6OrcCZO+9Yv6AR+tvegPPptYCDBIHiEEUdqRi8gAv2bXNKfMUrgAd2ejn/ow==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@ -1570,8 +1571,8 @@ packages:
engines: {node: '>=14.17'} engines: {node: '>=14.17'}
hasBin: true hasBin: true
undici-types@6.19.8: undici-types@6.18.2:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} resolution: {integrity: sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==}
update-browserslist-db@1.0.13: update-browserslist-db@1.0.13:
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
@ -1834,14 +1835,14 @@ snapshots:
'@bcoe/v8-coverage@0.2.3': {} '@bcoe/v8-coverage@0.2.3': {}
'@eslint-community/eslint-utils@4.4.0(eslint@9.9.1)': '@eslint-community/eslint-utils@4.4.0(eslint@9.9.0)':
dependencies: dependencies:
eslint: 9.9.1 eslint: 9.9.0
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.11.0': {} '@eslint-community/regexpp@4.11.0': {}
'@eslint/config-array@0.18.0': '@eslint/config-array@0.17.1':
dependencies: dependencies:
'@eslint/object-schema': 2.1.4 '@eslint/object-schema': 2.1.4
debug: 4.3.6 debug: 4.3.6
@ -1863,7 +1864,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@eslint/js@9.9.1': {} '@eslint/js@9.9.0': {}
'@eslint/object-schema@2.1.4': {} '@eslint/object-schema@2.1.4': {}
@ -1884,7 +1885,7 @@ snapshots:
'@jest/console@29.7.0': '@jest/console@29.7.0':
dependencies: dependencies:
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
chalk: 4.1.2 chalk: 4.1.2
jest-message-util: 29.7.0 jest-message-util: 29.7.0
jest-util: 29.7.0 jest-util: 29.7.0
@ -1897,14 +1898,14 @@ snapshots:
'@jest/test-result': 29.7.0 '@jest/test-result': 29.7.0
'@jest/transform': 29.7.0 '@jest/transform': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
ansi-escapes: 4.3.2 ansi-escapes: 4.3.2
chalk: 4.1.2 chalk: 4.1.2
ci-info: 3.9.0 ci-info: 3.9.0
exit: 0.1.2 exit: 0.1.2
graceful-fs: 4.2.11 graceful-fs: 4.2.11
jest-changed-files: 29.7.0 jest-changed-files: 29.7.0
jest-config: 29.7.0(@types/node@22.5.1) jest-config: 29.7.0(@types/node@22.3.0)
jest-haste-map: 29.7.0 jest-haste-map: 29.7.0
jest-message-util: 29.7.0 jest-message-util: 29.7.0
jest-regex-util: 29.6.3 jest-regex-util: 29.6.3
@ -1929,7 +1930,7 @@ snapshots:
dependencies: dependencies:
'@jest/fake-timers': 29.7.0 '@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
jest-mock: 29.7.0 jest-mock: 29.7.0
'@jest/expect-utils@29.7.0': '@jest/expect-utils@29.7.0':
@ -1947,7 +1948,7 @@ snapshots:
dependencies: dependencies:
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@sinonjs/fake-timers': 10.3.0 '@sinonjs/fake-timers': 10.3.0
'@types/node': 22.5.1 '@types/node': 22.3.0
jest-message-util: 29.7.0 jest-message-util: 29.7.0
jest-mock: 29.7.0 jest-mock: 29.7.0
jest-util: 29.7.0 jest-util: 29.7.0
@ -1969,7 +1970,7 @@ snapshots:
'@jest/transform': 29.7.0 '@jest/transform': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@jridgewell/trace-mapping': 0.3.22 '@jridgewell/trace-mapping': 0.3.22
'@types/node': 22.5.1 '@types/node': 22.3.0
chalk: 4.1.2 chalk: 4.1.2
collect-v8-coverage: 1.0.2 collect-v8-coverage: 1.0.2
exit: 0.1.2 exit: 0.1.2
@ -2039,7 +2040,7 @@ snapshots:
'@jest/schemas': 29.6.3 '@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4 '@types/istanbul-reports': 3.0.4
'@types/node': 22.5.1 '@types/node': 22.3.0
'@types/yargs': 17.0.32 '@types/yargs': 17.0.32
chalk: 4.1.2 chalk: 4.1.2
@ -2107,7 +2108,7 @@ snapshots:
'@types/graceful-fs@4.1.9': '@types/graceful-fs@4.1.9':
dependencies: dependencies:
'@types/node': 22.5.1 '@types/node': 22.3.0
'@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-coverage@2.0.6': {}
@ -2124,9 +2125,9 @@ snapshots:
expect: 29.7.0 expect: 29.7.0
pretty-format: 29.7.0 pretty-format: 29.7.0
'@types/node@22.5.1': '@types/node@22.3.0':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.18.2
'@types/stack-utils@2.0.3': {} '@types/stack-utils@2.0.3': {}
@ -2136,17 +2137,17 @@ snapshots:
dependencies: dependencies:
'@types/yargs-parser': 21.0.3 '@types/yargs-parser': 21.0.3
'@typescript-eslint/eslint-plugin@8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4)': '@typescript-eslint/eslint-plugin@8.1.0(@typescript-eslint/parser@8.1.0(eslint@9.9.0)(typescript@5.5.4))(eslint@9.9.0)(typescript@5.5.4)':
dependencies: dependencies:
'@eslint-community/regexpp': 4.11.0 '@eslint-community/regexpp': 4.11.0
'@typescript-eslint/parser': 8.0.0(eslint@9.9.1)(typescript@5.5.4) '@typescript-eslint/parser': 8.1.0(eslint@9.9.0)(typescript@5.5.4)
'@typescript-eslint/scope-manager': 8.0.0 '@typescript-eslint/scope-manager': 8.1.0
'@typescript-eslint/type-utils': 8.0.0(eslint@9.9.1)(typescript@5.5.4) '@typescript-eslint/type-utils': 8.1.0(eslint@9.9.0)(typescript@5.5.4)
'@typescript-eslint/utils': 8.0.0(eslint@9.9.1)(typescript@5.5.4) '@typescript-eslint/utils': 8.1.0(eslint@9.9.0)(typescript@5.5.4)
'@typescript-eslint/visitor-keys': 8.0.0 '@typescript-eslint/visitor-keys': 8.1.0
eslint: 9.9.1 eslint: 9.9.0
graphemer: 1.4.0 graphemer: 1.4.0
ignore: 5.3.1 ignore: 5.3.2
natural-compare: 1.4.0 natural-compare: 1.4.0
ts-api-utils: 1.3.0(typescript@5.5.4) ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies: optionalDependencies:
@ -2154,28 +2155,28 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/parser@8.0.0(eslint@9.9.1)(typescript@5.5.4)': '@typescript-eslint/parser@8.1.0(eslint@9.9.0)(typescript@5.5.4)':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.0.0 '@typescript-eslint/scope-manager': 8.1.0
'@typescript-eslint/types': 8.0.0 '@typescript-eslint/types': 8.1.0
'@typescript-eslint/typescript-estree': 8.0.0(typescript@5.5.4) '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.5.4)
'@typescript-eslint/visitor-keys': 8.0.0 '@typescript-eslint/visitor-keys': 8.1.0
debug: 4.3.6 debug: 4.3.6
eslint: 9.9.1 eslint: 9.9.0
optionalDependencies: optionalDependencies:
typescript: 5.5.4 typescript: 5.5.4
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/scope-manager@8.0.0': '@typescript-eslint/scope-manager@8.1.0':
dependencies: dependencies:
'@typescript-eslint/types': 8.0.0 '@typescript-eslint/types': 8.1.0
'@typescript-eslint/visitor-keys': 8.0.0 '@typescript-eslint/visitor-keys': 8.1.0
'@typescript-eslint/type-utils@8.0.0(eslint@9.9.1)(typescript@5.5.4)': '@typescript-eslint/type-utils@8.1.0(eslint@9.9.0)(typescript@5.5.4)':
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 8.0.0(typescript@5.5.4) '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.5.4)
'@typescript-eslint/utils': 8.0.0(eslint@9.9.1)(typescript@5.5.4) '@typescript-eslint/utils': 8.1.0(eslint@9.9.0)(typescript@5.5.4)
debug: 4.3.6 debug: 4.3.6
ts-api-utils: 1.3.0(typescript@5.5.4) ts-api-utils: 1.3.0(typescript@5.5.4)
optionalDependencies: optionalDependencies:
@ -2184,12 +2185,12 @@ snapshots:
- eslint - eslint
- supports-color - supports-color
'@typescript-eslint/types@8.0.0': {} '@typescript-eslint/types@8.1.0': {}
'@typescript-eslint/typescript-estree@8.0.0(typescript@5.5.4)': '@typescript-eslint/typescript-estree@8.1.0(typescript@5.5.4)':
dependencies: dependencies:
'@typescript-eslint/types': 8.0.0 '@typescript-eslint/types': 8.1.0
'@typescript-eslint/visitor-keys': 8.0.0 '@typescript-eslint/visitor-keys': 8.1.0
debug: 4.3.6 debug: 4.3.6
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
@ -2201,20 +2202,20 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/utils@8.0.0(eslint@9.9.1)(typescript@5.5.4)': '@typescript-eslint/utils@8.1.0(eslint@9.9.0)(typescript@5.5.4)':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0)
'@typescript-eslint/scope-manager': 8.0.0 '@typescript-eslint/scope-manager': 8.1.0
'@typescript-eslint/types': 8.0.0 '@typescript-eslint/types': 8.1.0
'@typescript-eslint/typescript-estree': 8.0.0(typescript@5.5.4) '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.5.4)
eslint: 9.9.1 eslint: 9.9.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
- typescript - typescript
'@typescript-eslint/visitor-keys@8.0.0': '@typescript-eslint/visitor-keys@8.1.0':
dependencies: dependencies:
'@typescript-eslint/types': 8.0.0 '@typescript-eslint/types': 8.1.0
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
acorn-jsx@5.3.2(acorn@8.12.1): acorn-jsx@5.3.2(acorn@8.12.1):
@ -2259,7 +2260,7 @@ snapshots:
array-union@2.1.0: {} array-union@2.1.0: {}
async@3.2.6: {} async@3.2.5: {}
babel-jest@29.7.0(@babel/core@7.23.9): babel-jest@29.7.0(@babel/core@7.23.9):
dependencies: dependencies:
@ -2400,13 +2401,13 @@ snapshots:
convert-source-map@2.0.0: {} convert-source-map@2.0.0: {}
create-jest@29.7.0(@types/node@22.5.1): create-jest@29.7.0(@types/node@22.3.0):
dependencies: dependencies:
'@jest/types': 29.6.3 '@jest/types': 29.6.3
chalk: 4.1.2 chalk: 4.1.2
exit: 0.1.2 exit: 0.1.2
graceful-fs: 4.2.11 graceful-fs: 4.2.11
jest-config: 29.7.0(@types/node@22.5.1) jest-config: 29.7.0(@types/node@22.3.0)
jest-util: 29.7.0 jest-util: 29.7.0
prompts: 2.4.2 prompts: 2.4.2
transitivePeerDependencies: transitivePeerDependencies:
@ -2461,9 +2462,9 @@ snapshots:
escape-string-regexp@4.0.0: {} escape-string-regexp@4.0.0: {}
eslint-plugin-prettier@5.2.1(eslint@9.9.1)(prettier@3.3.3): eslint-plugin-prettier@5.2.1(eslint@9.9.0)(prettier@3.3.3):
dependencies: dependencies:
eslint: 9.9.1 eslint: 9.9.0
prettier: 3.3.3 prettier: 3.3.3
prettier-linter-helpers: 1.0.0 prettier-linter-helpers: 1.0.0
synckit: 0.9.1 synckit: 0.9.1
@ -2477,13 +2478,13 @@ snapshots:
eslint-visitor-keys@4.0.0: {} eslint-visitor-keys@4.0.0: {}
eslint@9.9.1: eslint@9.9.0:
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@9.9.1) '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0)
'@eslint-community/regexpp': 4.11.0 '@eslint-community/regexpp': 4.11.0
'@eslint/config-array': 0.18.0 '@eslint/config-array': 0.17.1
'@eslint/eslintrc': 3.1.0 '@eslint/eslintrc': 3.1.0
'@eslint/js': 9.9.1 '@eslint/js': 9.9.0
'@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/module-importer': 1.0.1
'@humanwhocodes/retry': 0.3.0 '@humanwhocodes/retry': 0.3.0
'@nodelib/fs.walk': 1.2.8 '@nodelib/fs.walk': 1.2.8
@ -2676,8 +2677,6 @@ snapshots:
human-signals@2.1.0: {} human-signals@2.1.0: {}
ignore@5.3.1: {}
ignore@5.3.2: {} ignore@5.3.2: {}
import-fresh@3.3.0: import-fresh@3.3.0:
@ -2766,7 +2765,7 @@ snapshots:
jake@10.9.2: jake@10.9.2:
dependencies: dependencies:
async: 3.2.6 async: 3.2.5
chalk: 4.1.2 chalk: 4.1.2
filelist: 1.0.4 filelist: 1.0.4
minimatch: 3.1.2 minimatch: 3.1.2
@ -2783,7 +2782,7 @@ snapshots:
'@jest/expect': 29.7.0 '@jest/expect': 29.7.0
'@jest/test-result': 29.7.0 '@jest/test-result': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
chalk: 4.1.2 chalk: 4.1.2
co: 4.6.0 co: 4.6.0
dedent: 1.5.1 dedent: 1.5.1
@ -2803,16 +2802,16 @@ snapshots:
- babel-plugin-macros - babel-plugin-macros
- supports-color - supports-color
jest-cli@29.7.0(@types/node@22.5.1): jest-cli@29.7.0(@types/node@22.3.0):
dependencies: dependencies:
'@jest/core': 29.7.0 '@jest/core': 29.7.0
'@jest/test-result': 29.7.0 '@jest/test-result': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
chalk: 4.1.2 chalk: 4.1.2
create-jest: 29.7.0(@types/node@22.5.1) create-jest: 29.7.0(@types/node@22.3.0)
exit: 0.1.2 exit: 0.1.2
import-local: 3.1.0 import-local: 3.1.0
jest-config: 29.7.0(@types/node@22.5.1) jest-config: 29.7.0(@types/node@22.3.0)
jest-util: 29.7.0 jest-util: 29.7.0
jest-validate: 29.7.0 jest-validate: 29.7.0
yargs: 17.7.2 yargs: 17.7.2
@ -2822,7 +2821,7 @@ snapshots:
- supports-color - supports-color
- ts-node - ts-node
jest-config@29.7.0(@types/node@22.5.1): jest-config@29.7.0(@types/node@22.3.0):
dependencies: dependencies:
'@babel/core': 7.23.9 '@babel/core': 7.23.9
'@jest/test-sequencer': 29.7.0 '@jest/test-sequencer': 29.7.0
@ -2847,7 +2846,7 @@ snapshots:
slash: 3.0.0 slash: 3.0.0
strip-json-comments: 3.1.1 strip-json-comments: 3.1.1
optionalDependencies: optionalDependencies:
'@types/node': 22.5.1 '@types/node': 22.3.0
transitivePeerDependencies: transitivePeerDependencies:
- babel-plugin-macros - babel-plugin-macros
- supports-color - supports-color
@ -2876,7 +2875,7 @@ snapshots:
'@jest/environment': 29.7.0 '@jest/environment': 29.7.0
'@jest/fake-timers': 29.7.0 '@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
jest-mock: 29.7.0 jest-mock: 29.7.0
jest-util: 29.7.0 jest-util: 29.7.0
@ -2886,7 +2885,7 @@ snapshots:
dependencies: dependencies:
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/graceful-fs': 4.1.9 '@types/graceful-fs': 4.1.9
'@types/node': 22.5.1 '@types/node': 22.3.0
anymatch: 3.1.3 anymatch: 3.1.3
fb-watchman: 2.0.2 fb-watchman: 2.0.2
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@ -2925,7 +2924,7 @@ snapshots:
jest-mock@29.7.0: jest-mock@29.7.0:
dependencies: dependencies:
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
jest-util: 29.7.0 jest-util: 29.7.0
jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
@ -2960,7 +2959,7 @@ snapshots:
'@jest/test-result': 29.7.0 '@jest/test-result': 29.7.0
'@jest/transform': 29.7.0 '@jest/transform': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
chalk: 4.1.2 chalk: 4.1.2
emittery: 0.13.1 emittery: 0.13.1
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@ -2988,7 +2987,7 @@ snapshots:
'@jest/test-result': 29.7.0 '@jest/test-result': 29.7.0
'@jest/transform': 29.7.0 '@jest/transform': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
chalk: 4.1.2 chalk: 4.1.2
cjs-module-lexer: 1.2.3 cjs-module-lexer: 1.2.3
collect-v8-coverage: 1.0.2 collect-v8-coverage: 1.0.2
@ -3027,14 +3026,14 @@ snapshots:
jest-util: 29.7.0 jest-util: 29.7.0
natural-compare: 1.4.0 natural-compare: 1.4.0
pretty-format: 29.7.0 pretty-format: 29.7.0
semver: 7.6.3 semver: 7.6.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
jest-util@29.7.0: jest-util@29.7.0:
dependencies: dependencies:
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
chalk: 4.1.2 chalk: 4.1.2
ci-info: 3.9.0 ci-info: 3.9.0
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@ -3053,7 +3052,7 @@ snapshots:
dependencies: dependencies:
'@jest/test-result': 29.7.0 '@jest/test-result': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
'@types/node': 22.5.1 '@types/node': 22.3.0
ansi-escapes: 4.3.2 ansi-escapes: 4.3.2
chalk: 4.1.2 chalk: 4.1.2
emittery: 0.13.1 emittery: 0.13.1
@ -3062,17 +3061,17 @@ snapshots:
jest-worker@29.7.0: jest-worker@29.7.0:
dependencies: dependencies:
'@types/node': 22.5.1 '@types/node': 22.3.0
jest-util: 29.7.0 jest-util: 29.7.0
merge-stream: 2.0.0 merge-stream: 2.0.0
supports-color: 8.1.1 supports-color: 8.1.1
jest@29.7.0(@types/node@22.5.1): jest@29.7.0(@types/node@22.3.0):
dependencies: dependencies:
'@jest/core': 29.7.0 '@jest/core': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
import-local: 3.1.0 import-local: 3.1.0
jest-cli: 29.7.0(@types/node@22.5.1) jest-cli: 29.7.0(@types/node@22.3.0)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- babel-plugin-macros - babel-plugin-macros
@ -3108,7 +3107,7 @@ snapshots:
kleur@3.0.3: {} kleur@3.0.3: {}
lemmy-js-client@0.19.5-alpha.1: {} lemmy-js-client@0.20.0-alpha.4: {}
leven@3.1.0: {} leven@3.1.0: {}
@ -3306,6 +3305,8 @@ snapshots:
semver@6.3.1: {} semver@6.3.1: {}
semver@7.6.2: {}
semver@7.6.3: {} semver@7.6.3: {}
shebang-command@2.0.0: shebang-command@2.0.0:
@ -3393,12 +3394,12 @@ snapshots:
dependencies: dependencies:
typescript: 5.5.4 typescript: 5.5.4
ts-jest@29.2.5(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.5.1))(typescript@5.5.4): ts-jest@29.2.4(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.3.0))(typescript@5.5.4):
dependencies: dependencies:
bs-logger: 0.2.6 bs-logger: 0.2.6
ejs: 3.1.10 ejs: 3.1.10
fast-json-stable-stringify: 2.1.0 fast-json-stable-stringify: 2.1.0
jest: 29.7.0(@types/node@22.5.1) jest: 29.7.0(@types/node@22.3.0)
jest-util: 29.7.0 jest-util: 29.7.0
json5: 2.2.3 json5: 2.2.3
lodash.memoize: 4.1.2 lodash.memoize: 4.1.2
@ -3422,11 +3423,11 @@ snapshots:
type-fest@0.21.3: {} type-fest@0.21.3: {}
typescript-eslint@8.0.0(eslint@9.9.1)(typescript@5.5.4): typescript-eslint@8.1.0(eslint@9.9.0)(typescript@5.5.4):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.9.1)(typescript@5.5.4))(eslint@9.9.1)(typescript@5.5.4) '@typescript-eslint/eslint-plugin': 8.1.0(@typescript-eslint/parser@8.1.0(eslint@9.9.0)(typescript@5.5.4))(eslint@9.9.0)(typescript@5.5.4)
'@typescript-eslint/parser': 8.0.0(eslint@9.9.1)(typescript@5.5.4) '@typescript-eslint/parser': 8.1.0(eslint@9.9.0)(typescript@5.5.4)
'@typescript-eslint/utils': 8.0.0(eslint@9.9.1)(typescript@5.5.4) '@typescript-eslint/utils': 8.1.0(eslint@9.9.0)(typescript@5.5.4)
optionalDependencies: optionalDependencies:
typescript: 5.5.4 typescript: 5.5.4
transitivePeerDependencies: transitivePeerDependencies:
@ -3435,7 +3436,7 @@ snapshots:
typescript@5.5.4: {} typescript@5.5.4: {}
undici-types@6.19.8: {} undici-types@6.18.2: {}
update-browserslist-db@1.0.13(browserslist@4.22.3): update-browserslist-db@1.0.13(browserslist@4.22.3):
dependencies: dependencies:

View file

@ -502,10 +502,17 @@ test("Enforce site ban federation for local user", async () => {
alpha, alpha,
alphaPerson.person.id, alphaPerson.person.id,
false, false,
false, true,
); );
expect(unBanAlpha.banned).toBe(false); expect(unBanAlpha.banned).toBe(false);
// existing alpha post should be restored on beta
betaBanRes = await waitUntil(
() => getPost(beta, searchBeta1.post.id),
s => !s.post_view.post.removed,
);
expect(betaBanRes.post_view.post.removed).toBe(false);
// Login gets invalidated by ban, need to login again // Login gets invalidated by ban, need to login again
if (!alphaUserPerson) { if (!alphaUserPerson) {
throw "Missing alpha person"; throw "Missing alpha person";

View file

@ -419,13 +419,13 @@ export async function banPersonFromSite(
api: LemmyHttp, api: LemmyHttp,
person_id: number, person_id: number,
ban: boolean, ban: boolean,
remove_data: boolean, remove_or_restore_data: boolean,
): Promise<BanPersonResponse> { ): Promise<BanPersonResponse> {
// Make sure lemmy-beta/c/main is cached on lemmy_alpha // Make sure lemmy-beta/c/main is cached on lemmy_alpha
let form: BanPerson = { let form: BanPerson = {
person_id, person_id,
ban, ban,
remove_data, remove_or_restore_data,
}; };
return api.banPerson(form); return api.banPerson(form);
} }
@ -434,13 +434,13 @@ export async function banPersonFromCommunity(
api: LemmyHttp, api: LemmyHttp,
person_id: number, person_id: number,
community_id: number, community_id: number,
remove_data: boolean, remove_or_restore_data: boolean,
ban: boolean, ban: boolean,
): Promise<BanFromCommunityResponse> { ): Promise<BanFromCommunityResponse> {
let form: BanFromCommunity = { let form: BanFromCommunity = {
person_id, person_id,
community_id, community_id,
remove_data: remove_data, remove_or_restore_data,
ban, ban,
}; };
return api.banFromCommunity(form); return api.banFromCommunity(form);

View file

@ -4,7 +4,11 @@ use lemmy_api_common::{
community::{BanFromCommunity, BanFromCommunityResponse}, community::{BanFromCommunity, BanFromCommunityResponse},
context::LemmyContext, context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData}, send_activity::{ActivityChannel, SendActivityData},
utils::{check_community_mod_action, check_expire_time, remove_user_data_in_community}, utils::{
check_community_mod_action,
check_expire_time,
remove_or_restore_user_data_in_community,
},
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{ source::{
@ -33,7 +37,6 @@ pub async fn ban_from_community(
local_user_view: LocalUserView, local_user_view: LocalUserView,
) -> LemmyResult<Json<BanFromCommunityResponse>> { ) -> LemmyResult<Json<BanFromCommunityResponse>> {
let banned_person_id = data.person_id; let banned_person_id = data.person_id;
let remove_data = data.remove_data.unwrap_or(false);
let expires = check_expire_time(data.expires)?; let expires = check_expire_time(data.expires)?;
// Verify that only mods or admins can ban // Verify that only mods or admins can ban
@ -85,9 +88,16 @@ pub async fn ban_from_community(
} }
// Remove/Restore their data if that's desired // Remove/Restore their data if that's desired
if remove_data { if data.remove_or_restore_data.unwrap_or(false) {
remove_user_data_in_community(data.community_id, banned_person_id, &mut context.pool()).await?; let remove_data = data.ban;
} remove_or_restore_user_data_in_community(
data.community_id,
banned_person_id,
remove_data,
&mut context.pool(),
)
.await?;
};
// Mod tables // Mod tables
let form = ModBanFromCommunityForm { let form = ModBanFromCommunityForm {

View file

@ -172,7 +172,7 @@ pub(crate) async fn ban_nonlocal_user_from_local_communities(
target: &Person, target: &Person,
ban: bool, ban: bool,
reason: &Option<String>, reason: &Option<String>,
remove_data: &Option<bool>, remove_or_restore_data: &Option<bool>,
expires: &Option<i64>, expires: &Option<i64>,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
) -> LemmyResult<()> { ) -> LemmyResult<()> {
@ -230,7 +230,7 @@ pub(crate) async fn ban_nonlocal_user_from_local_communities(
person_id: target.id, person_id: target.id,
ban, ban,
reason: reason.clone(), reason: reason.clone(),
remove_data: *remove_data, remove_or_restore_data: *remove_or_restore_data,
expires: *expires, expires: *expires,
}; };

View file

@ -5,7 +5,7 @@ use lemmy_api_common::{
context::LemmyContext, context::LemmyContext,
person::{BanPerson, BanPersonResponse}, person::{BanPerson, BanPersonResponse},
send_activity::{ActivityChannel, SendActivityData}, send_activity::{ActivityChannel, SendActivityData},
utils::{check_expire_time, is_admin, remove_user_data}, utils::{check_expire_time, is_admin, remove_user_data, restore_user_data},
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{ source::{
@ -65,10 +65,13 @@ pub async fn ban_from_site(
} }
// Remove their data if that's desired // Remove their data if that's desired
let remove_data = data.remove_data.unwrap_or(false); if data.remove_or_restore_data.unwrap_or(false) {
if remove_data { if data.ban {
remove_user_data(person.id, &context).await?; remove_user_data(person.id, &context).await?;
} else {
restore_user_data(person.id, &context).await?;
} }
};
// Mod tables // Mod tables
let form = ModBanForm { let form = ModBanForm {
@ -90,7 +93,7 @@ pub async fn ban_from_site(
&person, &person,
data.ban, data.ban,
&data.reason, &data.reason,
&data.remove_data, &data.remove_or_restore_data,
&data.expires, &data.expires,
&context, &context,
) )
@ -101,7 +104,7 @@ pub async fn ban_from_site(
moderator: local_user_view.person, moderator: local_user_view.person,
banned_user: person_view.person.clone(), banned_user: person_view.person.clone(),
reason: data.reason.clone(), reason: data.reason.clone(),
remove_data: data.remove_data, remove_or_restore_data: data.remove_or_restore_data,
ban: data.ban, ban: data.ban,
expires: data.expires, expires: data.expires,
}, },

View file

@ -77,7 +77,7 @@ pub async fn purge_person(
moderator: local_user_view.person, moderator: local_user_view.person,
banned_user: person, banned_user: person,
reason: data.reason.clone(), reason: data.reason.clone(),
remove_data: Some(true), remove_or_restore_data: Some(true),
ban: true, ban: true,
expires: None, expires: None,
}, },

View file

@ -97,7 +97,9 @@ pub struct BanFromCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub person_id: PersonId, pub person_id: PersonId,
pub ban: bool, pub ban: bool,
pub remove_data: Option<bool>, /// Optionally remove or restore all their data. Useful for new troll accounts.
/// If ban is true, then this means remove. If ban is false, it means restore.
pub remove_or_restore_data: Option<bool>,
pub reason: Option<String>, pub reason: Option<String>,
/// A time that the ban will expire, in unix epoch seconds. /// A time that the ban will expire, in unix epoch seconds.
/// ///

View file

@ -217,8 +217,9 @@ pub struct AddAdminResponse {
pub struct BanPerson { pub struct BanPerson {
pub person_id: PersonId, pub person_id: PersonId,
pub ban: bool, pub ban: bool,
/// Optionally remove all their data. Useful for new troll accounts. /// Optionally remove or restore all their data. Useful for new troll accounts.
pub remove_data: Option<bool>, /// If ban is true, then this means remove. If ban is false, it means restore.
pub remove_or_restore_data: Option<bool>,
pub reason: Option<String>, pub reason: Option<String>,
/// A time that the ban will expire, in unix epoch seconds. /// A time that the ban will expire, in unix epoch seconds.
/// ///

View file

@ -83,7 +83,7 @@ pub enum SendActivityData {
moderator: Person, moderator: Person,
banned_user: Person, banned_user: Person,
reason: Option<String>, reason: Option<String>,
remove_data: Option<bool>, remove_or_restore_data: Option<bool>,
ban: bool, ban: bool,
expires: Option<i64>, expires: Option<i64>,
}, },

View file

@ -827,13 +827,30 @@ pub async fn remove_user_data(
Ok(()) Ok(())
} }
pub async fn remove_user_data_in_community( /// We can't restore their images, but we can unremove their posts and comments
pub async fn restore_user_data(
banned_person_id: PersonId,
context: &LemmyContext,
) -> LemmyResult<()> {
let pool = &mut context.pool();
// Posts
Post::update_removed_for_creator(pool, banned_person_id, None, false).await?;
// Comments
Comment::update_removed_for_creator(pool, banned_person_id, false).await?;
Ok(())
}
pub async fn remove_or_restore_user_data_in_community(
community_id: CommunityId, community_id: CommunityId,
banned_person_id: PersonId, banned_person_id: PersonId,
remove: bool,
pool: &mut DbPool<'_>, pool: &mut DbPool<'_>,
) -> LemmyResult<()> { ) -> LemmyResult<()> {
// Posts // Posts
Post::update_removed_for_creator(pool, banned_person_id, Some(community_id), true).await?; Post::update_removed_for_creator(pool, banned_person_id, Some(community_id), remove).await?;
// Comments // Comments
// TODO Diesel doesn't allow updates with joins, so this has to be a loop // TODO Diesel doesn't allow updates with joins, so this has to be a loop
@ -851,7 +868,7 @@ pub async fn remove_user_data_in_community(
pool, pool,
comment_id, comment_id,
&CommentUpdateForm { &CommentUpdateForm {
removed: Some(true), removed: Some(remove),
..Default::default() ..Default::default()
}, },
) )

View file

@ -23,7 +23,7 @@ use anyhow::anyhow;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use lemmy_api_common::{ use lemmy_api_common::{
context::LemmyContext, context::LemmyContext,
utils::{remove_user_data, remove_user_data_in_community}, utils::{remove_or_restore_user_data_in_community, remove_user_data},
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{ source::{
@ -205,7 +205,12 @@ impl ActivityHandler for BlockUser {
.ok(); .ok();
if self.remove_data.unwrap_or(false) { if self.remove_data.unwrap_or(false) {
remove_user_data_in_community(community.id, blocked_person.id, &mut context.pool()) remove_or_restore_user_data_in_community(
community.id,
blocked_person.id,
true,
&mut context.pool(),
)
.await?; .await?;
} }

View file

@ -136,7 +136,7 @@ pub(crate) async fn send_ban_from_site(
moderator: Person, moderator: Person,
banned_user: Person, banned_user: Person,
reason: Option<String>, reason: Option<String>,
remove_data: Option<bool>, remove_or_restore_data: Option<bool>,
ban: bool, ban: bool,
expires: Option<i64>, expires: Option<i64>,
context: Data<LemmyContext>, context: Data<LemmyContext>,
@ -151,7 +151,7 @@ pub(crate) async fn send_ban_from_site(
&site, &site,
&banned_user.into(), &banned_user.into(),
&moderator.into(), &moderator.into(),
remove_data.unwrap_or(false), remove_or_restore_data.unwrap_or(false),
reason.clone(), reason.clone(),
expires, expires,
&context, &context,
@ -162,6 +162,7 @@ pub(crate) async fn send_ban_from_site(
&site, &site,
&banned_user.into(), &banned_user.into(),
&moderator.into(), &moderator.into(),
remove_or_restore_data.unwrap_or(false),
reason.clone(), reason.clone(),
&context, &context,
) )
@ -190,7 +191,7 @@ pub(crate) async fn send_ban_from_community(
&SiteOrCommunity::Community(community), &SiteOrCommunity::Community(community),
&banned_person.into(), &banned_person.into(),
&mod_.into(), &mod_.into(),
data.remove_data.unwrap_or(false), data.remove_or_restore_data.unwrap_or(false),
data.reason.clone(), data.reason.clone(),
expires, expires,
&context, &context,
@ -201,6 +202,7 @@ pub(crate) async fn send_ban_from_community(
&SiteOrCommunity::Community(community), &SiteOrCommunity::Community(community),
&banned_person.into(), &banned_person.into(),
&mod_.into(), &mod_.into(),
data.remove_or_restore_data.unwrap_or(false),
data.reason.clone(), data.reason.clone(),
&context, &context,
) )

View file

@ -17,7 +17,10 @@ use activitypub_federation::{
protocol::verification::verify_domains_match, protocol::verification::verify_domains_match,
traits::{ActivityHandler, Actor}, traits::{ActivityHandler, Actor},
}; };
use lemmy_api_common::context::LemmyContext; use lemmy_api_common::{
context::LemmyContext,
utils::{remove_or_restore_user_data_in_community, restore_user_data},
};
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{ source::{
activity::ActivitySendTargets, activity::ActivitySendTargets,
@ -36,6 +39,7 @@ impl UndoBlockUser {
target: &SiteOrCommunity, target: &SiteOrCommunity,
user: &ApubPerson, user: &ApubPerson,
mod_: &ApubPerson, mod_: &ApubPerson,
restore_data: bool,
reason: Option<String>, reason: Option<String>,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
) -> LemmyResult<()> { ) -> LemmyResult<()> {
@ -58,6 +62,7 @@ impl UndoBlockUser {
kind: UndoType::Undo, kind: UndoType::Undo,
id: id.clone(), id: id.clone(),
audience, audience,
restore_data: Some(restore_data),
}; };
let mut inboxes = ActivitySendTargets::to_inbox(user.shared_inbox_or_inbox()); let mut inboxes = ActivitySendTargets::to_inbox(user.shared_inbox_or_inbox());
@ -114,6 +119,10 @@ impl ActivityHandler for UndoBlockUser {
) )
.await?; .await?;
if self.restore_data.unwrap_or(false) {
restore_user_data(blocked_person.id, context).await?;
}
// write mod log // write mod log
let form = ModBanForm { let form = ModBanForm {
mod_person_id: mod_person.id, mod_person_id: mod_person.id,
@ -132,6 +141,16 @@ impl ActivityHandler for UndoBlockUser {
}; };
CommunityPersonBan::unban(&mut context.pool(), &community_user_ban_form).await?; CommunityPersonBan::unban(&mut context.pool(), &community_user_ban_form).await?;
if self.restore_data.unwrap_or(false) {
remove_or_restore_user_data_in_community(
community.id,
blocked_person.id,
false,
&mut context.pool(),
)
.await?;
}
// write to mod log // write to mod log
let form = ModBanFromCommunityForm { let form = ModBanFromCommunityForm {
mod_person_id: mod_person.id, mod_person_id: mod_person.id,

View file

@ -352,7 +352,7 @@ pub async fn match_outgoing_activities(
moderator, moderator,
banned_user, banned_user,
reason, reason,
remove_data, remove_or_restore_data,
ban, ban,
expires, expires,
} => { } => {
@ -360,7 +360,7 @@ pub async fn match_outgoing_activities(
moderator, moderator,
banned_user, banned_user,
reason, reason,
remove_data, remove_or_restore_data,
ban, ban,
expires, expires,
context, context,

View file

@ -29,6 +29,10 @@ pub struct UndoBlockUser {
pub(crate) kind: UndoType, pub(crate) kind: UndoType,
pub(crate) id: Url, pub(crate) id: Url,
pub(crate) audience: Option<ObjectId<ApubCommunity>>, pub(crate) audience: Option<ObjectId<ApubCommunity>>,
/// Quick and dirty solution.
/// TODO: send a separate Delete activity instead
pub(crate) restore_data: Option<bool>,
} }
#[async_trait::async_trait] #[async_trait::async_trait]