Skip to content

Commit 4a9949b

Browse files
committed
Fix the mixer filter effects issues with undoing and persisting
1 parent 5d67670 commit 4a9949b

5 files changed

Lines changed: 363 additions & 10 deletions

File tree

backend/routes/rooms.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,97 @@ def get_undo_redo_status(roomId):
15461546
"redo_count": redo_count
15471547
})
15481548

1549+
@rooms_bp.route("/rooms/<roomId>/mark_undone", methods=["POST"])
1550+
@require_auth
1551+
@require_room_access(room_id_param="roomId")
1552+
@limiter.limit(f"{RATE_LIMIT_UNDO_REDO_MINUTE}/minute")
1553+
def mark_strokes_undone(roomId):
1554+
"""
1555+
Mark specific stroke IDs as undone without requiring them to be in the undo stack.
1556+
Useful for clearing filters after Redis flush.
1557+
1558+
Server-side enforcement:
1559+
- Authentication required via @require_auth
1560+
- Room access required via @require_room_access
1561+
- Viewer role cannot mark undone (read-only)
1562+
"""
1563+
logger.info(f"Mark undone request for room {roomId}")
1564+
1565+
user = g.current_user
1566+
claims = g.token_claims
1567+
room = g.current_room
1568+
user_id = claims['sub']
1569+
1570+
try:
1571+
share = shares_coll.find_one({"roomId": roomId, "$or": [{"userId": user_id}, {"username": user_id}]})
1572+
if share and share.get('role') == 'viewer':
1573+
return jsonify({"status":"error","message":"Forbidden: viewers cannot mark strokes as undone"}), 403
1574+
except Exception:
1575+
pass
1576+
1577+
# Get stroke IDs from request
1578+
data = request.get_json() or {}
1579+
stroke_ids = data.get('strokeIds', [])
1580+
1581+
if not stroke_ids or not isinstance(stroke_ids, list):
1582+
return jsonify({"status":"error","message":"strokeIds array required"}), 400
1583+
1584+
key_base = f"room:{roomId}:{user_id}"
1585+
marked_count = 0
1586+
1587+
try:
1588+
# Mark each stroke as undone in Redis
1589+
for stroke_id in stroke_ids:
1590+
if stroke_id:
1591+
redis_client.sadd(f"{key_base}:undone_strokes", str(stroke_id))
1592+
marked_count += 1
1593+
1594+
# Create and persist undo marker for each stroke
1595+
ts = int(time.time() * 1000)
1596+
marker_rec = {
1597+
"type": "undo_marker",
1598+
"roomId": roomId,
1599+
"user": user_id,
1600+
"strokeId": str(stroke_id),
1601+
"ts": ts,
1602+
"undone": True
1603+
}
1604+
1605+
try:
1606+
marker_asset = {"data": marker_rec}
1607+
payload = {
1608+
"operation": "CREATE", "amount": 1,
1609+
"signerPublicKey": SIGNER_PUBLIC_KEY,
1610+
"signerPrivateKey": SIGNER_PRIVATE_KEY,
1611+
"recipientPublicKey": RECIPIENT_PUBLIC_KEY,
1612+
"asset": marker_asset
1613+
}
1614+
strokes_coll.insert_one({"asset": marker_asset})
1615+
commit_transaction_via_graphql(payload)
1616+
logger.info(f"Persisted undo marker for stroke {stroke_id}")
1617+
except Exception as e:
1618+
logger.exception(f"Failed to persist undo marker for stroke {stroke_id}: {e}")
1619+
# Continue with other strokes even if one fails
1620+
1621+
# Broadcast event to other users
1622+
push_to_room(roomId, "strokes_marked_undone", {
1623+
"roomId": roomId,
1624+
"strokeIds": stroke_ids,
1625+
"user": claims.get("username", "unknown"),
1626+
"timestamp": int(time.time() * 1000)
1627+
})
1628+
1629+
logger.info(f"Marked {marked_count} strokes as undone")
1630+
return jsonify({
1631+
"status":"ok",
1632+
"marked_count": marked_count,
1633+
"stroke_ids": stroke_ids
1634+
})
1635+
1636+
except Exception as e:
1637+
logger.exception("An error occurred during mark_strokes_undone")
1638+
return jsonify({"status":"error","message":f"Failed to mark strokes as undone: {str(e)}"}), 500
1639+
15491640
@rooms_bp.route("/rooms/<roomId>/redo", methods=["POST"])
15501641
@require_auth
15511642
@require_room_access(room_id_param="roomId")

frontend/src/api/rooms.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ export async function redoRoomAction(token, roomId) {
162162
return await handleApiResponse(r);
163163
}
164164

165+
export async function markStrokesAsUndone(token, roomId, strokeIds) {
166+
const r = await authFetch(`${API_BASE}/rooms/${roomId}/mark_undone`, {
167+
method: "POST",
168+
headers: withTK({ "Content-Type": "application/json" }),
169+
body: JSON.stringify({ strokeIds })
170+
});
171+
return await handleApiResponse(r);
172+
}
173+
165174
export async function getUndoRedoStatus(token, roomId) {
166175
const r = await authFetch(`${API_BASE}/rooms/${roomId}/undo_redo_status`, { headers: withTK() });
167176
return await handleApiResponse(r);

0 commit comments

Comments
 (0)