mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
fix: enforce forced retention on global tag rename and delete
Per-conversation tag writes already convert their conversation under forced ephemeral retention, but global bookmark-tag renames and deletes rewrite conversation rows via Conversation.updateMany without setting isTemporary/expiredAt. A permanent chat tagged before the install switched to ephemeral, touched only by a tag rename or delete, would keep its retention fields unset and stay visible and non-expiring. Add cascadeForcedRetentionByTag plus an applyForcedRetentionToTag method that bulk-converts every conversation carrying a tag (and backfills its messages and caps its shares) through the shared gap filter, so it never extends a chat that already expires sooner. Load the interface config on PUT /:tag and DELETE /:tag and route those writes through it.
This commit is contained in:
parent
a3cad799dd
commit
c392db0dd8
4 changed files with 210 additions and 2 deletions
|
|
@ -9,6 +9,7 @@ const {
|
|||
deleteConversationTag,
|
||||
getConversationTags,
|
||||
applyForcedRetention,
|
||||
applyForcedRetentionToTag,
|
||||
getRoleByName,
|
||||
} = require('~/models');
|
||||
const { requireJwtAuth, configMiddleware } = require('~/server/middleware');
|
||||
|
|
@ -35,6 +36,18 @@ const enforceForcedRetention = (req, conversationId, context) =>
|
|||
{ context },
|
||||
);
|
||||
|
||||
/**
|
||||
* Enforces forced (ephemeral) retention on every conversation carrying a tag, for global
|
||||
* tag renames/deletes that rewrite conversation rows without converting them; a no-op
|
||||
* outside forced retention.
|
||||
*/
|
||||
const enforceForcedRetentionForTag = (req, tag, context) =>
|
||||
applyForcedRetentionToTag(
|
||||
{ userId: req?.user?.id, interfaceConfig: req?.config?.interfaceConfig },
|
||||
{ tag },
|
||||
{ context },
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /
|
||||
* Retrieves all conversation tags for the authenticated user.
|
||||
|
|
@ -80,11 +93,12 @@ router.post('/', configMiddleware, async (req, res) => {
|
|||
* @param {Object} req - Express request object
|
||||
* @param {Object} res - Express response object
|
||||
*/
|
||||
router.put('/:tag', async (req, res) => {
|
||||
router.put('/:tag', configMiddleware, async (req, res) => {
|
||||
try {
|
||||
const decodedTag = decodeURIComponent(req.params.tag);
|
||||
const tag = await updateConversationTag(req.user.id, decodedTag, req.body);
|
||||
if (tag) {
|
||||
await enforceForcedRetentionForTag(req, req.body?.tag || decodedTag, 'PUT /api/tags/:tag');
|
||||
res.status(200).json(tag);
|
||||
} else {
|
||||
res.status(404).json({ error: 'Tag not found' });
|
||||
|
|
@ -101,9 +115,10 @@ router.put('/:tag', async (req, res) => {
|
|||
* @param {Object} req - Express request object
|
||||
* @param {Object} res - Express response object
|
||||
*/
|
||||
router.delete('/:tag', async (req, res) => {
|
||||
router.delete('/:tag', configMiddleware, async (req, res) => {
|
||||
try {
|
||||
const decodedTag = decodeURIComponent(req.params.tag);
|
||||
await enforceForcedRetentionForTag(req, decodedTag, 'DELETE /api/tags/:tag');
|
||||
const tag = await deleteConversationTag(req.user.id, decodedTag);
|
||||
if (tag) {
|
||||
res.status(200).json(tag);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue